[runtime] Require C# namespace to be quoted.
[mono-project.git] / mono / metadata / object.c
blob8162ea01f89f28adbdd9802a8852dcaf086fab16
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)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include <config.h>
14 #ifdef HAVE_ALLOCA_H
15 #include <alloca.h>
16 #endif
17 #include <stdlib.h>
18 #include <stdio.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-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.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 <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
53 static void
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
56 static MonoString*
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
59 static void
60 free_main_args (void);
62 static char *
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
65 static void
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
68 static MonoMethod*
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
84 /**
85 * mono_runtime_object_init:
86 * @this_obj: the object to initialize
88 * This function calls the zero-argument constructor (which must
89 * exist) for the given object.
91 void
92 mono_runtime_object_init (MonoObject *this_obj)
94 MonoError error;
95 mono_runtime_object_init_checked (this_obj, &error);
96 mono_error_assert_ok (&error);
99 /**
100 * mono_runtime_object_init_checked:
101 * @this_obj: the object to initialize
102 * @error: set on error.
104 * This function calls the zero-argument constructor (which must
105 * exist) for the given object and returns TRUE on success, or FALSE
106 * on error and sets @error.
108 gboolean
109 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
111 MONO_REQ_GC_UNSAFE_MODE;
113 MonoMethod *method = NULL;
114 MonoClass *klass = this_obj->vtable->klass;
116 mono_error_init (error);
117 method = mono_class_get_method_from_name (klass, ".ctor", 0);
118 if (!method)
119 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
121 if (method->klass->valuetype)
122 this_obj = (MonoObject *)mono_object_unbox (this_obj);
124 mono_runtime_invoke_checked (method, this_obj, NULL, error);
125 return is_ok (error);
128 /* The pseudo algorithm for type initialization from the spec
129 Note it doesn't say anything about domains - only threads.
131 2. If the type is initialized you are done.
132 2.1. If the type is not yet initialized, try to take an
133 initialization lock.
134 2.2. If successful, record this thread as responsible for
135 initializing the type and proceed to step 2.3.
136 2.2.1. If not, see whether this thread or any thread
137 waiting for this thread to complete already holds the lock.
138 2.2.2. If so, return since blocking would create a deadlock. This thread
139 will now see an incompletely initialized state for the type,
140 but no deadlock will arise.
141 2.2.3 If not, block until the type is initialized then return.
142 2.3 Initialize the parent type and then all interfaces implemented
143 by this type.
144 2.4 Execute the type initialization code for this type.
145 2.5 Mark the type as initialized, release the initialization lock,
146 awaken any threads waiting for this type to be initialized,
147 and return.
151 typedef struct
153 MonoNativeThreadId initializing_tid;
154 guint32 waiting_count;
155 gboolean done;
156 MonoCoopMutex mutex;
157 /* condvar used to wait for 'done' becoming TRUE */
158 MonoCoopCond cond;
159 } TypeInitializationLock;
161 /* for locking access to type_initialization_hash and blocked_thread_hash */
162 static MonoCoopMutex type_initialization_section;
164 static inline void
165 mono_type_initialization_lock (void)
167 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
168 mono_coop_mutex_lock (&type_initialization_section);
171 static inline void
172 mono_type_initialization_unlock (void)
174 mono_coop_mutex_unlock (&type_initialization_section);
177 static void
178 mono_type_init_lock (TypeInitializationLock *lock)
180 MONO_REQ_GC_NEUTRAL_MODE;
182 mono_coop_mutex_lock (&lock->mutex);
185 static void
186 mono_type_init_unlock (TypeInitializationLock *lock)
188 mono_coop_mutex_unlock (&lock->mutex);
191 /* from vtable to lock */
192 static GHashTable *type_initialization_hash;
194 /* from thread id to thread id being waited on */
195 static GHashTable *blocked_thread_hash;
197 /* Main thread */
198 static MonoThread *main_thread;
200 /* Functions supplied by the runtime */
201 static MonoRuntimeCallbacks callbacks;
204 * mono_thread_set_main:
205 * @thread: thread to set as the main thread
207 * This function can be used to instruct the runtime to treat @thread
208 * as the main thread, ie, the thread that would normally execute the Main()
209 * method. This basically means that at the end of @thread, the runtime will
210 * wait for the existing foreground threads to quit and other such details.
212 void
213 mono_thread_set_main (MonoThread *thread)
215 MONO_REQ_GC_UNSAFE_MODE;
217 static gboolean registered = FALSE;
219 if (!registered) {
220 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 registered = TRUE;
224 main_thread = thread;
227 MonoThread*
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
232 return main_thread;
235 void
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
244 void
245 mono_type_initialization_cleanup (void)
247 #if 0
248 /* This is causing race conditions with
249 * mono_release_type_locks
251 mono_coop_mutex_destroy (&type_initialization_section);
252 g_hash_table_destroy (type_initialization_hash);
253 type_initialization_hash = NULL;
254 #endif
255 mono_os_mutex_destroy (&ldstr_section);
256 g_hash_table_destroy (blocked_thread_hash);
257 blocked_thread_hash = NULL;
259 free_main_args ();
263 * get_type_init_exception_for_vtable:
265 * Return the stored type initialization exception for VTABLE.
267 static MonoException*
268 get_type_init_exception_for_vtable (MonoVTable *vtable)
270 MONO_REQ_GC_UNSAFE_MODE;
272 MonoError error;
273 MonoDomain *domain = vtable->domain;
274 MonoClass *klass = vtable->klass;
275 MonoException *ex;
276 gchar *full_name;
278 if (!vtable->init_failed)
279 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282 * If the initializing thread was rudely aborted, the exception is not stored
283 * in the hash.
285 ex = NULL;
286 mono_domain_lock (domain);
287 if (domain->type_init_exception_hash)
288 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
289 mono_domain_unlock (domain);
291 if (!ex) {
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
294 else
295 full_name = g_strdup (klass->name);
296 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
297 g_free (full_name);
298 return_val_if_nok (&error, NULL);
301 return ex;
305 * mono_runtime_class_init:
306 * @vtable: vtable that needs to be initialized
308 * This routine calls the class constructor for @vtable.
310 void
311 mono_runtime_class_init (MonoVTable *vtable)
313 MONO_REQ_GC_UNSAFE_MODE;
314 MonoError error;
316 mono_runtime_class_init_full (vtable, &error);
317 mono_error_assert_ok (&error);
321 * Returns TRUE if the lock was freed.
322 * LOCKING: Caller should hold type_initialization_lock.
324 static gboolean
325 unref_type_lock (TypeInitializationLock *lock)
327 --lock->waiting_count;
328 if (lock->waiting_count == 0) {
329 mono_coop_mutex_destroy (&lock->mutex);
330 mono_coop_cond_destroy (&lock->cond);
331 g_free (lock);
332 return TRUE;
333 } else {
334 return FALSE;
339 * mono_runtime_class_init_full:
340 * @vtable that neeeds to be initialized
341 * @error set on error
343 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
346 gboolean
347 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
349 MONO_REQ_GC_UNSAFE_MODE;
351 MonoMethod *method = NULL;
352 MonoClass *klass;
353 gchar *full_name;
354 MonoDomain *domain = vtable->domain;
355 TypeInitializationLock *lock;
356 MonoNativeThreadId tid;
357 int do_initialization = 0;
358 MonoDomain *last_domain = NULL;
359 MonoException * pending_tae = NULL;
361 mono_error_init (error);
363 if (vtable->initialized)
364 return TRUE;
366 klass = vtable->klass;
368 if (!klass->image->checked_module_cctor) {
369 mono_image_check_for_module_cctor (klass->image);
370 if (klass->image->has_module_cctor) {
371 MonoClass *module_klass;
372 MonoVTable *module_vtable;
374 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
375 if (!module_klass) {
376 return FALSE;
379 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
380 if (!module_vtable)
381 return FALSE;
382 if (!mono_runtime_class_init_full (module_vtable, error))
383 return FALSE;
386 method = mono_class_get_cctor (klass);
387 if (!method) {
388 vtable->initialized = 1;
389 return TRUE;
392 tid = mono_native_thread_id_get ();
395 * Due some preprocessing inside a global lock. If we are the first thread
396 * trying to initialize this class, create a separate lock+cond var, and
397 * acquire it before leaving the global lock. The other threads will wait
398 * on this cond var.
401 mono_type_initialization_lock ();
402 /* double check... */
403 if (vtable->initialized) {
404 mono_type_initialization_unlock ();
405 return TRUE;
407 if (vtable->init_failed) {
408 mono_type_initialization_unlock ();
410 /* The type initialization already failed once, rethrow the same exception */
411 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
412 return FALSE;
414 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
415 if (lock == NULL) {
416 /* This thread will get to do the initialization */
417 if (mono_domain_get () != domain) {
418 /* Transfer into the target domain */
419 last_domain = mono_domain_get ();
420 if (!mono_domain_set (domain, FALSE)) {
421 vtable->initialized = 1;
422 mono_type_initialization_unlock ();
423 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
424 return FALSE;
427 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
428 mono_coop_mutex_init_recursive (&lock->mutex);
429 mono_coop_cond_init (&lock->cond);
430 lock->initializing_tid = tid;
431 lock->waiting_count = 1;
432 lock->done = FALSE;
433 /* grab the vtable lock while this thread still owns type_initialization_section */
434 /* This is why type_initialization_lock needs to enter blocking mode */
435 mono_type_init_lock (lock);
436 g_hash_table_insert (type_initialization_hash, vtable, lock);
437 do_initialization = 1;
438 } else {
439 gpointer blocked;
440 TypeInitializationLock *pending_lock;
442 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
443 mono_type_initialization_unlock ();
444 return TRUE;
446 /* see if the thread doing the initialization is already blocked on this thread */
447 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
448 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
449 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
450 if (!pending_lock->done) {
451 mono_type_initialization_unlock ();
452 return TRUE;
453 } else {
454 /* the thread doing the initialization is blocked on this thread,
455 but on a lock that has already been freed. It just hasn't got
456 time to awake */
457 break;
460 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
462 ++lock->waiting_count;
463 /* record the fact that we are waiting on the initializing thread */
464 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
466 mono_type_initialization_unlock ();
468 if (do_initialization) {
469 MonoException *exc = NULL;
471 /* We are holding the per-vtable lock, do the actual initialization */
473 mono_threads_begin_abort_protected_block ();
474 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
475 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
477 //exception extracted, error will be set to the right value later
478 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
479 exc = mono_error_convert_to_exception (error);
480 else
481 mono_error_cleanup (error);
483 mono_error_init (error);
485 /* If the initialization failed, mark the class as unusable. */
486 /* Avoid infinite loops */
487 if (!(!exc ||
488 (klass->image == mono_defaults.corlib &&
489 !strcmp (klass->name_space, "System") &&
490 !strcmp (klass->name, "TypeInitializationException")))) {
491 vtable->init_failed = 1;
493 if (klass->name_space && *klass->name_space)
494 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
495 else
496 full_name = g_strdup (klass->name);
498 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
499 g_free (full_name);
501 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
504 * Store the exception object so it could be thrown on subsequent
505 * accesses.
507 mono_domain_lock (domain);
508 if (!domain->type_init_exception_hash)
509 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
510 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
511 mono_domain_unlock (domain);
514 if (last_domain)
515 mono_domain_set (last_domain, TRUE);
516 /* Signal to the other threads that we are done */
517 lock->done = TRUE;
518 mono_coop_cond_broadcast (&lock->cond);
520 mono_type_init_unlock (lock);
522 //This can happen if the cctor self-aborts
523 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
524 pending_tae = exc;
526 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
527 if (!pending_tae && got_pending_interrupt)
528 pending_tae = mono_thread_try_resume_interruption ();
529 } else {
530 /* this just blocks until the initializing thread is done */
531 mono_type_init_lock (lock);
532 while (!lock->done)
533 mono_coop_cond_wait (&lock->cond, &lock->mutex);
534 mono_type_init_unlock (lock);
537 /* Do cleanup and setting vtable->initialized inside the global lock again */
538 mono_type_initialization_lock ();
539 if (!do_initialization)
540 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
541 gboolean deleted = unref_type_lock (lock);
542 if (deleted)
543 g_hash_table_remove (type_initialization_hash, vtable);
544 /* Have to set this here since we check it inside the global lock */
545 if (do_initialization && !vtable->init_failed)
546 vtable->initialized = 1;
547 mono_type_initialization_unlock ();
549 //TAE wins over TIE
550 if (pending_tae)
551 mono_error_set_exception_instance (error, pending_tae);
552 else if (vtable->init_failed) {
553 /* Either we were the initializing thread or we waited for the initialization */
554 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
555 return FALSE;
557 return TRUE;
560 static
561 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
563 MONO_REQ_GC_NEUTRAL_MODE;
565 MonoVTable *vtable = (MonoVTable*)key;
567 TypeInitializationLock *lock = (TypeInitializationLock*) value;
568 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
569 lock->done = TRUE;
571 * Have to set this since it cannot be set by the normal code in
572 * mono_runtime_class_init (). In this case, the exception object is not stored,
573 * and get_type_init_exception_for_class () needs to be aware of this.
575 vtable->init_failed = 1;
576 mono_coop_cond_broadcast (&lock->cond);
577 mono_type_init_unlock (lock);
578 gboolean deleted = unref_type_lock (lock);
579 if (deleted)
580 return TRUE;
582 return FALSE;
585 void
586 mono_release_type_locks (MonoInternalThread *thread)
588 MONO_REQ_GC_UNSAFE_MODE;
590 mono_type_initialization_lock ();
591 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
592 mono_type_initialization_unlock ();
595 #ifndef DISABLE_REMOTING
597 static gpointer
598 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
600 if (!callbacks.create_remoting_trampoline)
601 g_error ("remoting not installed");
602 return callbacks.create_remoting_trampoline (domain, method, target, error);
605 #endif
607 static MonoImtTrampolineBuilder imt_trampoline_builder;
608 static gboolean always_build_imt_trampolines;
610 #if (MONO_IMT_SIZE > 32)
611 #error "MONO_IMT_SIZE cannot be larger than 32"
612 #endif
614 void
615 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
617 memcpy (&callbacks, cbs, sizeof (*cbs));
620 MonoRuntimeCallbacks*
621 mono_get_runtime_callbacks (void)
623 return &callbacks;
626 void
627 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
629 imt_trampoline_builder = func;
632 void
633 mono_set_always_build_imt_trampolines (gboolean value)
635 always_build_imt_trampolines = value;
639 * mono_compile_method:
640 * @method: The method to compile.
642 * This JIT-compiles the method, and returns the pointer to the native code
643 * produced.
645 gpointer
646 mono_compile_method (MonoMethod *method)
648 MonoError error;
649 gpointer result = mono_compile_method_checked (method, &error);
650 mono_error_cleanup (&error);
651 return result;
655 * mono_compile_method:
656 * @method: The method to compile.
657 * @error: set on error.
659 * This JIT-compiles the method, and returns the pointer to the native code
660 * produced. On failure returns NULL and sets @error.
662 gpointer
663 mono_compile_method_checked (MonoMethod *method, MonoError *error)
665 gpointer res;
667 MONO_REQ_GC_NEUTRAL_MODE
669 mono_error_init (error);
671 g_assert (callbacks.compile_method);
672 res = callbacks.compile_method (method, error);
673 return res;
676 gpointer
677 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
679 gpointer res;
681 MONO_REQ_GC_NEUTRAL_MODE;
683 mono_error_init (error);
684 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
685 return res;
688 gpointer
689 mono_runtime_create_delegate_trampoline (MonoClass *klass)
691 MONO_REQ_GC_NEUTRAL_MODE
693 g_assert (callbacks.create_delegate_trampoline);
694 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
698 * mono_runtime_free_method:
699 * @domain; domain where the method is hosted
700 * @method: method to release
702 * This routine is invoked to free the resources associated with
703 * a method that has been JIT compiled. This is used to discard
704 * methods that were used only temporarily (for example, used in marshalling)
707 void
708 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
710 MONO_REQ_GC_NEUTRAL_MODE
712 if (callbacks.free_method)
713 callbacks.free_method (domain, method);
715 mono_method_clear_object (domain, method);
717 mono_free_method (method);
721 * The vtables in the root appdomain are assumed to be reachable by other
722 * roots, and we don't use typed allocation in the other domains.
725 /* The sync block is no longer a GC pointer */
726 #define GC_HEADER_BITMAP (0)
728 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
730 static gsize*
731 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
733 MONO_REQ_GC_NEUTRAL_MODE;
735 MonoClassField *field;
736 MonoClass *p;
737 guint32 pos;
738 int max_size;
740 if (static_fields)
741 max_size = mono_class_data_size (klass) / sizeof (gpointer);
742 else
743 max_size = klass->instance_size / sizeof (gpointer);
744 if (max_size > size) {
745 g_assert (offset <= 0);
746 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
747 size = max_size;
750 #ifdef HAVE_SGEN_GC
751 /*An Ephemeron cannot be marked by sgen*/
752 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
753 *max_set = 0;
754 memset (bitmap, 0, size / 8);
755 return bitmap;
757 #endif
759 for (p = klass; p != NULL; p = p->parent) {
760 gpointer iter = NULL;
761 while ((field = mono_class_get_fields (p, &iter))) {
762 MonoType *type;
764 if (static_fields) {
765 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
766 continue;
767 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
768 continue;
769 } else {
770 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
771 continue;
773 /* FIXME: should not happen, flag as type load error */
774 if (field->type->byref)
775 break;
777 if (static_fields && field->offset == -1)
778 /* special static */
779 continue;
781 pos = field->offset / sizeof (gpointer);
782 pos += offset;
784 type = mono_type_get_underlying_type (field->type);
785 switch (type->type) {
786 case MONO_TYPE_I:
787 case MONO_TYPE_PTR:
788 case MONO_TYPE_FNPTR:
789 break;
790 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
791 case MONO_TYPE_U:
792 #ifdef HAVE_SGEN_GC
793 break;
794 #else
795 if (klass->image != mono_defaults.corlib)
796 break;
797 #endif
798 case MONO_TYPE_STRING:
799 case MONO_TYPE_SZARRAY:
800 case MONO_TYPE_CLASS:
801 case MONO_TYPE_OBJECT:
802 case MONO_TYPE_ARRAY:
803 g_assert ((field->offset % sizeof(gpointer)) == 0);
805 g_assert (pos < size || pos <= max_size);
806 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
807 *max_set = MAX (*max_set, pos);
808 break;
809 case MONO_TYPE_GENERICINST:
810 if (!mono_type_generic_inst_is_valuetype (type)) {
811 g_assert ((field->offset % sizeof(gpointer)) == 0);
813 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
814 *max_set = MAX (*max_set, pos);
815 break;
816 } else {
817 /* fall through */
819 case MONO_TYPE_VALUETYPE: {
820 MonoClass *fclass = mono_class_from_mono_type (field->type);
821 if (fclass->has_references) {
822 /* remove the object header */
823 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
825 break;
827 case MONO_TYPE_I1:
828 case MONO_TYPE_U1:
829 case MONO_TYPE_I2:
830 case MONO_TYPE_U2:
831 case MONO_TYPE_I4:
832 case MONO_TYPE_U4:
833 case MONO_TYPE_I8:
834 case MONO_TYPE_U8:
835 case MONO_TYPE_R4:
836 case MONO_TYPE_R8:
837 case MONO_TYPE_BOOLEAN:
838 case MONO_TYPE_CHAR:
839 break;
840 default:
841 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
842 break;
845 if (static_fields)
846 break;
848 return bitmap;
852 * mono_class_compute_bitmap:
854 * Mono internal function to compute a bitmap of reference fields in a class.
856 gsize*
857 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
859 MONO_REQ_GC_NEUTRAL_MODE;
861 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
864 #if 0
866 * similar to the above, but sets the bits in the bitmap for any non-ref field
867 * and ignores static fields
869 static gsize*
870 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
872 MonoClassField *field;
873 MonoClass *p;
874 guint32 pos, pos2;
875 int max_size;
877 max_size = class->instance_size / sizeof (gpointer);
878 if (max_size >= size) {
879 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
882 for (p = class; p != NULL; p = p->parent) {
883 gpointer iter = NULL;
884 while ((field = mono_class_get_fields (p, &iter))) {
885 MonoType *type;
887 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
888 continue;
889 /* FIXME: should not happen, flag as type load error */
890 if (field->type->byref)
891 break;
893 pos = field->offset / sizeof (gpointer);
894 pos += offset;
896 type = mono_type_get_underlying_type (field->type);
897 switch (type->type) {
898 #if SIZEOF_VOID_P == 8
899 case MONO_TYPE_I:
900 case MONO_TYPE_U:
901 case MONO_TYPE_PTR:
902 case MONO_TYPE_FNPTR:
903 #endif
904 case MONO_TYPE_I8:
905 case MONO_TYPE_U8:
906 case MONO_TYPE_R8:
907 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
908 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
909 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
911 /* fall through */
912 #if SIZEOF_VOID_P == 4
913 case MONO_TYPE_I:
914 case MONO_TYPE_U:
915 case MONO_TYPE_PTR:
916 case MONO_TYPE_FNPTR:
917 #endif
918 case MONO_TYPE_I4:
919 case MONO_TYPE_U4:
920 case MONO_TYPE_R4:
921 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
922 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
923 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
925 /* fall through */
926 case MONO_TYPE_CHAR:
927 case MONO_TYPE_I2:
928 case MONO_TYPE_U2:
929 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
930 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
931 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
933 /* fall through */
934 case MONO_TYPE_BOOLEAN:
935 case MONO_TYPE_I1:
936 case MONO_TYPE_U1:
937 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
938 break;
939 case MONO_TYPE_STRING:
940 case MONO_TYPE_SZARRAY:
941 case MONO_TYPE_CLASS:
942 case MONO_TYPE_OBJECT:
943 case MONO_TYPE_ARRAY:
944 break;
945 case MONO_TYPE_GENERICINST:
946 if (!mono_type_generic_inst_is_valuetype (type)) {
947 break;
948 } else {
949 /* fall through */
951 case MONO_TYPE_VALUETYPE: {
952 MonoClass *fclass = mono_class_from_mono_type (field->type);
953 /* remove the object header */
954 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
955 break;
957 default:
958 g_assert_not_reached ();
959 break;
963 return bitmap;
967 * mono_class_insecure_overlapping:
968 * check if a class with explicit layout has references and non-references
969 * fields overlapping.
971 * Returns: TRUE if it is insecure to load the type.
973 gboolean
974 mono_class_insecure_overlapping (MonoClass *klass)
976 int max_set = 0;
977 gsize *bitmap;
978 gsize default_bitmap [4] = {0};
979 gsize *nrbitmap;
980 gsize default_nrbitmap [4] = {0};
981 int i, insecure = FALSE;
982 return FALSE;
984 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
985 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
987 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
988 int idx = i % (sizeof (bitmap [0]) * 8);
989 if (bitmap [idx] & nrbitmap [idx]) {
990 insecure = TRUE;
991 break;
994 if (bitmap != default_bitmap)
995 g_free (bitmap);
996 if (nrbitmap != default_nrbitmap)
997 g_free (nrbitmap);
998 if (insecure) {
999 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1000 return FALSE;
1002 return insecure;
1004 #endif
1006 MonoString*
1007 ves_icall_string_alloc (int length)
1009 MonoError error;
1010 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1011 mono_error_set_pending_exception (&error);
1013 return str;
1016 /* LOCKING: Acquires the loader lock */
1017 void
1018 mono_class_compute_gc_descriptor (MonoClass *klass)
1020 MONO_REQ_GC_NEUTRAL_MODE;
1022 int max_set = 0;
1023 gsize *bitmap;
1024 gsize default_bitmap [4] = {0};
1025 static gboolean gcj_inited = FALSE;
1026 MonoGCDescriptor gc_descr;
1028 if (!gcj_inited) {
1029 mono_loader_lock ();
1031 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1032 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1034 gcj_inited = TRUE;
1035 mono_loader_unlock ();
1038 if (!klass->inited)
1039 mono_class_init (klass);
1041 if (klass->gc_descr_inited)
1042 return;
1044 bitmap = default_bitmap;
1045 if (klass == mono_defaults.string_class) {
1046 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1047 } else if (klass->rank) {
1048 mono_class_compute_gc_descriptor (klass->element_class);
1049 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1050 gsize abm = 1;
1051 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1052 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1053 class->name_space, class->name);*/
1054 } else {
1055 /* remove the object header */
1056 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1057 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1058 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1059 class->name_space, class->name);*/
1060 if (bitmap != default_bitmap)
1061 g_free (bitmap);
1063 } else {
1064 /*static int count = 0;
1065 if (count++ > 58)
1066 return;*/
1067 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1068 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1070 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1071 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1073 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1074 if (bitmap != default_bitmap)
1075 g_free (bitmap);
1078 /* Publish the data */
1079 mono_loader_lock ();
1080 klass->gc_descr = gc_descr;
1081 mono_memory_barrier ();
1082 klass->gc_descr_inited = TRUE;
1083 mono_loader_unlock ();
1087 * field_is_special_static:
1088 * @fklass: The MonoClass to look up.
1089 * @field: The MonoClassField describing the field.
1091 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1092 * SPECIAL_STATIC_NONE otherwise.
1094 static gint32
1095 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1097 MONO_REQ_GC_NEUTRAL_MODE;
1099 MonoError error;
1100 MonoCustomAttrInfo *ainfo;
1101 int i;
1102 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1103 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1104 if (!ainfo)
1105 return FALSE;
1106 for (i = 0; i < ainfo->num_attrs; ++i) {
1107 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1108 if (klass->image == mono_defaults.corlib) {
1109 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1110 mono_custom_attrs_free (ainfo);
1111 return SPECIAL_STATIC_THREAD;
1113 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1114 mono_custom_attrs_free (ainfo);
1115 return SPECIAL_STATIC_CONTEXT;
1119 mono_custom_attrs_free (ainfo);
1120 return SPECIAL_STATIC_NONE;
1123 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1124 #define mix(a,b,c) { \
1125 a -= c; a ^= rot(c, 4); c += b; \
1126 b -= a; b ^= rot(a, 6); a += c; \
1127 c -= b; c ^= rot(b, 8); b += a; \
1128 a -= c; a ^= rot(c,16); c += b; \
1129 b -= a; b ^= rot(a,19); a += c; \
1130 c -= b; c ^= rot(b, 4); b += a; \
1132 #define final(a,b,c) { \
1133 c ^= b; c -= rot(b,14); \
1134 a ^= c; a -= rot(c,11); \
1135 b ^= a; b -= rot(a,25); \
1136 c ^= b; c -= rot(b,16); \
1137 a ^= c; a -= rot(c,4); \
1138 b ^= a; b -= rot(a,14); \
1139 c ^= b; c -= rot(b,24); \
1143 * mono_method_get_imt_slot:
1145 * The IMT slot is embedded into AOTed code, so this must return the same value
1146 * for the same method across all executions. This means:
1147 * - pointers shouldn't be used as hash values.
1148 * - mono_metadata_str_hash () should be used for hashing strings.
1150 guint32
1151 mono_method_get_imt_slot (MonoMethod *method)
1153 MONO_REQ_GC_NEUTRAL_MODE;
1155 MonoMethodSignature *sig;
1156 int hashes_count;
1157 guint32 *hashes_start, *hashes;
1158 guint32 a, b, c;
1159 int i;
1161 /* This can be used to stress tests the collision code */
1162 //return 0;
1165 * We do this to simplify generic sharing. It will hurt
1166 * performance in cases where a class implements two different
1167 * instantiations of the same generic interface.
1168 * The code in build_imt_slots () depends on this.
1170 if (method->is_inflated)
1171 method = ((MonoMethodInflated*)method)->declaring;
1173 sig = mono_method_signature (method);
1174 hashes_count = sig->param_count + 4;
1175 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1176 hashes = hashes_start;
1178 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1179 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1180 method->klass->name_space, method->klass->name, method->name);
1183 /* Initialize hashes */
1184 hashes [0] = mono_metadata_str_hash (method->klass->name);
1185 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1186 hashes [2] = mono_metadata_str_hash (method->name);
1187 hashes [3] = mono_metadata_type_hash (sig->ret);
1188 for (i = 0; i < sig->param_count; i++) {
1189 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1192 /* Setup internal state */
1193 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1195 /* Handle most of the hashes */
1196 while (hashes_count > 3) {
1197 a += hashes [0];
1198 b += hashes [1];
1199 c += hashes [2];
1200 mix (a,b,c);
1201 hashes_count -= 3;
1202 hashes += 3;
1205 /* Handle the last 3 hashes (all the case statements fall through) */
1206 switch (hashes_count) {
1207 case 3 : c += hashes [2];
1208 case 2 : b += hashes [1];
1209 case 1 : a += hashes [0];
1210 final (a,b,c);
1211 case 0: /* nothing left to add */
1212 break;
1215 g_free (hashes_start);
1216 /* Report the result */
1217 return c % MONO_IMT_SIZE;
1219 #undef rot
1220 #undef mix
1221 #undef final
1223 #define DEBUG_IMT 0
1225 static void
1226 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1227 MONO_REQ_GC_NEUTRAL_MODE;
1229 guint32 imt_slot = mono_method_get_imt_slot (method);
1230 MonoImtBuilderEntry *entry;
1232 if (slot_num >= 0 && imt_slot != slot_num) {
1233 /* we build just a single imt slot and this is not it */
1234 return;
1237 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1238 entry->key = method;
1239 entry->value.vtable_slot = vtable_slot;
1240 entry->next = imt_builder [imt_slot];
1241 if (imt_builder [imt_slot] != NULL) {
1242 entry->children = imt_builder [imt_slot]->children + 1;
1243 if (entry->children == 1) {
1244 mono_stats.imt_slots_with_collisions++;
1245 *imt_collisions_bitmap |= (1 << imt_slot);
1247 } else {
1248 entry->children = 0;
1249 mono_stats.imt_used_slots++;
1251 imt_builder [imt_slot] = entry;
1252 #if DEBUG_IMT
1254 char *method_name = mono_method_full_name (method, TRUE);
1255 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1256 method, method_name, imt_slot, vtable_slot, entry->children);
1257 g_free (method_name);
1259 #endif
1262 #if DEBUG_IMT
1263 static void
1264 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1265 if (e != NULL) {
1266 MonoMethod *method = e->key;
1267 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1268 message,
1269 num,
1270 method,
1271 method->klass->name_space,
1272 method->klass->name,
1273 method->name);
1274 } else {
1275 printf (" * %s: NULL\n", message);
1278 #endif
1280 static int
1281 compare_imt_builder_entries (const void *p1, const void *p2) {
1282 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1283 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1285 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1288 static int
1289 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1291 MONO_REQ_GC_NEUTRAL_MODE;
1293 int count = end - start;
1294 int chunk_start = out_array->len;
1295 if (count < 4) {
1296 int i;
1297 for (i = start; i < end; ++i) {
1298 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1299 item->key = sorted_array [i]->key;
1300 item->value = sorted_array [i]->value;
1301 item->has_target_code = sorted_array [i]->has_target_code;
1302 item->is_equals = TRUE;
1303 if (i < end - 1)
1304 item->check_target_idx = out_array->len + 1;
1305 else
1306 item->check_target_idx = 0;
1307 g_ptr_array_add (out_array, item);
1309 } else {
1310 int middle = start + count / 2;
1311 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1313 item->key = sorted_array [middle]->key;
1314 item->is_equals = FALSE;
1315 g_ptr_array_add (out_array, item);
1316 imt_emit_ir (sorted_array, start, middle, out_array);
1317 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1319 return chunk_start;
1322 static GPtrArray*
1323 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1324 MONO_REQ_GC_NEUTRAL_MODE;
1326 int number_of_entries = entries->children + 1;
1327 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1328 GPtrArray *result = g_ptr_array_new ();
1329 MonoImtBuilderEntry *current_entry;
1330 int i;
1332 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1333 sorted_array [i] = current_entry;
1335 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1337 /*for (i = 0; i < number_of_entries; i++) {
1338 print_imt_entry (" sorted array:", sorted_array [i], i);
1341 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1343 g_free (sorted_array);
1344 return result;
1347 static gpointer
1348 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1350 MONO_REQ_GC_NEUTRAL_MODE;
1352 if (imt_builder_entry != NULL) {
1353 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1354 /* No collision, return the vtable slot contents */
1355 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1356 } else {
1357 /* Collision, build the trampoline */
1358 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1359 gpointer result;
1360 int i;
1361 result = imt_trampoline_builder (vtable, domain,
1362 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1363 for (i = 0; i < imt_ir->len; ++i)
1364 g_free (g_ptr_array_index (imt_ir, i));
1365 g_ptr_array_free (imt_ir, TRUE);
1366 return result;
1368 } else {
1369 if (fail_tramp)
1370 return fail_tramp;
1371 else
1372 /* Empty slot */
1373 return NULL;
1377 static MonoImtBuilderEntry*
1378 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1381 * LOCKING: requires the loader and domain locks.
1384 static void
1385 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1387 MONO_REQ_GC_NEUTRAL_MODE;
1389 int i;
1390 GSList *list_item;
1391 guint32 imt_collisions_bitmap = 0;
1392 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1393 int method_count = 0;
1394 gboolean record_method_count_for_max_collisions = FALSE;
1395 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1397 #if DEBUG_IMT
1398 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1399 #endif
1400 for (i = 0; i < klass->interface_offsets_count; ++i) {
1401 MonoClass *iface = klass->interfaces_packed [i];
1402 int interface_offset = klass->interface_offsets_packed [i];
1403 int method_slot_in_interface, vt_slot;
1405 if (mono_class_has_variant_generic_params (iface))
1406 has_variant_iface = TRUE;
1408 mono_class_setup_methods (iface);
1409 vt_slot = interface_offset;
1410 int mcount = mono_class_get_method_count (iface);
1411 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1412 MonoMethod *method;
1414 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1416 * The imt slot of the method is the same as for its declaring method,
1417 * see the comment in mono_method_get_imt_slot (), so we can
1418 * avoid inflating methods which will be discarded by
1419 * add_imt_builder_entry anyway.
1421 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1422 if (mono_method_get_imt_slot (method) != slot_num) {
1423 vt_slot ++;
1424 continue;
1427 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1428 if (method->is_generic) {
1429 has_generic_virtual = TRUE;
1430 vt_slot ++;
1431 continue;
1434 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1435 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1436 vt_slot ++;
1440 if (extra_interfaces) {
1441 int interface_offset = klass->vtable_size;
1443 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1444 MonoClass* iface = (MonoClass *)list_item->data;
1445 int method_slot_in_interface;
1446 int mcount = mono_class_get_method_count (iface);
1447 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1448 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1450 if (method->is_generic)
1451 has_generic_virtual = TRUE;
1452 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1454 interface_offset += mcount;
1457 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1458 /* overwrite the imt slot only if we're building all the entries or if
1459 * we're building this specific one
1461 if (slot_num < 0 || i == slot_num) {
1462 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1464 if (entries) {
1465 if (imt_builder [i]) {
1466 MonoImtBuilderEntry *entry;
1468 /* Link entries with imt_builder [i] */
1469 for (entry = entries; entry->next; entry = entry->next) {
1470 #if DEBUG_IMT
1471 MonoMethod *method = (MonoMethod*)entry->key;
1472 char *method_name = mono_method_full_name (method, TRUE);
1473 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1474 g_free (method_name);
1475 #endif
1477 entry->next = imt_builder [i];
1478 entries->children += imt_builder [i]->children + 1;
1480 imt_builder [i] = entries;
1483 if (has_generic_virtual || has_variant_iface) {
1485 * There might be collisions later when the the trampoline is expanded.
1487 imt_collisions_bitmap |= (1 << i);
1490 * The IMT trampoline might be called with an instance of one of the
1491 * generic virtual methods, so has to fallback to the IMT trampoline.
1493 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1494 } else {
1495 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1497 #if DEBUG_IMT
1498 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1499 #endif
1502 if (imt_builder [i] != NULL) {
1503 int methods_in_slot = imt_builder [i]->children + 1;
1504 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1505 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1506 record_method_count_for_max_collisions = TRUE;
1508 method_count += methods_in_slot;
1512 mono_stats.imt_number_of_methods += method_count;
1513 if (record_method_count_for_max_collisions) {
1514 mono_stats.imt_method_count_when_max_collisions = method_count;
1517 for (i = 0; i < MONO_IMT_SIZE; i++) {
1518 MonoImtBuilderEntry* entry = imt_builder [i];
1519 while (entry != NULL) {
1520 MonoImtBuilderEntry* next = entry->next;
1521 g_free (entry);
1522 entry = next;
1525 g_free (imt_builder);
1526 /* we OR the bitmap since we may build just a single imt slot at a time */
1527 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1530 static void
1531 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1532 MONO_REQ_GC_NEUTRAL_MODE;
1534 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1538 * mono_vtable_build_imt_slot:
1539 * @vtable: virtual object table struct
1540 * @imt_slot: slot in the IMT table
1542 * Fill the given @imt_slot in the IMT table of @vtable with
1543 * a trampoline or a trampoline for the case of collisions.
1544 * This is part of the internal mono API.
1546 * LOCKING: Take the domain lock.
1548 void
1549 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1551 MONO_REQ_GC_NEUTRAL_MODE;
1553 gpointer *imt = (gpointer*)vtable;
1554 imt -= MONO_IMT_SIZE;
1555 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1557 /* no support for extra interfaces: the proxy objects will need
1558 * to build the complete IMT
1559 * Update and heck needs to ahppen inside the proper domain lock, as all
1560 * the changes made to a MonoVTable.
1562 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1563 mono_domain_lock (vtable->domain);
1564 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1565 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1566 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1567 mono_domain_unlock (vtable->domain);
1568 mono_loader_unlock ();
1571 #define THUNK_THRESHOLD 10
1574 * mono_method_alloc_generic_virtual_trampoline:
1575 * @domain: a domain
1576 * @size: size in bytes
1578 * Allocs size bytes to be used for the code of a generic virtual
1579 * trampoline. It's either allocated from the domain's code manager or
1580 * reused from a previously invalidated piece.
1582 * LOCKING: The domain lock must be held.
1584 gpointer
1585 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1587 MONO_REQ_GC_NEUTRAL_MODE;
1589 static gboolean inited = FALSE;
1590 static int generic_virtual_trampolines_size = 0;
1592 if (!inited) {
1593 mono_counters_register ("Generic virtual trampoline bytes",
1594 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1595 inited = TRUE;
1597 generic_virtual_trampolines_size += size;
1599 return mono_domain_code_reserve (domain, size);
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 MONO_REQ_GC_NEUTRAL_MODE;
1621 GenericVirtualCase *list;
1622 MonoImtBuilderEntry *entries;
1624 mono_domain_lock (domain);
1625 if (!domain->generic_virtual_cases)
1626 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1628 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1630 entries = NULL;
1631 for (; list; list = list->next) {
1632 MonoImtBuilderEntry *entry;
1634 if (list->count < THUNK_THRESHOLD)
1635 continue;
1637 entry = g_new0 (MonoImtBuilderEntry, 1);
1638 entry->key = list->method;
1639 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1640 entry->has_target_code = 1;
1641 if (entries)
1642 entry->children = entries->children + 1;
1643 entry->next = entries;
1644 entries = entry;
1647 mono_domain_unlock (domain);
1649 /* FIXME: Leaking memory ? */
1650 return entries;
1654 * mono_method_add_generic_virtual_invocation:
1655 * @domain: a domain
1656 * @vtable_slot: pointer to the vtable slot
1657 * @method: the inflated generic virtual method
1658 * @code: the method's code
1660 * Registers a call via unmanaged code to a generic virtual method
1661 * instantiation or variant interface method. If the number of calls reaches a threshold
1662 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1663 * virtual method trampoline.
1665 void
1666 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1667 gpointer *vtable_slot,
1668 MonoMethod *method, gpointer code)
1670 MONO_REQ_GC_NEUTRAL_MODE;
1672 static gboolean inited = FALSE;
1673 static int num_added = 0;
1674 static int num_freed = 0;
1676 GenericVirtualCase *gvc, *list;
1677 MonoImtBuilderEntry *entries;
1678 int i;
1679 GPtrArray *sorted;
1681 mono_domain_lock (domain);
1682 if (!domain->generic_virtual_cases)
1683 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1685 if (!inited) {
1686 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1687 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1688 inited = TRUE;
1691 /* Check whether the case was already added */
1692 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1693 gvc = list;
1694 while (gvc) {
1695 if (gvc->method == method)
1696 break;
1697 gvc = gvc->next;
1700 /* If not found, make a new one */
1701 if (!gvc) {
1702 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1703 gvc->method = method;
1704 gvc->code = code;
1705 gvc->count = 0;
1706 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1708 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1710 num_added++;
1713 if (++gvc->count == THUNK_THRESHOLD) {
1714 gpointer *old_thunk = (void **)*vtable_slot;
1715 gpointer vtable_trampoline = NULL;
1716 gpointer imt_trampoline = NULL;
1718 if ((gpointer)vtable_slot < (gpointer)vtable) {
1719 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1720 int imt_slot = MONO_IMT_SIZE + displacement;
1722 /* Force the rebuild of the trampoline at the next call */
1723 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1724 *vtable_slot = imt_trampoline;
1725 } else {
1726 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1728 entries = get_generic_virtual_entries (domain, vtable_slot);
1730 sorted = imt_sort_slot_entries (entries);
1732 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1733 vtable_trampoline);
1735 while (entries) {
1736 MonoImtBuilderEntry *next = entries->next;
1737 g_free (entries);
1738 entries = next;
1741 for (i = 0; i < sorted->len; ++i)
1742 g_free (g_ptr_array_index (sorted, i));
1743 g_ptr_array_free (sorted, TRUE);
1745 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1746 num_freed ++;
1750 mono_domain_unlock (domain);
1753 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1756 * mono_class_vtable:
1757 * @domain: the application domain
1758 * @class: the class to initialize
1760 * VTables are domain specific because we create domain specific code, and
1761 * they contain the domain specific static class data.
1762 * On failure, NULL is returned, and class->exception_type is set.
1764 MonoVTable *
1765 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1767 MonoError error;
1768 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1769 mono_error_cleanup (&error);
1770 return vtable;
1774 * mono_class_vtable_full:
1775 * @domain: the application domain
1776 * @class: the class to initialize
1777 * @error set on failure.
1779 * VTables are domain specific because we create domain specific code, and
1780 * they contain the domain specific static class data.
1782 MonoVTable *
1783 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1785 MONO_REQ_GC_UNSAFE_MODE;
1787 MonoClassRuntimeInfo *runtime_info;
1789 mono_error_init (error);
1791 g_assert (klass);
1793 if (mono_class_has_failure (klass)) {
1794 mono_error_set_for_class_failure (error, klass);
1795 return NULL;
1798 /* this check can be inlined in jitted code, too */
1799 runtime_info = klass->runtime_info;
1800 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1801 return runtime_info->domain_vtables [domain->domain_id];
1802 return mono_class_create_runtime_vtable (domain, klass, error);
1806 * mono_class_try_get_vtable:
1807 * @domain: the application domain
1808 * @class: the class to initialize
1810 * This function tries to get the associated vtable from @class if
1811 * it was already created.
1813 MonoVTable *
1814 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1816 MONO_REQ_GC_NEUTRAL_MODE;
1818 MonoClassRuntimeInfo *runtime_info;
1820 g_assert (klass);
1822 runtime_info = klass->runtime_info;
1823 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1824 return runtime_info->domain_vtables [domain->domain_id];
1825 return NULL;
1828 static gpointer*
1829 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1831 MONO_REQ_GC_NEUTRAL_MODE;
1833 size_t alloc_offset;
1836 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1837 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1838 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1840 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1841 g_assert ((imt_table_bytes & 7) == 4);
1842 vtable_size += 4;
1843 alloc_offset = 4;
1844 } else {
1845 alloc_offset = 0;
1848 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1851 static MonoVTable *
1852 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1854 MONO_REQ_GC_UNSAFE_MODE;
1856 MonoVTable *vt;
1857 MonoClassRuntimeInfo *runtime_info, *old_info;
1858 MonoClassField *field;
1859 char *t;
1860 int i, vtable_slots;
1861 size_t imt_table_bytes;
1862 int gc_bits;
1863 guint32 vtable_size, class_size;
1864 gpointer iter;
1865 gpointer *interface_offsets;
1867 mono_error_init (error);
1869 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1870 mono_domain_lock (domain);
1871 runtime_info = klass->runtime_info;
1872 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1873 mono_domain_unlock (domain);
1874 mono_loader_unlock ();
1875 return runtime_info->domain_vtables [domain->domain_id];
1877 if (!klass->inited || mono_class_has_failure (klass)) {
1878 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1879 mono_domain_unlock (domain);
1880 mono_loader_unlock ();
1881 mono_error_set_for_class_failure (error, klass);
1882 return NULL;
1886 /* Array types require that their element type be valid*/
1887 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1888 MonoClass *element_class = klass->element_class;
1889 if (!element_class->inited)
1890 mono_class_init (element_class);
1892 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1893 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1894 mono_class_setup_vtable (element_class);
1896 if (mono_class_has_failure (element_class)) {
1897 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1898 if (!mono_class_has_failure (klass))
1899 mono_class_set_type_load_failure (klass, "");
1900 mono_domain_unlock (domain);
1901 mono_loader_unlock ();
1902 mono_error_set_for_class_failure (error, klass);
1903 return NULL;
1908 * For some classes, mono_class_init () already computed klass->vtable_size, and
1909 * that is all that is needed because of the vtable trampolines.
1911 if (!klass->vtable_size)
1912 mono_class_setup_vtable (klass);
1914 if (mono_class_is_ginst (klass) && !klass->vtable)
1915 mono_class_check_vtable_constraints (klass, NULL);
1917 /* Initialize klass->has_finalize */
1918 mono_class_has_finalizer (klass);
1920 if (mono_class_has_failure (klass)) {
1921 mono_domain_unlock (domain);
1922 mono_loader_unlock ();
1923 mono_error_set_for_class_failure (error, klass);
1924 return NULL;
1927 vtable_slots = klass->vtable_size;
1928 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1929 class_size = mono_class_data_size (klass);
1930 if (class_size)
1931 vtable_slots++;
1933 if (klass->interface_offsets_count) {
1934 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1935 mono_stats.imt_number_of_tables++;
1936 mono_stats.imt_tables_size += imt_table_bytes;
1937 } else {
1938 imt_table_bytes = 0;
1941 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1943 mono_stats.used_class_count++;
1944 mono_stats.class_vtable_size += vtable_size;
1946 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1947 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1948 g_assert (!((gsize)vt & 7));
1950 vt->klass = klass;
1951 vt->rank = klass->rank;
1952 vt->domain = domain;
1954 mono_class_compute_gc_descriptor (klass);
1956 * We can't use typed allocation in the non-root domains, since the
1957 * collector needs the GC descriptor stored in the vtable even after
1958 * the mempool containing the vtable is destroyed when the domain is
1959 * unloaded. An alternative might be to allocate vtables in the GC
1960 * heap, but this does not seem to work (it leads to crashes inside
1961 * libgc). If that approach is tried, two gc descriptors need to be
1962 * allocated for each class: one for the root domain, and one for all
1963 * other domains. The second descriptor should contain a bit for the
1964 * vtable field in MonoObject, since we can no longer assume the
1965 * vtable is reachable by other roots after the appdomain is unloaded.
1967 #ifdef HAVE_BOEHM_GC
1968 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1969 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1970 else
1971 #endif
1972 vt->gc_descr = klass->gc_descr;
1974 gc_bits = mono_gc_get_vtable_bits (klass);
1975 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1977 vt->gc_bits = gc_bits;
1979 if (class_size) {
1980 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1981 if (klass->has_static_refs) {
1982 MonoGCDescriptor statics_gc_descr;
1983 int max_set = 0;
1984 gsize default_bitmap [4] = {0};
1985 gsize *bitmap;
1987 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1988 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1989 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1990 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1991 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1992 if (bitmap != default_bitmap)
1993 g_free (bitmap);
1994 } else {
1995 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1997 vt->has_static_fields = TRUE;
1998 mono_stats.class_static_data_size += class_size;
2001 iter = NULL;
2002 while ((field = mono_class_get_fields (klass, &iter))) {
2003 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2004 continue;
2005 if (mono_field_is_deleted (field))
2006 continue;
2007 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2008 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2009 if (special_static != SPECIAL_STATIC_NONE) {
2010 guint32 size, offset;
2011 gint32 align;
2012 gsize default_bitmap [4] = {0};
2013 gsize *bitmap;
2014 int max_set = 0;
2015 int numbits;
2016 MonoClass *fclass;
2017 if (mono_type_is_reference (field->type)) {
2018 default_bitmap [0] = 1;
2019 numbits = 1;
2020 bitmap = default_bitmap;
2021 } else if (mono_type_is_struct (field->type)) {
2022 fclass = mono_class_from_mono_type (field->type);
2023 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2024 numbits = max_set + 1;
2025 } else {
2026 default_bitmap [0] = 0;
2027 numbits = 0;
2028 bitmap = default_bitmap;
2030 size = mono_type_size (field->type, &align);
2031 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2032 if (!domain->special_static_fields)
2033 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2034 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2035 if (bitmap != default_bitmap)
2036 g_free (bitmap);
2038 * This marks the field as special static to speed up the
2039 * checks in mono_field_static_get/set_value ().
2041 field->offset = -1;
2042 continue;
2045 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2046 MonoClass *fklass = mono_class_from_mono_type (field->type);
2047 const char *data = mono_field_get_data (field);
2049 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2050 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2051 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2052 if (!data)
2053 continue;
2054 if (fklass->valuetype) {
2055 memcpy (t, data, mono_class_value_size (fklass, NULL));
2056 } else {
2057 /* it's a pointer type: add check */
2058 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2059 *t = *(char *)data;
2061 continue;
2065 vt->max_interface_id = klass->max_interface_id;
2066 vt->interface_bitmap = klass->interface_bitmap;
2068 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2069 // class->name, klass->interface_offsets_count);
2071 /* Initialize vtable */
2072 if (callbacks.get_vtable_trampoline) {
2073 // This also covers the AOT case
2074 for (i = 0; i < klass->vtable_size; ++i) {
2075 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2077 } else {
2078 mono_class_setup_vtable (klass);
2080 for (i = 0; i < klass->vtable_size; ++i) {
2081 MonoMethod *cm;
2083 cm = klass->vtable [i];
2084 if (cm) {
2085 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2086 if (!is_ok (error)) {
2087 mono_domain_unlock (domain);
2088 mono_loader_unlock ();
2089 return NULL;
2095 if (imt_table_bytes) {
2096 /* Now that the vtable is full, we can actually fill up the IMT */
2097 for (i = 0; i < MONO_IMT_SIZE; ++i)
2098 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2102 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2103 * re-acquire them and check if another thread has created the vtable in the meantime.
2105 /* Special case System.MonoType to avoid infinite recursion */
2106 if (klass != mono_defaults.runtimetype_class) {
2107 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2108 if (!is_ok (error)) {
2109 mono_domain_unlock (domain);
2110 mono_loader_unlock ();
2111 return NULL;
2114 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2115 /* This is unregistered in
2116 unregister_vtable_reflection_type() in
2117 domain.c. */
2118 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2121 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2123 /* class_vtable_array keeps an array of created vtables
2125 g_ptr_array_add (domain->class_vtable_array, vt);
2126 /* klass->runtime_info is protected by the loader lock, both when
2127 * it it enlarged and when it is stored info.
2131 * Store the vtable in klass->runtime_info.
2132 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2134 mono_memory_barrier ();
2136 old_info = klass->runtime_info;
2137 if (old_info && old_info->max_domain >= domain->domain_id) {
2138 /* someone already created a large enough runtime info */
2139 old_info->domain_vtables [domain->domain_id] = vt;
2140 } else {
2141 int new_size = domain->domain_id;
2142 if (old_info)
2143 new_size = MAX (new_size, old_info->max_domain);
2144 new_size++;
2145 /* make the new size a power of two */
2146 i = 2;
2147 while (new_size > i)
2148 i <<= 1;
2149 new_size = i;
2150 /* this is a bounded memory retention issue: may want to
2151 * handle it differently when we'll have a rcu-like system.
2153 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2154 runtime_info->max_domain = new_size - 1;
2155 /* copy the stuff from the older info */
2156 if (old_info) {
2157 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2159 runtime_info->domain_vtables [domain->domain_id] = vt;
2160 /* keep this last*/
2161 mono_memory_barrier ();
2162 klass->runtime_info = runtime_info;
2165 if (klass == mono_defaults.runtimetype_class) {
2166 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2167 if (!is_ok (error)) {
2168 mono_domain_unlock (domain);
2169 mono_loader_unlock ();
2170 return NULL;
2173 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2174 /* This is unregistered in
2175 unregister_vtable_reflection_type() in
2176 domain.c. */
2177 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2180 mono_domain_unlock (domain);
2181 mono_loader_unlock ();
2183 /* make sure the parent is initialized */
2184 /*FIXME shouldn't this fail the current type?*/
2185 if (klass->parent)
2186 mono_class_vtable_full (domain, klass->parent, error);
2188 return vt;
2191 #ifndef DISABLE_REMOTING
2193 * mono_class_proxy_vtable:
2194 * @domain: the application domain
2195 * @remove_class: the remote class
2196 * @error: set on error
2198 * Creates a vtable for transparent proxies. It is basically
2199 * a copy of the real vtable of the class wrapped in @remote_class,
2200 * but all function pointers invoke the remoting functions, and
2201 * vtable->klass points to the transparent proxy class, and not to @class.
2203 * On failure returns NULL and sets @error
2205 static MonoVTable *
2206 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2208 MONO_REQ_GC_UNSAFE_MODE;
2210 MonoVTable *vt, *pvt;
2211 int i, j, vtsize, extra_interface_vtsize = 0;
2212 guint32 max_interface_id;
2213 MonoClass *k;
2214 GSList *extra_interfaces = NULL;
2215 MonoClass *klass = remote_class->proxy_class;
2216 gpointer *interface_offsets;
2217 uint8_t *bitmap = NULL;
2218 int bsize;
2219 size_t imt_table_bytes;
2221 #ifdef COMPRESSED_INTERFACE_BITMAP
2222 int bcsize;
2223 #endif
2225 mono_error_init (error);
2227 vt = mono_class_vtable (domain, klass);
2228 g_assert (vt); /*FIXME property handle failure*/
2229 max_interface_id = vt->max_interface_id;
2231 /* Calculate vtable space for extra interfaces */
2232 for (j = 0; j < remote_class->interface_count; j++) {
2233 MonoClass* iclass = remote_class->interfaces[j];
2234 GPtrArray *ifaces;
2235 int method_count;
2237 /*FIXME test for interfaces with variant generic arguments*/
2238 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2239 continue; /* interface implemented by the class */
2240 if (g_slist_find (extra_interfaces, iclass))
2241 continue;
2243 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2245 method_count = mono_class_num_methods (iclass);
2247 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2248 if (!is_ok (error))
2249 goto failure;
2250 if (ifaces) {
2251 for (i = 0; i < ifaces->len; ++i) {
2252 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2253 /*FIXME test for interfaces with variant generic arguments*/
2254 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2255 continue; /* interface implemented by the class */
2256 if (g_slist_find (extra_interfaces, ic))
2257 continue;
2258 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2259 method_count += mono_class_num_methods (ic);
2261 g_ptr_array_free (ifaces, TRUE);
2262 ifaces = NULL;
2265 extra_interface_vtsize += method_count * sizeof (gpointer);
2266 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2269 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2270 mono_stats.imt_number_of_tables++;
2271 mono_stats.imt_tables_size += imt_table_bytes;
2273 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2275 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2277 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2278 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2279 g_assert (!((gsize)pvt & 7));
2281 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2283 pvt->klass = mono_defaults.transparent_proxy_class;
2284 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2285 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2287 /* initialize vtable */
2288 mono_class_setup_vtable (klass);
2289 for (i = 0; i < klass->vtable_size; ++i) {
2290 MonoMethod *cm;
2292 if ((cm = klass->vtable [i])) {
2293 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2294 if (!is_ok (error))
2295 goto failure;
2296 } else
2297 pvt->vtable [i] = NULL;
2300 if (mono_class_is_abstract (klass)) {
2301 /* create trampolines for abstract methods */
2302 for (k = klass; k; k = k->parent) {
2303 MonoMethod* m;
2304 gpointer iter = NULL;
2305 while ((m = mono_class_get_methods (k, &iter)))
2306 if (!pvt->vtable [m->slot]) {
2307 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2308 if (!is_ok (error))
2309 goto failure;
2314 pvt->max_interface_id = max_interface_id;
2315 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2316 #ifdef COMPRESSED_INTERFACE_BITMAP
2317 bitmap = (uint8_t *)g_malloc0 (bsize);
2318 #else
2319 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2320 #endif
2322 for (i = 0; i < klass->interface_offsets_count; ++i) {
2323 int interface_id = klass->interfaces_packed [i]->interface_id;
2324 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2327 if (extra_interfaces) {
2328 int slot = klass->vtable_size;
2329 MonoClass* interf;
2330 gpointer iter;
2331 MonoMethod* cm;
2332 GSList *list_item;
2334 /* Create trampolines for the methods of the interfaces */
2335 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2336 interf = (MonoClass *)list_item->data;
2338 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2340 iter = NULL;
2341 j = 0;
2342 while ((cm = mono_class_get_methods (interf, &iter))) {
2343 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2344 if (!is_ok (error))
2345 goto failure;
2348 slot += mono_class_num_methods (interf);
2352 /* Now that the vtable is full, we can actually fill up the IMT */
2353 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2354 if (extra_interfaces) {
2355 g_slist_free (extra_interfaces);
2358 #ifdef COMPRESSED_INTERFACE_BITMAP
2359 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2360 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2361 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2362 g_free (bitmap);
2363 #else
2364 pvt->interface_bitmap = bitmap;
2365 #endif
2366 return pvt;
2367 failure:
2368 if (extra_interfaces)
2369 g_slist_free (extra_interfaces);
2370 #ifdef COMPRESSED_INTERFACE_BITMAP
2371 g_free (bitmap);
2372 #endif
2373 return NULL;
2376 #endif /* DISABLE_REMOTING */
2379 * mono_class_field_is_special_static:
2381 * Returns whether @field is a thread/context static field.
2383 gboolean
2384 mono_class_field_is_special_static (MonoClassField *field)
2386 MONO_REQ_GC_NEUTRAL_MODE
2388 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2389 return FALSE;
2390 if (mono_field_is_deleted (field))
2391 return FALSE;
2392 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2393 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2394 return TRUE;
2396 return FALSE;
2400 * mono_class_field_get_special_static_type:
2401 * @field: The MonoClassField describing the field.
2403 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2404 * SPECIAL_STATIC_NONE otherwise.
2406 guint32
2407 mono_class_field_get_special_static_type (MonoClassField *field)
2409 MONO_REQ_GC_NEUTRAL_MODE
2411 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2412 return SPECIAL_STATIC_NONE;
2413 if (mono_field_is_deleted (field))
2414 return SPECIAL_STATIC_NONE;
2415 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2416 return field_is_special_static (field->parent, field);
2417 return SPECIAL_STATIC_NONE;
2421 * mono_class_has_special_static_fields:
2423 * Returns whenever @klass has any thread/context static fields.
2425 gboolean
2426 mono_class_has_special_static_fields (MonoClass *klass)
2428 MONO_REQ_GC_NEUTRAL_MODE
2430 MonoClassField *field;
2431 gpointer iter;
2433 iter = NULL;
2434 while ((field = mono_class_get_fields (klass, &iter))) {
2435 g_assert (field->parent == klass);
2436 if (mono_class_field_is_special_static (field))
2437 return TRUE;
2440 return FALSE;
2443 #ifndef DISABLE_REMOTING
2445 * create_remote_class_key:
2446 * Creates an array of pointers that can be used as a hash key for a remote class.
2447 * The first element of the array is the number of pointers.
2449 static gpointer*
2450 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2452 MONO_REQ_GC_NEUTRAL_MODE;
2454 gpointer *key;
2455 int i, j;
2457 if (remote_class == NULL) {
2458 if (mono_class_is_interface (extra_class)) {
2459 key = (void **)g_malloc (sizeof(gpointer) * 3);
2460 key [0] = GINT_TO_POINTER (2);
2461 key [1] = mono_defaults.marshalbyrefobject_class;
2462 key [2] = extra_class;
2463 } else {
2464 key = (void **)g_malloc (sizeof(gpointer) * 2);
2465 key [0] = GINT_TO_POINTER (1);
2466 key [1] = extra_class;
2468 } else {
2469 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2470 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2471 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2472 key [1] = remote_class->proxy_class;
2474 // Keep the list of interfaces sorted
2475 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2476 if (extra_class && remote_class->interfaces [i] > extra_class) {
2477 key [j++] = extra_class;
2478 extra_class = NULL;
2480 key [j] = remote_class->interfaces [i];
2482 if (extra_class)
2483 key [j] = extra_class;
2484 } else {
2485 // Replace the old class. The interface list is the same
2486 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2487 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2488 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2489 for (i = 0; i < remote_class->interface_count; i++)
2490 key [2 + i] = remote_class->interfaces [i];
2494 return key;
2498 * copy_remote_class_key:
2500 * Make a copy of KEY in the domain and return the copy.
2502 static gpointer*
2503 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2505 MONO_REQ_GC_NEUTRAL_MODE
2507 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2508 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2510 memcpy (mp_key, key, key_size);
2512 return mp_key;
2516 * mono_remote_class:
2517 * @domain: the application domain
2518 * @class_name: name of the remote class
2519 * @error: set on error
2521 * Creates and initializes a MonoRemoteClass object for a remote type.
2523 * On failure returns NULL and sets @error
2525 MonoRemoteClass*
2526 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2528 MONO_REQ_GC_UNSAFE_MODE;
2530 MonoRemoteClass *rc;
2531 gpointer* key, *mp_key;
2532 char *name;
2534 mono_error_init (error);
2536 key = create_remote_class_key (NULL, proxy_class);
2538 mono_domain_lock (domain);
2539 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2541 if (rc) {
2542 g_free (key);
2543 mono_domain_unlock (domain);
2544 return rc;
2547 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2548 if (!is_ok (error)) {
2549 g_free (key);
2550 mono_domain_unlock (domain);
2551 return NULL;
2554 mp_key = copy_remote_class_key (domain, key);
2555 g_free (key);
2556 key = mp_key;
2558 if (mono_class_is_interface (proxy_class)) {
2559 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2560 rc->interface_count = 1;
2561 rc->interfaces [0] = proxy_class;
2562 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2563 } else {
2564 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2565 rc->interface_count = 0;
2566 rc->proxy_class = proxy_class;
2569 rc->default_vtable = NULL;
2570 rc->xdomain_vtable = NULL;
2571 rc->proxy_class_name = name;
2572 #ifndef DISABLE_PERFCOUNTERS
2573 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2574 #endif
2576 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2578 mono_domain_unlock (domain);
2579 return rc;
2583 * clone_remote_class:
2584 * Creates a copy of the remote_class, adding the provided class or interface
2586 static MonoRemoteClass*
2587 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2589 MONO_REQ_GC_NEUTRAL_MODE;
2591 MonoRemoteClass *rc;
2592 gpointer* key, *mp_key;
2594 key = create_remote_class_key (remote_class, extra_class);
2595 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2596 if (rc != NULL) {
2597 g_free (key);
2598 return rc;
2601 mp_key = copy_remote_class_key (domain, key);
2602 g_free (key);
2603 key = mp_key;
2605 if (mono_class_is_interface (extra_class)) {
2606 int i,j;
2607 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2608 rc->proxy_class = remote_class->proxy_class;
2609 rc->interface_count = remote_class->interface_count + 1;
2611 // Keep the list of interfaces sorted, since the hash key of
2612 // the remote class depends on this
2613 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2614 if (remote_class->interfaces [i] > extra_class && i == j)
2615 rc->interfaces [j++] = extra_class;
2616 rc->interfaces [j] = remote_class->interfaces [i];
2618 if (i == j)
2619 rc->interfaces [j] = extra_class;
2620 } else {
2621 // Replace the old class. The interface array is the same
2622 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2623 rc->proxy_class = extra_class;
2624 rc->interface_count = remote_class->interface_count;
2625 if (rc->interface_count > 0)
2626 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2629 rc->default_vtable = NULL;
2630 rc->xdomain_vtable = NULL;
2631 rc->proxy_class_name = remote_class->proxy_class_name;
2633 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2635 return rc;
2638 gpointer
2639 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2641 MONO_REQ_GC_UNSAFE_MODE;
2643 mono_error_init (error);
2645 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2646 mono_domain_lock (domain);
2647 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2648 if (target_domain_id != -1) {
2649 if (remote_class->xdomain_vtable == NULL)
2650 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2651 mono_domain_unlock (domain);
2652 mono_loader_unlock ();
2653 return_val_if_nok (error, NULL);
2654 return remote_class->xdomain_vtable;
2656 if (remote_class->default_vtable == NULL) {
2657 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2658 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2660 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2661 MonoClass *klass = mono_class_from_mono_type (type);
2662 #ifndef DISABLE_COM
2663 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2664 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2665 else
2666 #endif
2667 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2668 /* N.B. both branches of the if modify error */
2669 if (!is_ok (error)) {
2670 mono_domain_unlock (domain);
2671 mono_loader_unlock ();
2672 return NULL;
2676 mono_domain_unlock (domain);
2677 mono_loader_unlock ();
2678 return remote_class->default_vtable;
2682 * mono_upgrade_remote_class:
2683 * @domain: the application domain
2684 * @tproxy: the proxy whose remote class has to be upgraded.
2685 * @klass: class to which the remote class can be casted.
2686 * @error: set on error
2688 * Updates the vtable of the remote class by adding the necessary method slots
2689 * and interface offsets so it can be safely casted to klass. klass can be a
2690 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2692 gboolean
2693 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2695 MONO_REQ_GC_UNSAFE_MODE;
2697 mono_error_init (error);
2699 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2700 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2702 gboolean redo_vtable;
2703 if (mono_class_is_interface (klass)) {
2704 int i;
2705 redo_vtable = TRUE;
2706 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2707 if (remote_class->interfaces [i] == klass)
2708 redo_vtable = FALSE;
2710 else {
2711 redo_vtable = (remote_class->proxy_class != klass);
2714 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2715 mono_domain_lock (domain);
2716 if (redo_vtable) {
2717 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2718 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2719 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2720 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2721 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2722 if (!is_ok (error))
2723 goto leave;
2726 leave:
2727 mono_domain_unlock (domain);
2728 mono_loader_unlock ();
2729 return is_ok (error);
2731 #endif /* DISABLE_REMOTING */
2735 * mono_object_get_virtual_method:
2736 * @obj: object to operate on.
2737 * @method: method
2739 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2740 * the instance of a callvirt of method.
2742 MonoMethod*
2743 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2745 MONO_REQ_GC_UNSAFE_MODE;
2746 HANDLE_FUNCTION_ENTER ();
2747 MonoError error;
2748 MONO_HANDLE_DCL (MonoObject, obj);
2749 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2750 mono_error_assert_ok (&error);
2751 HANDLE_FUNCTION_RETURN_VAL (result);
2755 * mono_object_get_virtual_method:
2756 * @obj: object to operate on.
2757 * @method: method
2759 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2760 * the instance of a callvirt of method.
2762 MonoMethod*
2763 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2765 mono_error_init (error);
2767 gboolean is_proxy = FALSE;
2768 MonoClass *klass = mono_handle_class (obj);
2769 if (mono_class_is_transparent_proxy (klass)) {
2770 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2771 klass = remote_class->proxy_class;
2772 is_proxy = TRUE;
2774 return class_get_virtual_method (klass, method, is_proxy, error);
2777 static MonoMethod*
2778 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2780 mono_error_init (error);
2783 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2784 return method;
2786 mono_class_setup_vtable (klass);
2787 MonoMethod **vtable = klass->vtable;
2789 if (method->slot == -1) {
2790 /* method->slot might not be set for instances of generic methods */
2791 if (method->is_inflated) {
2792 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2793 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2794 } else {
2795 if (!is_proxy)
2796 g_assert_not_reached ();
2800 MonoMethod *res = NULL;
2801 /* check method->slot is a valid index: perform isinstance? */
2802 if (method->slot != -1) {
2803 if (mono_class_is_interface (method->klass)) {
2804 if (!is_proxy) {
2805 gboolean variance_used = FALSE;
2806 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2807 g_assert (iface_offset > 0);
2808 res = vtable [iface_offset + method->slot];
2810 } else {
2811 res = vtable [method->slot];
2815 #ifndef DISABLE_REMOTING
2816 if (is_proxy) {
2817 /* It may be an interface, abstract class method or generic method */
2818 if (!res || mono_method_signature (res)->generic_param_count)
2819 res = method;
2821 /* generic methods demand invoke_with_check */
2822 if (mono_method_signature (res)->generic_param_count)
2823 res = mono_marshal_get_remoting_invoke_with_check (res);
2824 else {
2825 #ifndef DISABLE_COM
2826 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2827 res = mono_cominterop_get_invoke (res);
2828 else
2829 #endif
2830 res = mono_marshal_get_remoting_invoke (res);
2832 } else
2833 #endif
2835 if (method->is_inflated) {
2836 /* Have to inflate the result */
2837 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2841 return res;
2844 static MonoObject*
2845 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2847 MONO_REQ_GC_UNSAFE_MODE;
2849 MonoObject *result = NULL;
2851 g_assert (callbacks.runtime_invoke);
2853 mono_error_init (error);
2855 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2856 mono_profiler_method_start_invoke (method);
2858 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2860 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2861 mono_profiler_method_end_invoke (method);
2863 if (!mono_error_ok (error))
2864 return NULL;
2866 return result;
2870 * mono_runtime_invoke:
2871 * @method: method to invoke
2872 * @obJ: object instance
2873 * @params: arguments to the method
2874 * @exc: exception information.
2876 * Invokes the method represented by @method on the object @obj.
2878 * obj is the 'this' pointer, it should be NULL for static
2879 * methods, a MonoObject* for object instances and a pointer to
2880 * the value type for value types.
2882 * The params array contains the arguments to the method with the
2883 * same convention: MonoObject* pointers for object instances and
2884 * pointers to the value type otherwise.
2886 * From unmanaged code you'll usually use the
2887 * mono_runtime_invoke() variant.
2889 * Note that this function doesn't handle virtual methods for
2890 * you, it will exec the exact method you pass: we still need to
2891 * expose a function to lookup the derived class implementation
2892 * of a virtual method (there are examples of this in the code,
2893 * though).
2895 * You can pass NULL as the exc argument if you don't want to
2896 * catch exceptions, otherwise, *exc will be set to the exception
2897 * thrown, if any. if an exception is thrown, you can't use the
2898 * MonoObject* result from the function.
2900 * If the method returns a value type, it is boxed in an object
2901 * reference.
2903 MonoObject*
2904 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2906 MonoError error;
2907 MonoObject *res;
2908 if (exc) {
2909 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2910 if (*exc == NULL && !mono_error_ok(&error)) {
2911 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2912 } else
2913 mono_error_cleanup (&error);
2914 } else {
2915 res = mono_runtime_invoke_checked (method, obj, params, &error);
2916 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2918 return res;
2922 * mono_runtime_try_invoke:
2923 * @method: method to invoke
2924 * @obJ: object instance
2925 * @params: arguments to the method
2926 * @exc: exception information.
2927 * @error: set on error
2929 * Invokes the method represented by @method on the object @obj.
2931 * obj is the 'this' pointer, it should be NULL for static
2932 * methods, a MonoObject* for object instances and a pointer to
2933 * the value type for value types.
2935 * The params array contains the arguments to the method with the
2936 * same convention: MonoObject* pointers for object instances and
2937 * pointers to the value type otherwise.
2939 * From unmanaged code you'll usually use the
2940 * mono_runtime_invoke() variant.
2942 * Note that this function doesn't handle virtual methods for
2943 * you, it will exec the exact method you pass: we still need to
2944 * expose a function to lookup the derived class implementation
2945 * of a virtual method (there are examples of this in the code,
2946 * though).
2948 * For this function, you must not pass NULL as the exc argument if
2949 * you don't want to catch exceptions, use
2950 * mono_runtime_invoke_checked(). If an exception is thrown, you
2951 * can't use the MonoObject* result from the function.
2953 * If this method cannot be invoked, @error will be set and @exc and
2954 * the return value must not be used.
2956 * If the method returns a value type, it is boxed in an object
2957 * reference.
2959 MonoObject*
2960 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2962 MONO_REQ_GC_UNSAFE_MODE;
2964 g_assert (exc != NULL);
2966 if (mono_runtime_get_no_exec ())
2967 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2969 return do_runtime_invoke (method, obj, params, exc, error);
2973 * mono_runtime_invoke_checked:
2974 * @method: method to invoke
2975 * @obJ: object instance
2976 * @params: arguments to the method
2977 * @error: set on error
2979 * Invokes the method represented by @method on the object @obj.
2981 * obj is the 'this' pointer, it should be NULL for static
2982 * methods, a MonoObject* for object instances and a pointer to
2983 * the value type for value types.
2985 * The params array contains the arguments to the method with the
2986 * same convention: MonoObject* pointers for object instances and
2987 * pointers to the value type otherwise.
2989 * From unmanaged code you'll usually use the
2990 * mono_runtime_invoke() variant.
2992 * Note that this function doesn't handle virtual methods for
2993 * you, it will exec the exact method you pass: we still need to
2994 * expose a function to lookup the derived class implementation
2995 * of a virtual method (there are examples of this in the code,
2996 * though).
2998 * If an exception is thrown, you can't use the MonoObject* result
2999 * from the function.
3001 * If this method cannot be invoked, @error will be set. If the
3002 * method throws an exception (and we're in coop mode) the exception
3003 * will be set in @error.
3005 * If the method returns a value type, it is boxed in an object
3006 * reference.
3008 MonoObject*
3009 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3011 MONO_REQ_GC_UNSAFE_MODE;
3013 if (mono_runtime_get_no_exec ())
3014 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3016 return do_runtime_invoke (method, obj, params, NULL, error);
3020 * mono_method_get_unmanaged_thunk:
3021 * @method: method to generate a thunk for.
3023 * Returns an unmanaged->managed thunk that can be used to call
3024 * a managed method directly from C.
3026 * The thunk's C signature closely matches the managed signature:
3028 * C#: public bool Equals (object obj);
3029 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3030 * MonoObject*, MonoException**);
3032 * The 1st ("this") parameter must not be used with static methods:
3034 * C#: public static bool ReferenceEquals (object a, object b);
3035 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3036 * MonoException**);
3038 * The last argument must be a non-null pointer of a MonoException* pointer.
3039 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3040 * exception has been thrown in managed code. Otherwise it will point
3041 * to the MonoException* caught by the thunk. In this case, the result of
3042 * the thunk is undefined:
3044 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3045 * MonoException *ex = NULL;
3046 * Equals func = mono_method_get_unmanaged_thunk (method);
3047 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3048 * if (ex) {
3049 * // handle exception
3052 * The calling convention of the thunk matches the platform's default
3053 * convention. This means that under Windows, C declarations must
3054 * contain the __stdcall attribute:
3056 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3057 * MonoObject*, MonoException**);
3059 * LIMITATIONS
3061 * Value type arguments and return values are treated as they were objects:
3063 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3064 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3066 * Arguments must be properly boxed upon trunk's invocation, while return
3067 * values must be unboxed.
3069 gpointer
3070 mono_method_get_unmanaged_thunk (MonoMethod *method)
3072 MONO_REQ_GC_NEUTRAL_MODE;
3073 MONO_REQ_API_ENTRYPOINT;
3075 MonoError error;
3076 gpointer res;
3078 g_assert (!mono_threads_is_coop_enabled ());
3080 MONO_ENTER_GC_UNSAFE;
3081 method = mono_marshal_get_thunk_invoke_wrapper (method);
3082 res = mono_compile_method_checked (method, &error);
3083 mono_error_cleanup (&error);
3084 MONO_EXIT_GC_UNSAFE;
3086 return res;
3089 void
3090 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3092 MONO_REQ_GC_UNSAFE_MODE;
3094 int t;
3095 if (type->byref) {
3096 /* object fields cannot be byref, so we don't need a
3097 wbarrier here */
3098 gpointer *p = (gpointer*)dest;
3099 *p = value;
3100 return;
3102 t = type->type;
3103 handle_enum:
3104 switch (t) {
3105 case MONO_TYPE_BOOLEAN:
3106 case MONO_TYPE_I1:
3107 case MONO_TYPE_U1: {
3108 guint8 *p = (guint8*)dest;
3109 *p = value ? *(guint8*)value : 0;
3110 return;
3112 case MONO_TYPE_I2:
3113 case MONO_TYPE_U2:
3114 case MONO_TYPE_CHAR: {
3115 guint16 *p = (guint16*)dest;
3116 *p = value ? *(guint16*)value : 0;
3117 return;
3119 #if SIZEOF_VOID_P == 4
3120 case MONO_TYPE_I:
3121 case MONO_TYPE_U:
3122 #endif
3123 case MONO_TYPE_I4:
3124 case MONO_TYPE_U4: {
3125 gint32 *p = (gint32*)dest;
3126 *p = value ? *(gint32*)value : 0;
3127 return;
3129 #if SIZEOF_VOID_P == 8
3130 case MONO_TYPE_I:
3131 case MONO_TYPE_U:
3132 #endif
3133 case MONO_TYPE_I8:
3134 case MONO_TYPE_U8: {
3135 gint64 *p = (gint64*)dest;
3136 *p = value ? *(gint64*)value : 0;
3137 return;
3139 case MONO_TYPE_R4: {
3140 float *p = (float*)dest;
3141 *p = value ? *(float*)value : 0;
3142 return;
3144 case MONO_TYPE_R8: {
3145 double *p = (double*)dest;
3146 *p = value ? *(double*)value : 0;
3147 return;
3149 case MONO_TYPE_STRING:
3150 case MONO_TYPE_SZARRAY:
3151 case MONO_TYPE_CLASS:
3152 case MONO_TYPE_OBJECT:
3153 case MONO_TYPE_ARRAY:
3154 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3155 return;
3156 case MONO_TYPE_FNPTR:
3157 case MONO_TYPE_PTR: {
3158 gpointer *p = (gpointer*)dest;
3159 *p = deref_pointer? *(gpointer*)value: value;
3160 return;
3162 case MONO_TYPE_VALUETYPE:
3163 /* note that 't' and 'type->type' can be different */
3164 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3165 t = mono_class_enum_basetype (type->data.klass)->type;
3166 goto handle_enum;
3167 } else {
3168 MonoClass *klass = mono_class_from_mono_type (type);
3169 int size = mono_class_value_size (klass, NULL);
3170 if (value == NULL)
3171 mono_gc_bzero_atomic (dest, size);
3172 else
3173 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3175 return;
3176 case MONO_TYPE_GENERICINST:
3177 t = type->data.generic_class->container_class->byval_arg.type;
3178 goto handle_enum;
3179 default:
3180 g_error ("got type %x", type->type);
3185 * mono_field_set_value:
3186 * @obj: Instance object
3187 * @field: MonoClassField describing the field to set
3188 * @value: The value to be set
3190 * Sets the value of the field described by @field in the object instance @obj
3191 * to the value passed in @value. This method should only be used for instance
3192 * fields. For static fields, use mono_field_static_set_value.
3194 * The value must be on the native format of the field type.
3196 void
3197 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3199 MONO_REQ_GC_UNSAFE_MODE;
3201 void *dest;
3203 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3205 dest = (char*)obj + field->offset;
3206 mono_copy_value (field->type, dest, value, FALSE);
3210 * mono_field_static_set_value:
3211 * @field: MonoClassField describing the field to set
3212 * @value: The value to be set
3214 * Sets the value of the static field described by @field
3215 * to the value passed in @value.
3217 * The value must be on the native format of the field type.
3219 void
3220 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3222 MONO_REQ_GC_UNSAFE_MODE;
3224 void *dest;
3226 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3227 /* you cant set a constant! */
3228 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3230 if (field->offset == -1) {
3231 /* Special static */
3232 gpointer addr;
3234 mono_domain_lock (vt->domain);
3235 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3236 mono_domain_unlock (vt->domain);
3237 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3238 } else {
3239 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3241 mono_copy_value (field->type, dest, value, FALSE);
3245 * mono_vtable_get_static_field_data:
3247 * Internal use function: return a pointer to the memory holding the static fields
3248 * for a class or NULL if there are no static fields.
3249 * This is exported only for use by the debugger.
3251 void *
3252 mono_vtable_get_static_field_data (MonoVTable *vt)
3254 MONO_REQ_GC_NEUTRAL_MODE
3256 if (!vt->has_static_fields)
3257 return NULL;
3258 return vt->vtable [vt->klass->vtable_size];
3261 static guint8*
3262 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3264 MONO_REQ_GC_UNSAFE_MODE;
3266 guint8 *src;
3268 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3269 if (field->offset == -1) {
3270 /* Special static */
3271 gpointer addr;
3273 mono_domain_lock (vt->domain);
3274 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3275 mono_domain_unlock (vt->domain);
3276 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3277 } else {
3278 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3280 } else {
3281 src = (guint8*)obj + field->offset;
3284 return src;
3288 * mono_field_get_value:
3289 * @obj: Object instance
3290 * @field: MonoClassField describing the field to fetch information from
3291 * @value: pointer to the location where the value will be stored
3293 * Use this routine to get the value of the field @field in the object
3294 * passed.
3296 * The pointer provided by value must be of the field type, for reference
3297 * types this is a MonoObject*, for value types its the actual pointer to
3298 * the value type.
3300 * For example:
3301 * int i;
3302 * mono_field_get_value (obj, int_field, &i);
3304 void
3305 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3307 MONO_REQ_GC_UNSAFE_MODE;
3309 void *src;
3311 g_assert (obj);
3313 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3315 src = (char*)obj + field->offset;
3316 mono_copy_value (field->type, value, src, TRUE);
3320 * mono_field_get_value_object:
3321 * @domain: domain where the object will be created (if boxing)
3322 * @field: MonoClassField describing the field to fetch information from
3323 * @obj: The object instance for the field.
3325 * Returns: a new MonoObject with the value from the given field. If the
3326 * field represents a value type, the value is boxed.
3329 MonoObject *
3330 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3332 MonoError error;
3333 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3334 mono_error_assert_ok (&error);
3335 return result;
3339 * mono_field_get_value_object_checked:
3340 * @domain: domain where the object will be created (if boxing)
3341 * @field: MonoClassField describing the field to fetch information from
3342 * @obj: The object instance for the field.
3343 * @error: Set on error.
3345 * Returns: a new MonoObject with the value from the given field. If the
3346 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3349 MonoObject *
3350 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3352 MONO_REQ_GC_UNSAFE_MODE;
3354 mono_error_init (error);
3356 MonoObject *o;
3357 MonoClass *klass;
3358 MonoVTable *vtable = NULL;
3359 gchar *v;
3360 gboolean is_static = FALSE;
3361 gboolean is_ref = FALSE;
3362 gboolean is_literal = FALSE;
3363 gboolean is_ptr = FALSE;
3364 MonoType *type = mono_field_get_type_checked (field, error);
3366 return_val_if_nok (error, NULL);
3368 switch (type->type) {
3369 case MONO_TYPE_STRING:
3370 case MONO_TYPE_OBJECT:
3371 case MONO_TYPE_CLASS:
3372 case MONO_TYPE_ARRAY:
3373 case MONO_TYPE_SZARRAY:
3374 is_ref = TRUE;
3375 break;
3376 case MONO_TYPE_U1:
3377 case MONO_TYPE_I1:
3378 case MONO_TYPE_BOOLEAN:
3379 case MONO_TYPE_U2:
3380 case MONO_TYPE_I2:
3381 case MONO_TYPE_CHAR:
3382 case MONO_TYPE_U:
3383 case MONO_TYPE_I:
3384 case MONO_TYPE_U4:
3385 case MONO_TYPE_I4:
3386 case MONO_TYPE_R4:
3387 case MONO_TYPE_U8:
3388 case MONO_TYPE_I8:
3389 case MONO_TYPE_R8:
3390 case MONO_TYPE_VALUETYPE:
3391 is_ref = type->byref;
3392 break;
3393 case MONO_TYPE_GENERICINST:
3394 is_ref = !mono_type_generic_inst_is_valuetype (type);
3395 break;
3396 case MONO_TYPE_PTR:
3397 is_ptr = TRUE;
3398 break;
3399 default:
3400 g_error ("type 0x%x not handled in "
3401 "mono_field_get_value_object", type->type);
3402 return NULL;
3405 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3406 is_literal = TRUE;
3408 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3409 is_static = TRUE;
3411 if (!is_literal) {
3412 vtable = mono_class_vtable_full (domain, field->parent, error);
3413 return_val_if_nok (error, NULL);
3415 if (!vtable->initialized) {
3416 mono_runtime_class_init_full (vtable, error);
3417 return_val_if_nok (error, NULL);
3420 } else {
3421 g_assert (obj);
3424 if (is_ref) {
3425 if (is_literal) {
3426 get_default_field_value (domain, field, &o, error);
3427 return_val_if_nok (error, NULL);
3428 } else if (is_static) {
3429 mono_field_static_get_value_checked (vtable, field, &o, error);
3430 return_val_if_nok (error, NULL);
3431 } else {
3432 mono_field_get_value (obj, field, &o);
3434 return o;
3437 if (is_ptr) {
3438 static MonoMethod *m;
3439 gpointer args [2];
3440 gpointer *ptr;
3441 gpointer v;
3443 if (!m) {
3444 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3445 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3446 g_assert (m);
3449 v = &ptr;
3450 if (is_literal) {
3451 get_default_field_value (domain, field, v, error);
3452 return_val_if_nok (error, NULL);
3453 } else if (is_static) {
3454 mono_field_static_get_value_checked (vtable, field, v, error);
3455 return_val_if_nok (error, NULL);
3456 } else {
3457 mono_field_get_value (obj, field, v);
3460 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3461 args [0] = ptr ? *ptr : NULL;
3462 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3463 return_val_if_nok (error, NULL);
3465 o = mono_runtime_invoke_checked (m, NULL, args, error);
3466 return_val_if_nok (error, NULL);
3468 return o;
3471 /* boxed value type */
3472 klass = mono_class_from_mono_type (type);
3474 if (mono_class_is_nullable (klass))
3475 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3477 o = mono_object_new_checked (domain, klass, error);
3478 return_val_if_nok (error, NULL);
3479 v = ((gchar *) o) + sizeof (MonoObject);
3481 if (is_literal) {
3482 get_default_field_value (domain, field, v, error);
3483 return_val_if_nok (error, NULL);
3484 } else if (is_static) {
3485 mono_field_static_get_value_checked (vtable, field, v, error);
3486 return_val_if_nok (error, NULL);
3487 } else {
3488 mono_field_get_value (obj, field, v);
3491 return o;
3495 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3497 MONO_REQ_GC_UNSAFE_MODE;
3499 mono_error_init (error);
3500 int retval = 0;
3501 const char *p = blob;
3502 mono_metadata_decode_blob_size (p, &p);
3504 switch (type) {
3505 case MONO_TYPE_BOOLEAN:
3506 case MONO_TYPE_U1:
3507 case MONO_TYPE_I1:
3508 *(guint8 *) value = *p;
3509 break;
3510 case MONO_TYPE_CHAR:
3511 case MONO_TYPE_U2:
3512 case MONO_TYPE_I2:
3513 *(guint16*) value = read16 (p);
3514 break;
3515 case MONO_TYPE_U4:
3516 case MONO_TYPE_I4:
3517 *(guint32*) value = read32 (p);
3518 break;
3519 case MONO_TYPE_U8:
3520 case MONO_TYPE_I8:
3521 *(guint64*) value = read64 (p);
3522 break;
3523 case MONO_TYPE_R4:
3524 readr4 (p, (float*) value);
3525 break;
3526 case MONO_TYPE_R8:
3527 readr8 (p, (double*) value);
3528 break;
3529 case MONO_TYPE_STRING:
3530 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3531 break;
3532 case MONO_TYPE_CLASS:
3533 *(gpointer*) value = NULL;
3534 break;
3535 default:
3536 retval = -1;
3537 g_warning ("type 0x%02x should not be in constant table", type);
3539 return retval;
3542 static void
3543 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3545 MONO_REQ_GC_NEUTRAL_MODE;
3547 MonoTypeEnum def_type;
3548 const char* data;
3550 mono_error_init (error);
3552 data = mono_class_get_field_default_value (field, &def_type);
3553 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3556 void
3557 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3559 MONO_REQ_GC_UNSAFE_MODE;
3561 void *src;
3563 mono_error_init (error);
3565 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3567 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3568 get_default_field_value (vt->domain, field, value, error);
3569 return;
3572 if (field->offset == -1) {
3573 /* Special static */
3574 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3575 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3576 } else {
3577 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3579 mono_copy_value (field->type, value, src, TRUE);
3583 * mono_field_static_get_value:
3584 * @vt: vtable to the object
3585 * @field: MonoClassField describing the field to fetch information from
3586 * @value: where the value is returned
3588 * Use this routine to get the value of the static field @field value.
3590 * The pointer provided by value must be of the field type, for reference
3591 * types this is a MonoObject*, for value types its the actual pointer to
3592 * the value type.
3594 * For example:
3595 * int i;
3596 * mono_field_static_get_value (vt, int_field, &i);
3598 void
3599 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3601 MONO_REQ_GC_NEUTRAL_MODE;
3603 MonoError error;
3604 mono_field_static_get_value_checked (vt, field, value, &error);
3605 mono_error_cleanup (&error);
3609 * mono_field_static_get_value_checked:
3610 * @vt: vtable to the object
3611 * @field: MonoClassField describing the field to fetch information from
3612 * @value: where the value is returned
3613 * @error: set on error
3615 * Use this routine to get the value of the static field @field value.
3617 * The pointer provided by value must be of the field type, for reference
3618 * types this is a MonoObject*, for value types its the actual pointer to
3619 * the value type.
3621 * For example:
3622 * int i;
3623 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3624 * if (!is_ok (error)) { ... }
3626 * On failure sets @error.
3628 void
3629 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3631 MONO_REQ_GC_NEUTRAL_MODE;
3633 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3637 * mono_property_set_value:
3638 * @prop: MonoProperty to set
3639 * @obj: instance object on which to act
3640 * @params: parameters to pass to the propery
3641 * @exc: optional exception
3643 * Invokes the property's set method with the given arguments on the
3644 * object instance obj (or NULL for static properties).
3646 * You can pass NULL as the exc argument if you don't want to
3647 * catch exceptions, otherwise, *exc will be set to the exception
3648 * thrown, if any. if an exception is thrown, you can't use the
3649 * MonoObject* result from the function.
3651 void
3652 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3654 MONO_REQ_GC_UNSAFE_MODE;
3656 MonoError error;
3657 do_runtime_invoke (prop->set, obj, params, exc, &error);
3658 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3659 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3660 } else {
3661 mono_error_cleanup (&error);
3666 * mono_property_set_value_checked:
3667 * @prop: MonoProperty to set
3668 * @obj: instance object on which to act
3669 * @params: parameters to pass to the propery
3670 * @error: set on error
3672 * Invokes the property's set method with the given arguments on the
3673 * object instance obj (or NULL for static properties).
3675 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3676 * If an exception is thrown, it will be caught and returned via @error.
3678 gboolean
3679 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3681 MONO_REQ_GC_UNSAFE_MODE;
3683 MonoObject *exc;
3685 mono_error_init (error);
3686 do_runtime_invoke (prop->set, obj, params, &exc, error);
3687 if (exc != NULL && is_ok (error))
3688 mono_error_set_exception_instance (error, (MonoException*)exc);
3689 return is_ok (error);
3693 * mono_property_get_value:
3694 * @prop: MonoProperty to fetch
3695 * @obj: instance object on which to act
3696 * @params: parameters to pass to the propery
3697 * @exc: optional exception
3699 * Invokes the property's get method with the given arguments on the
3700 * object instance obj (or NULL for static properties).
3702 * You can pass NULL as the exc argument if you don't want to
3703 * catch exceptions, otherwise, *exc will be set to the exception
3704 * thrown, if any. if an exception is thrown, you can't use the
3705 * MonoObject* result from the function.
3707 * Returns: the value from invoking the get method on the property.
3709 MonoObject*
3710 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3712 MONO_REQ_GC_UNSAFE_MODE;
3714 MonoError error;
3715 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3716 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3717 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3718 } else {
3719 mono_error_cleanup (&error); /* FIXME don't raise here */
3722 return val;
3726 * mono_property_get_value_checked:
3727 * @prop: MonoProperty to fetch
3728 * @obj: instance object on which to act
3729 * @params: parameters to pass to the propery
3730 * @error: set on error
3732 * Invokes the property's get method with the given arguments on the
3733 * object instance obj (or NULL for static properties).
3735 * If an exception is thrown, you can't use the
3736 * MonoObject* result from the function. The exception will be propagated via @error.
3738 * Returns: the value from invoking the get method on the property. On
3739 * failure returns NULL and sets @error.
3741 MonoObject*
3742 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3744 MONO_REQ_GC_UNSAFE_MODE;
3746 MonoObject *exc;
3747 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3748 if (exc != NULL && !is_ok (error))
3749 mono_error_set_exception_instance (error, (MonoException*) exc);
3750 if (!is_ok (error))
3751 val = NULL;
3752 return val;
3757 * mono_nullable_init:
3758 * @buf: The nullable structure to initialize.
3759 * @value: the value to initialize from
3760 * @klass: the type for the object
3762 * Initialize the nullable structure pointed to by @buf from @value which
3763 * should be a boxed value type. The size of @buf should be able to hold
3764 * as much data as the @klass->instance_size (which is the number of bytes
3765 * that will be copies).
3767 * Since Nullables have variable structure, we can not define a C
3768 * structure for them.
3770 void
3771 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3773 MONO_REQ_GC_UNSAFE_MODE;
3775 MonoClass *param_class = klass->cast_class;
3777 mono_class_setup_fields (klass);
3778 g_assert (klass->fields_inited);
3780 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3781 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3783 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3784 if (value) {
3785 if (param_class->has_references)
3786 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3787 else
3788 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3789 } else {
3790 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3795 * mono_nullable_box:
3796 * @buf: The buffer representing the data to be boxed
3797 * @klass: the type to box it as.
3798 * @error: set on oerr
3800 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3801 * @buf. On failure returns NULL and sets @error
3803 MonoObject*
3804 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3806 MONO_REQ_GC_UNSAFE_MODE;
3808 mono_error_init (error);
3809 MonoClass *param_class = klass->cast_class;
3811 mono_class_setup_fields (klass);
3812 g_assert (klass->fields_inited);
3814 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3815 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3817 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3818 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3819 return_val_if_nok (error, NULL);
3820 if (param_class->has_references)
3821 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3822 else
3823 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3824 return o;
3826 else
3827 return NULL;
3831 * mono_get_delegate_invoke:
3832 * @klass: The delegate class
3834 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3836 MonoMethod *
3837 mono_get_delegate_invoke (MonoClass *klass)
3839 MONO_REQ_GC_NEUTRAL_MODE;
3841 MonoMethod *im;
3843 /* This is called at runtime, so avoid the slower search in metadata */
3844 mono_class_setup_methods (klass);
3845 if (mono_class_has_failure (klass))
3846 return NULL;
3847 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3848 return im;
3852 * mono_get_delegate_begin_invoke:
3853 * @klass: The delegate class
3855 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3857 MonoMethod *
3858 mono_get_delegate_begin_invoke (MonoClass *klass)
3860 MONO_REQ_GC_NEUTRAL_MODE;
3862 MonoMethod *im;
3864 /* This is called at runtime, so avoid the slower search in metadata */
3865 mono_class_setup_methods (klass);
3866 if (mono_class_has_failure (klass))
3867 return NULL;
3868 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3869 return im;
3873 * mono_get_delegate_end_invoke:
3874 * @klass: The delegate class
3876 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3878 MonoMethod *
3879 mono_get_delegate_end_invoke (MonoClass *klass)
3881 MONO_REQ_GC_NEUTRAL_MODE;
3883 MonoMethod *im;
3885 /* This is called at runtime, so avoid the slower search in metadata */
3886 mono_class_setup_methods (klass);
3887 if (mono_class_has_failure (klass))
3888 return NULL;
3889 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3890 return im;
3894 * mono_runtime_delegate_invoke:
3895 * @delegate: pointer to a delegate object.
3896 * @params: parameters for the delegate.
3897 * @exc: Pointer to the exception result.
3899 * Invokes the delegate method @delegate with the parameters provided.
3901 * You can pass NULL as the exc argument if you don't want to
3902 * catch exceptions, otherwise, *exc will be set to the exception
3903 * thrown, if any. if an exception is thrown, you can't use the
3904 * MonoObject* result from the function.
3906 MonoObject*
3907 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3909 MONO_REQ_GC_UNSAFE_MODE;
3911 MonoError error;
3912 if (exc) {
3913 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3914 if (*exc) {
3915 mono_error_cleanup (&error);
3916 return NULL;
3917 } else {
3918 if (!is_ok (&error))
3919 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3920 return result;
3922 } else {
3923 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3924 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3925 return result;
3930 * mono_runtime_delegate_try_invoke:
3931 * @delegate: pointer to a delegate object.
3932 * @params: parameters for the delegate.
3933 * @exc: Pointer to the exception result.
3934 * @error: set on error
3936 * Invokes the delegate method @delegate with the parameters provided.
3938 * You can pass NULL as the exc argument if you don't want to
3939 * catch exceptions, otherwise, *exc will be set to the exception
3940 * thrown, if any. On failure to execute, @error will be set.
3941 * if an exception is thrown, you can't use the
3942 * MonoObject* result from the function.
3944 MonoObject*
3945 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3947 MONO_REQ_GC_UNSAFE_MODE;
3949 mono_error_init (error);
3950 MonoMethod *im;
3951 MonoClass *klass = delegate->vtable->klass;
3952 MonoObject *o;
3954 im = mono_get_delegate_invoke (klass);
3955 if (!im)
3956 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3958 if (exc) {
3959 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3960 } else {
3961 o = mono_runtime_invoke_checked (im, delegate, params, error);
3964 return o;
3968 * mono_runtime_delegate_invoke_checked:
3969 * @delegate: pointer to a delegate object.
3970 * @params: parameters for the delegate.
3971 * @error: set on error
3973 * Invokes the delegate method @delegate with the parameters provided.
3975 * On failure @error will be set and you can't use the MonoObject*
3976 * result from the function.
3978 MonoObject*
3979 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3981 mono_error_init (error);
3982 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3985 static char **main_args = NULL;
3986 static int num_main_args = 0;
3989 * mono_runtime_get_main_args:
3991 * Returns: a MonoArray with the arguments passed to the main program
3993 MonoArray*
3994 mono_runtime_get_main_args (void)
3996 MONO_REQ_GC_UNSAFE_MODE;
3997 MonoError error;
3998 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3999 mono_error_assert_ok (&error);
4000 return result;
4004 * mono_runtime_get_main_args:
4005 * @error: set on error
4007 * Returns: a MonoArray with the arguments passed to the main
4008 * program. On failure returns NULL and sets @error.
4010 MonoArray*
4011 mono_runtime_get_main_args_checked (MonoError *error)
4013 MonoArray *res;
4014 int i;
4015 MonoDomain *domain = mono_domain_get ();
4017 mono_error_init (error);
4019 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4020 return_val_if_nok (error, NULL);
4022 for (i = 0; i < num_main_args; ++i)
4023 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4025 return res;
4028 static void
4029 free_main_args (void)
4031 MONO_REQ_GC_NEUTRAL_MODE;
4033 int i;
4035 for (i = 0; i < num_main_args; ++i)
4036 g_free (main_args [i]);
4037 g_free (main_args);
4038 num_main_args = 0;
4039 main_args = NULL;
4043 * mono_runtime_set_main_args:
4044 * @argc: number of arguments from the command line
4045 * @argv: array of strings from the command line
4047 * Set the command line arguments from an embedding application that doesn't otherwise call
4048 * mono_runtime_run_main ().
4051 mono_runtime_set_main_args (int argc, char* argv[])
4053 MONO_REQ_GC_NEUTRAL_MODE;
4055 int i;
4057 free_main_args ();
4058 main_args = g_new0 (char*, argc);
4059 num_main_args = argc;
4061 for (i = 0; i < argc; ++i) {
4062 gchar *utf8_arg;
4064 utf8_arg = mono_utf8_from_external (argv[i]);
4065 if (utf8_arg == NULL) {
4066 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4067 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4068 exit (-1);
4071 main_args [i] = utf8_arg;
4074 return 0;
4078 * Prepare an array of arguments in order to execute a standard Main()
4079 * method (argc/argv contains the executable name). This method also
4080 * sets the command line argument value needed by System.Environment.
4083 static MonoArray*
4084 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4086 MONO_REQ_GC_UNSAFE_MODE;
4088 MonoError error;
4089 int i;
4090 MonoArray *args = NULL;
4091 MonoDomain *domain = mono_domain_get ();
4092 gchar *utf8_fullpath;
4093 MonoMethodSignature *sig;
4095 g_assert (method != NULL);
4097 mono_thread_set_main (mono_thread_current ());
4099 main_args = g_new0 (char*, argc);
4100 num_main_args = argc;
4102 if (!g_path_is_absolute (argv [0])) {
4103 gchar *basename = g_path_get_basename (argv [0]);
4104 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4105 basename,
4106 NULL);
4108 utf8_fullpath = mono_utf8_from_external (fullpath);
4109 if(utf8_fullpath == NULL) {
4110 /* Printing the arg text will cause glib to
4111 * whinge about "Invalid UTF-8", but at least
4112 * its relevant, and shows the problem text
4113 * string.
4115 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4116 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4117 exit (-1);
4120 g_free (fullpath);
4121 g_free (basename);
4122 } else {
4123 utf8_fullpath = mono_utf8_from_external (argv[0]);
4124 if(utf8_fullpath == NULL) {
4125 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4126 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4127 exit (-1);
4131 main_args [0] = utf8_fullpath;
4133 for (i = 1; i < argc; ++i) {
4134 gchar *utf8_arg;
4136 utf8_arg=mono_utf8_from_external (argv[i]);
4137 if(utf8_arg==NULL) {
4138 /* Ditto the comment about Invalid UTF-8 here */
4139 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4140 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4141 exit (-1);
4144 main_args [i] = utf8_arg;
4146 argc--;
4147 argv++;
4149 sig = mono_method_signature (method);
4150 if (!sig) {
4151 g_print ("Unable to load Main method.\n");
4152 exit (-1);
4155 if (sig->param_count) {
4156 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4157 mono_error_assert_ok (&error);
4158 for (i = 0; i < argc; ++i) {
4159 /* The encodings should all work, given that
4160 * we've checked all these args for the
4161 * main_args array.
4163 gchar *str = mono_utf8_from_external (argv [i]);
4164 MonoString *arg = mono_string_new (domain, str);
4165 mono_array_setref (args, i, arg);
4166 g_free (str);
4168 } else {
4169 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4170 mono_error_assert_ok (&error);
4173 mono_assembly_set_main (method->klass->image->assembly);
4175 return args;
4179 * mono_runtime_run_main:
4180 * @method: the method to start the application with (usually Main)
4181 * @argc: number of arguments from the command line
4182 * @argv: array of strings from the command line
4183 * @exc: excetption results
4185 * Execute a standard Main() method (argc/argv contains the
4186 * executable name). This method also sets the command line argument value
4187 * needed by System.Environment.
4192 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4193 MonoObject **exc)
4195 MONO_REQ_GC_UNSAFE_MODE;
4197 MonoError error;
4198 MonoArray *args = prepare_run_main (method, argc, argv);
4199 int res;
4200 if (exc) {
4201 res = mono_runtime_try_exec_main (method, args, exc);
4202 } else {
4203 res = mono_runtime_exec_main_checked (method, args, &error);
4204 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4206 return res;
4210 * mono_runtime_run_main_checked:
4211 * @method: the method to start the application with (usually Main)
4212 * @argc: number of arguments from the command line
4213 * @argv: array of strings from the command line
4214 * @error: set on error
4216 * Execute a standard Main() method (argc/argv contains the
4217 * executable name). This method also sets the command line argument value
4218 * needed by System.Environment. On failure sets @error.
4223 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4224 MonoError *error)
4226 mono_error_init (error);
4227 MonoArray *args = prepare_run_main (method, argc, argv);
4228 return mono_runtime_exec_main_checked (method, args, error);
4232 * mono_runtime_try_run_main:
4233 * @method: the method to start the application with (usually Main)
4234 * @argc: number of arguments from the command line
4235 * @argv: array of strings from the command line
4236 * @exc: set if Main throws an exception
4237 * @error: set if Main can't be executed
4239 * Execute a standard Main() method (argc/argv contains the executable
4240 * name). This method also sets the command line argument value needed
4241 * by System.Environment. On failure sets @error if Main can't be
4242 * executed or @exc if it threw and exception.
4247 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4248 MonoObject **exc)
4250 g_assert (exc);
4251 MonoArray *args = prepare_run_main (method, argc, argv);
4252 return mono_runtime_try_exec_main (method, args, exc);
4256 static MonoObject*
4257 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4259 static MonoMethod *serialize_method;
4261 MonoError error;
4262 void *params [1];
4263 MonoObject *array;
4265 if (!serialize_method) {
4266 MonoClass *klass = mono_class_get_remoting_services_class ();
4267 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4270 if (!serialize_method) {
4271 *failure = TRUE;
4272 return NULL;
4275 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4277 params [0] = obj;
4278 *exc = NULL;
4280 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4281 if (*exc == NULL && !mono_error_ok (&error))
4282 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4283 else
4284 mono_error_cleanup (&error);
4286 if (*exc)
4287 *failure = TRUE;
4289 return array;
4292 static MonoObject*
4293 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4295 MONO_REQ_GC_UNSAFE_MODE;
4297 static MonoMethod *deserialize_method;
4299 MonoError error;
4300 void *params [1];
4301 MonoObject *result;
4303 if (!deserialize_method) {
4304 MonoClass *klass = mono_class_get_remoting_services_class ();
4305 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4307 if (!deserialize_method) {
4308 *failure = TRUE;
4309 return NULL;
4312 params [0] = obj;
4313 *exc = NULL;
4315 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4316 if (*exc == NULL && !mono_error_ok (&error))
4317 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4318 else
4319 mono_error_cleanup (&error);
4321 if (*exc)
4322 *failure = TRUE;
4324 return result;
4327 #ifndef DISABLE_REMOTING
4328 static MonoObject*
4329 make_transparent_proxy (MonoObject *obj, MonoError *error)
4331 MONO_REQ_GC_UNSAFE_MODE;
4333 static MonoMethod *get_proxy_method;
4335 MonoDomain *domain = mono_domain_get ();
4336 MonoRealProxy *real_proxy;
4337 MonoReflectionType *reflection_type;
4338 MonoTransparentProxy *transparent_proxy;
4340 mono_error_init (error);
4342 if (!get_proxy_method)
4343 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4345 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4347 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4348 return_val_if_nok (error, NULL);
4349 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4350 return_val_if_nok (error, NULL);
4352 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4353 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4355 MonoObject *exc = NULL;
4357 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4358 if (exc != NULL && is_ok (error))
4359 mono_error_set_exception_instance (error, (MonoException*)exc);
4361 return (MonoObject*) transparent_proxy;
4363 #endif /* DISABLE_REMOTING */
4366 * mono_object_xdomain_representation
4367 * @obj: an object
4368 * @target_domain: a domain
4369 * @error: set on error.
4371 * Creates a representation of obj in the domain target_domain. This
4372 * is either a copy of obj arrived through via serialization and
4373 * deserialization or a proxy, depending on whether the object is
4374 * serializable or marshal by ref. obj must not be in target_domain.
4376 * If the object cannot be represented in target_domain, NULL is
4377 * returned and @error is set appropriately.
4379 MonoObject*
4380 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4382 MONO_REQ_GC_UNSAFE_MODE;
4384 mono_error_init (error);
4385 MonoObject *deserialized = NULL;
4387 #ifndef DISABLE_REMOTING
4388 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4389 deserialized = make_transparent_proxy (obj, error);
4391 else
4392 #endif
4394 gboolean failure = FALSE;
4395 MonoDomain *domain = mono_domain_get ();
4396 MonoObject *serialized;
4397 MonoObject *exc = NULL;
4399 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4400 serialized = serialize_object (obj, &failure, &exc);
4401 mono_domain_set_internal_with_options (target_domain, FALSE);
4402 if (!failure)
4403 deserialized = deserialize_object (serialized, &failure, &exc);
4404 if (domain != target_domain)
4405 mono_domain_set_internal_with_options (domain, FALSE);
4406 if (failure)
4407 mono_error_set_exception_instance (error, (MonoException*)exc);
4410 return deserialized;
4413 /* Used in call_unhandled_exception_delegate */
4414 static MonoObject *
4415 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4417 MONO_REQ_GC_UNSAFE_MODE;
4419 mono_error_init (error);
4420 MonoClass *klass;
4421 gpointer args [2];
4422 MonoMethod *method = NULL;
4423 MonoBoolean is_terminating = TRUE;
4424 MonoObject *obj;
4426 klass = mono_class_get_unhandled_exception_event_args_class ();
4427 mono_class_init (klass);
4429 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4430 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4431 g_assert (method);
4433 args [0] = exc;
4434 args [1] = &is_terminating;
4436 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4437 return_val_if_nok (error, NULL);
4439 mono_runtime_invoke_checked (method, obj, args, error);
4440 return_val_if_nok (error, NULL);
4442 return obj;
4445 /* Used in mono_unhandled_exception */
4446 static void
4447 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4448 MONO_REQ_GC_UNSAFE_MODE;
4450 MonoError error;
4451 MonoObject *e = NULL;
4452 gpointer pa [2];
4453 MonoDomain *current_domain = mono_domain_get ();
4455 if (domain != current_domain)
4456 mono_domain_set_internal_with_options (domain, FALSE);
4458 g_assert (domain == mono_object_domain (domain->domain));
4460 if (mono_object_domain (exc) != domain) {
4462 exc = mono_object_xdomain_representation (exc, domain, &error);
4463 if (!exc) {
4464 if (!is_ok (&error)) {
4465 MonoError inner_error;
4466 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4467 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4468 mono_error_assert_ok (&inner_error);
4469 } else {
4470 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4471 "System.Runtime.Serialization", "SerializationException",
4472 "Could not serialize unhandled exception.");
4476 g_assert (mono_object_domain (exc) == domain);
4478 pa [0] = domain->domain;
4479 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4480 mono_error_assert_ok (&error);
4481 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4482 if (!is_ok (&error)) {
4483 if (e == NULL)
4484 e = (MonoObject*)mono_error_convert_to_exception (&error);
4485 else
4486 mono_error_cleanup (&error);
4489 if (domain != current_domain)
4490 mono_domain_set_internal_with_options (current_domain, FALSE);
4492 if (e) {
4493 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4494 if (!mono_error_ok (&error)) {
4495 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4496 mono_error_cleanup (&error);
4497 } else {
4498 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4499 g_free (msg);
4504 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4507 * mono_runtime_unhandled_exception_policy_set:
4508 * @policy: the new policy
4510 * This is a VM internal routine.
4512 * Sets the runtime policy for handling unhandled exceptions.
4514 void
4515 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4516 runtime_unhandled_exception_policy = policy;
4520 * mono_runtime_unhandled_exception_policy_get:
4522 * This is a VM internal routine.
4524 * Gets the runtime policy for handling unhandled exceptions.
4526 MonoRuntimeUnhandledExceptionPolicy
4527 mono_runtime_unhandled_exception_policy_get (void) {
4528 return runtime_unhandled_exception_policy;
4532 * mono_unhandled_exception:
4533 * @exc: exception thrown
4535 * This is a VM internal routine.
4537 * We call this function when we detect an unhandled exception
4538 * in the default domain.
4540 * It invokes the * UnhandledException event in AppDomain or prints
4541 * a warning to the console
4543 void
4544 mono_unhandled_exception (MonoObject *exc)
4546 MONO_REQ_GC_UNSAFE_MODE;
4548 MonoError error;
4549 MonoClassField *field;
4550 MonoDomain *current_domain, *root_domain;
4551 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4553 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4554 return;
4556 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4557 g_assert (field);
4559 current_domain = mono_domain_get ();
4560 root_domain = mono_get_root_domain ();
4562 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4563 mono_error_assert_ok (&error);
4564 if (current_domain != root_domain) {
4565 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4566 mono_error_assert_ok (&error);
4569 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4570 mono_print_unhandled_exception (exc);
4571 } else {
4572 /* unhandled exception callbacks must not be aborted */
4573 mono_threads_begin_abort_protected_block ();
4574 if (root_appdomain_delegate)
4575 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4576 if (current_appdomain_delegate)
4577 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4578 mono_threads_end_abort_protected_block ();
4581 /* set exitcode only if we will abort the process */
4582 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4583 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4585 mono_environment_exitcode_set (1);
4590 * mono_runtime_exec_managed_code:
4591 * @domain: Application domain
4592 * @main_func: function to invoke from the execution thread
4593 * @main_args: parameter to the main_func
4595 * Launch a new thread to execute a function
4597 * main_func is called back from the thread with main_args as the
4598 * parameter. The callback function is expected to start Main()
4599 * eventually. This function then waits for all managed threads to
4600 * finish.
4601 * It is not necesseray anymore to execute managed code in a subthread,
4602 * so this function should not be used anymore by default: just
4603 * execute the code and then call mono_thread_manage ().
4605 void
4606 mono_runtime_exec_managed_code (MonoDomain *domain,
4607 MonoMainThreadFunc main_func,
4608 gpointer main_args)
4610 MonoError error;
4611 mono_thread_create_checked (domain, main_func, main_args, &error);
4612 mono_error_assert_ok (&error);
4614 mono_thread_manage ();
4617 static void
4618 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4620 MonoInternalThread* thread = mono_thread_internal_current ();
4621 MonoCustomAttrInfo* cinfo;
4622 gboolean has_stathread_attribute;
4624 if (!domain->entry_assembly) {
4625 gchar *str;
4626 MonoAssembly *assembly;
4628 assembly = method->klass->image->assembly;
4629 domain->entry_assembly = assembly;
4630 /* Domains created from another domain already have application_base and configuration_file set */
4631 if (domain->setup->application_base == NULL) {
4632 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4635 if (domain->setup->configuration_file == NULL) {
4636 str = g_strconcat (assembly->image->name, ".config", NULL);
4637 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4638 g_free (str);
4639 mono_domain_set_options_from_config (domain);
4643 MonoError cattr_error;
4644 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4645 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4646 if (cinfo) {
4647 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4648 if (!cinfo->cached)
4649 mono_custom_attrs_free (cinfo);
4650 } else {
4651 has_stathread_attribute = FALSE;
4653 if (has_stathread_attribute) {
4654 thread->apartment_state = ThreadApartmentState_STA;
4655 } else {
4656 thread->apartment_state = ThreadApartmentState_MTA;
4658 mono_thread_init_apartment_state ();
4662 static int
4663 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4665 MONO_REQ_GC_UNSAFE_MODE;
4667 gpointer pa [1];
4668 int rval;
4670 mono_error_init (error);
4671 g_assert (args);
4673 pa [0] = args;
4675 /* FIXME: check signature of method */
4676 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4677 MonoObject *res;
4678 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4679 if (is_ok (error))
4680 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4681 else
4682 rval = -1;
4683 mono_environment_exitcode_set (rval);
4684 } else {
4685 mono_runtime_invoke_checked (method, NULL, pa, error);
4687 if (is_ok (error))
4688 rval = 0;
4689 else {
4690 rval = -1;
4693 return rval;
4696 static int
4697 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4699 MONO_REQ_GC_UNSAFE_MODE;
4701 gpointer pa [1];
4702 int rval;
4704 g_assert (args);
4705 g_assert (exc);
4707 pa [0] = args;
4709 /* FIXME: check signature of method */
4710 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4711 MonoError inner_error;
4712 MonoObject *res;
4713 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4714 if (*exc == NULL && !mono_error_ok (&inner_error))
4715 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4716 else
4717 mono_error_cleanup (&inner_error);
4719 if (*exc == NULL)
4720 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4721 else
4722 rval = -1;
4724 mono_environment_exitcode_set (rval);
4725 } else {
4726 MonoError inner_error;
4727 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4728 if (*exc == NULL && !mono_error_ok (&inner_error))
4729 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4730 else
4731 mono_error_cleanup (&inner_error);
4733 if (*exc == NULL)
4734 rval = 0;
4735 else {
4736 /* If the return type of Main is void, only
4737 * set the exitcode if an exception was thrown
4738 * (we don't want to blow away an
4739 * explicitly-set exit code)
4741 rval = -1;
4742 mono_environment_exitcode_set (rval);
4746 return rval;
4750 * Execute a standard Main() method (args doesn't contain the
4751 * executable name).
4754 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4756 MonoError error;
4757 prepare_thread_to_exec_main (mono_object_domain (args), method);
4758 if (exc) {
4759 int rval = do_try_exec_main (method, args, exc);
4760 return rval;
4761 } else {
4762 int rval = do_exec_main_checked (method, args, &error);
4763 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4764 return rval;
4769 * Execute a standard Main() method (args doesn't contain the
4770 * executable name).
4772 * On failure sets @error
4775 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4777 mono_error_init (error);
4778 prepare_thread_to_exec_main (mono_object_domain (args), method);
4779 return do_exec_main_checked (method, args, error);
4783 * Execute a standard Main() method (args doesn't contain the
4784 * executable name).
4786 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4789 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4791 prepare_thread_to_exec_main (mono_object_domain (args), method);
4792 return do_try_exec_main (method, args, exc);
4797 /** invoke_array_extract_argument:
4798 * @params: array of arguments to the method.
4799 * @i: the index of the argument to extract.
4800 * @t: ith type from the method signature.
4801 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4802 * @error: set on error.
4804 * Given an array of method arguments, return the ith one using the corresponding type
4805 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4807 * On failure sets @error and returns NULL.
4809 static gpointer
4810 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4812 MonoType *t_orig = t;
4813 gpointer result = NULL;
4814 mono_error_init (error);
4815 again:
4816 switch (t->type) {
4817 case MONO_TYPE_U1:
4818 case MONO_TYPE_I1:
4819 case MONO_TYPE_BOOLEAN:
4820 case MONO_TYPE_U2:
4821 case MONO_TYPE_I2:
4822 case MONO_TYPE_CHAR:
4823 case MONO_TYPE_U:
4824 case MONO_TYPE_I:
4825 case MONO_TYPE_U4:
4826 case MONO_TYPE_I4:
4827 case MONO_TYPE_U8:
4828 case MONO_TYPE_I8:
4829 case MONO_TYPE_R4:
4830 case MONO_TYPE_R8:
4831 case MONO_TYPE_VALUETYPE:
4832 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4833 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4834 result = mono_array_get (params, MonoObject*, i);
4835 if (t->byref)
4836 *has_byref_nullables = TRUE;
4837 } else {
4838 /* MS seems to create the objects if a null is passed in */
4839 if (!mono_array_get (params, MonoObject*, i)) {
4840 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4841 return_val_if_nok (error, NULL);
4842 mono_array_setref (params, i, o);
4845 if (t->byref) {
4847 * We can't pass the unboxed vtype byref to the callee, since
4848 * that would mean the callee would be able to modify boxed
4849 * primitive types. So we (and MS) make a copy of the boxed
4850 * object, pass that to the callee, and replace the original
4851 * boxed object in the arg array with the copy.
4853 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4854 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4855 return_val_if_nok (error, NULL);
4856 mono_array_setref (params, i, copy);
4859 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4861 break;
4862 case MONO_TYPE_STRING:
4863 case MONO_TYPE_OBJECT:
4864 case MONO_TYPE_CLASS:
4865 case MONO_TYPE_ARRAY:
4866 case MONO_TYPE_SZARRAY:
4867 if (t->byref)
4868 result = mono_array_addr (params, MonoObject*, i);
4869 // FIXME: I need to check this code path
4870 else
4871 result = mono_array_get (params, MonoObject*, i);
4872 break;
4873 case MONO_TYPE_GENERICINST:
4874 if (t->byref)
4875 t = &t->data.generic_class->container_class->this_arg;
4876 else
4877 t = &t->data.generic_class->container_class->byval_arg;
4878 goto again;
4879 case MONO_TYPE_PTR: {
4880 MonoObject *arg;
4882 /* The argument should be an IntPtr */
4883 arg = mono_array_get (params, MonoObject*, i);
4884 if (arg == NULL) {
4885 result = NULL;
4886 } else {
4887 g_assert (arg->vtable->klass == mono_defaults.int_class);
4888 result = ((MonoIntPtr*)arg)->m_value;
4890 break;
4892 default:
4893 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4895 return result;
4898 * mono_runtime_invoke_array:
4899 * @method: method to invoke
4900 * @obJ: object instance
4901 * @params: arguments to the method
4902 * @exc: exception information.
4904 * Invokes the method represented by @method on the object @obj.
4906 * obj is the 'this' pointer, it should be NULL for static
4907 * methods, a MonoObject* for object instances and a pointer to
4908 * the value type for value types.
4910 * The params array contains the arguments to the method with the
4911 * same convention: MonoObject* pointers for object instances and
4912 * pointers to the value type otherwise. The _invoke_array
4913 * variant takes a C# object[] as the params argument (MonoArray
4914 * *params): in this case the value types are boxed inside the
4915 * respective reference representation.
4917 * From unmanaged code you'll usually use the
4918 * mono_runtime_invoke_checked() variant.
4920 * Note that this function doesn't handle virtual methods for
4921 * you, it will exec the exact method you pass: we still need to
4922 * expose a function to lookup the derived class implementation
4923 * of a virtual method (there are examples of this in the code,
4924 * though).
4926 * You can pass NULL as the exc argument if you don't want to
4927 * catch exceptions, otherwise, *exc will be set to the exception
4928 * thrown, if any. if an exception is thrown, you can't use the
4929 * MonoObject* result from the function.
4931 * If the method returns a value type, it is boxed in an object
4932 * reference.
4934 MonoObject*
4935 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4936 MonoObject **exc)
4938 MonoError error;
4939 if (exc) {
4940 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4941 if (*exc) {
4942 mono_error_cleanup (&error);
4943 return NULL;
4944 } else {
4945 if (!is_ok (&error))
4946 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4947 return result;
4949 } else {
4950 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4951 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4952 return result;
4957 * mono_runtime_invoke_array_checked:
4958 * @method: method to invoke
4959 * @obJ: object instance
4960 * @params: arguments to the method
4961 * @error: set on failure.
4963 * Invokes the method represented by @method on the object @obj.
4965 * obj is the 'this' pointer, it should be NULL for static
4966 * methods, a MonoObject* for object instances and a pointer to
4967 * the value type for value types.
4969 * The params array contains the arguments to the method with the
4970 * same convention: MonoObject* pointers for object instances and
4971 * pointers to the value type otherwise. The _invoke_array
4972 * variant takes a C# object[] as the params argument (MonoArray
4973 * *params): in this case the value types are boxed inside the
4974 * respective reference representation.
4976 * From unmanaged code you'll usually use the
4977 * mono_runtime_invoke_checked() variant.
4979 * Note that this function doesn't handle virtual methods for
4980 * you, it will exec the exact method you pass: we still need to
4981 * expose a function to lookup the derived class implementation
4982 * of a virtual method (there are examples of this in the code,
4983 * though).
4985 * On failure or exception, @error will be set. In that case, you
4986 * can't use the MonoObject* result from the function.
4988 * If the method returns a value type, it is boxed in an object
4989 * reference.
4991 MonoObject*
4992 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4993 MonoError *error)
4995 mono_error_init (error);
4996 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5000 * mono_runtime_try_invoke_array:
5001 * @method: method to invoke
5002 * @obJ: object instance
5003 * @params: arguments to the method
5004 * @exc: exception information.
5005 * @error: set on failure.
5007 * Invokes the method represented by @method on the object @obj.
5009 * obj is the 'this' pointer, it should be NULL for static
5010 * methods, a MonoObject* for object instances and a pointer to
5011 * the value type for value types.
5013 * The params array contains the arguments to the method with the
5014 * same convention: MonoObject* pointers for object instances and
5015 * pointers to the value type otherwise. The _invoke_array
5016 * variant takes a C# object[] as the params argument (MonoArray
5017 * *params): in this case the value types are boxed inside the
5018 * respective reference representation.
5020 * From unmanaged code you'll usually use the
5021 * mono_runtime_invoke_checked() variant.
5023 * Note that this function doesn't handle virtual methods for
5024 * you, it will exec the exact method you pass: we still need to
5025 * expose a function to lookup the derived class implementation
5026 * of a virtual method (there are examples of this in the code,
5027 * though).
5029 * You can pass NULL as the exc argument if you don't want to catch
5030 * exceptions, otherwise, *exc will be set to the exception thrown, if
5031 * any. On other failures, @error will be set. If an exception is
5032 * thrown or there's an error, you can't use the MonoObject* result
5033 * from the function.
5035 * If the method returns a value type, it is boxed in an object
5036 * reference.
5038 MonoObject*
5039 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5040 MonoObject **exc, MonoError *error)
5042 MONO_REQ_GC_UNSAFE_MODE;
5044 mono_error_init (error);
5046 MonoMethodSignature *sig = mono_method_signature (method);
5047 gpointer *pa = NULL;
5048 MonoObject *res;
5049 int i;
5050 gboolean has_byref_nullables = FALSE;
5052 if (NULL != params) {
5053 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5054 for (i = 0; i < mono_array_length (params); i++) {
5055 MonoType *t = sig->params [i];
5056 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5057 return_val_if_nok (error, NULL);
5061 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5062 void *o = obj;
5064 if (mono_class_is_nullable (method->klass)) {
5065 /* Need to create a boxed vtype instead */
5066 g_assert (!obj);
5068 if (!params)
5069 return NULL;
5070 else {
5071 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5075 if (!obj) {
5076 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5077 mono_error_assert_ok (error);
5078 g_assert (obj); /*maybe we should raise a TLE instead?*/
5079 #ifndef DISABLE_REMOTING
5080 if (mono_object_is_transparent_proxy (obj)) {
5081 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5083 #endif
5084 if (method->klass->valuetype)
5085 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5086 else
5087 o = obj;
5088 } else if (method->klass->valuetype) {
5089 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5090 return_val_if_nok (error, NULL);
5093 if (exc) {
5094 mono_runtime_try_invoke (method, o, pa, exc, error);
5095 } else {
5096 mono_runtime_invoke_checked (method, o, pa, error);
5099 return (MonoObject *)obj;
5100 } else {
5101 if (mono_class_is_nullable (method->klass)) {
5102 MonoObject *nullable;
5104 /* Convert the unboxed vtype into a Nullable structure */
5105 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5106 return_val_if_nok (error, NULL);
5108 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5109 return_val_if_nok (error, NULL);
5110 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5111 obj = mono_object_unbox (nullable);
5114 /* obj must be already unboxed if needed */
5115 if (exc) {
5116 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5117 } else {
5118 res = mono_runtime_invoke_checked (method, obj, pa, error);
5120 return_val_if_nok (error, NULL);
5122 if (sig->ret->type == MONO_TYPE_PTR) {
5123 MonoClass *pointer_class;
5124 static MonoMethod *box_method;
5125 void *box_args [2];
5126 MonoObject *box_exc;
5129 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5130 * convert it to a Pointer object.
5132 pointer_class = mono_class_get_pointer_class ();
5133 if (!box_method)
5134 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5136 g_assert (res->vtable->klass == mono_defaults.int_class);
5137 box_args [0] = ((MonoIntPtr*)res)->m_value;
5138 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5139 return_val_if_nok (error, NULL);
5141 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5142 g_assert (box_exc == NULL);
5143 mono_error_assert_ok (error);
5146 if (has_byref_nullables) {
5148 * The runtime invoke wrapper already converted byref nullables back,
5149 * and stored them in pa, we just need to copy them back to the
5150 * managed array.
5152 for (i = 0; i < mono_array_length (params); i++) {
5153 MonoType *t = sig->params [i];
5155 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5156 mono_array_setref (params, i, pa [i]);
5160 return res;
5165 * mono_object_new:
5166 * @klass: the class of the object that we want to create
5168 * Returns: a newly created object whose definition is
5169 * looked up using @klass. This will not invoke any constructors,
5170 * so the consumer of this routine has to invoke any constructors on
5171 * its own to initialize the object.
5173 * It returns NULL on failure.
5175 MonoObject *
5176 mono_object_new (MonoDomain *domain, MonoClass *klass)
5178 MONO_REQ_GC_UNSAFE_MODE;
5180 MonoError error;
5182 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5184 mono_error_cleanup (&error);
5185 return result;
5188 MonoObject *
5189 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5191 MONO_REQ_GC_UNSAFE_MODE;
5193 MonoError error;
5195 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5197 mono_error_set_pending_exception (&error);
5198 return result;
5202 * mono_object_new_checked:
5203 * @klass: the class of the object that we want to create
5204 * @error: set on error
5206 * Returns: a newly created object whose definition is
5207 * looked up using @klass. This will not invoke any constructors,
5208 * so the consumer of this routine has to invoke any constructors on
5209 * its own to initialize the object.
5211 * It returns NULL on failure and sets @error.
5213 MonoObject *
5214 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5216 MONO_REQ_GC_UNSAFE_MODE;
5218 MonoVTable *vtable;
5220 vtable = mono_class_vtable (domain, klass);
5221 g_assert (vtable); /* FIXME don't swallow the error */
5223 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5224 return o;
5228 * mono_object_new_pinned:
5230 * Same as mono_object_new, but the returned object will be pinned.
5231 * For SGEN, these objects will only be freed at appdomain unload.
5233 MonoObject *
5234 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5236 MONO_REQ_GC_UNSAFE_MODE;
5238 MonoVTable *vtable;
5240 mono_error_init (error);
5242 vtable = mono_class_vtable (domain, klass);
5243 g_assert (vtable); /* FIXME don't swallow the error */
5245 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5247 if (G_UNLIKELY (!o))
5248 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5249 else if (G_UNLIKELY (vtable->klass->has_finalize))
5250 mono_object_register_finalizer (o);
5252 return o;
5256 * mono_object_new_specific:
5257 * @vtable: the vtable of the object that we want to create
5259 * Returns: A newly created object with class and domain specified
5260 * by @vtable
5262 MonoObject *
5263 mono_object_new_specific (MonoVTable *vtable)
5265 MonoError error;
5266 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5267 mono_error_cleanup (&error);
5269 return o;
5272 MonoObject *
5273 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5275 MONO_REQ_GC_UNSAFE_MODE;
5277 MonoObject *o;
5279 mono_error_init (error);
5281 /* check for is_com_object for COM Interop */
5282 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5284 gpointer pa [1];
5285 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5287 if (im == NULL) {
5288 MonoClass *klass = mono_class_get_activation_services_class ();
5290 if (!klass->inited)
5291 mono_class_init (klass);
5293 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5294 if (!im) {
5295 mono_error_set_not_supported (error, "Linked away.");
5296 return NULL;
5298 vtable->domain->create_proxy_for_type_method = im;
5301 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5302 if (!mono_error_ok (error))
5303 return NULL;
5305 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5306 if (!mono_error_ok (error))
5307 return NULL;
5309 if (o != NULL)
5310 return o;
5313 return mono_object_new_alloc_specific_checked (vtable, error);
5316 MonoObject *
5317 ves_icall_object_new_specific (MonoVTable *vtable)
5319 MonoError error;
5320 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5321 mono_error_set_pending_exception (&error);
5323 return o;
5327 * mono_object_new_alloc_specific:
5328 * @vtable: virtual table for the object.
5330 * This function allocates a new `MonoObject` with the type derived
5331 * from the @vtable information. If the class of this object has a
5332 * finalizer, then the object will be tracked for finalization.
5334 * This method might raise an exception on errors. Use the
5335 * `mono_object_new_fast_checked` method if you want to manually raise
5336 * the exception.
5338 * Returns: the allocated object.
5340 MonoObject *
5341 mono_object_new_alloc_specific (MonoVTable *vtable)
5343 MonoError error;
5344 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5345 mono_error_cleanup (&error);
5347 return o;
5351 * mono_object_new_alloc_specific_checked:
5352 * @vtable: virtual table for the object.
5353 * @error: holds the error return value.
5355 * This function allocates a new `MonoObject` with the type derived
5356 * from the @vtable information. If the class of this object has a
5357 * finalizer, then the object will be tracked for finalization.
5359 * If there is not enough memory, the @error parameter will be set
5360 * and will contain a user-visible message with the amount of bytes
5361 * that were requested.
5363 * Returns: the allocated object, or NULL if there is not enough memory
5366 MonoObject *
5367 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5369 MONO_REQ_GC_UNSAFE_MODE;
5371 MonoObject *o;
5373 mono_error_init (error);
5375 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5377 if (G_UNLIKELY (!o))
5378 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5379 else if (G_UNLIKELY (vtable->klass->has_finalize))
5380 mono_object_register_finalizer (o);
5382 return o;
5386 * mono_object_new_fast:
5387 * @vtable: virtual table for the object.
5389 * This function allocates a new `MonoObject` with the type derived
5390 * from the @vtable information. The returned object is not tracked
5391 * for finalization. If your object implements a finalizer, you should
5392 * use `mono_object_new_alloc_specific` instead.
5394 * This method might raise an exception on errors. Use the
5395 * `mono_object_new_fast_checked` method if you want to manually raise
5396 * the exception.
5398 * Returns: the allocated object.
5400 MonoObject*
5401 mono_object_new_fast (MonoVTable *vtable)
5403 MonoError error;
5404 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5405 mono_error_cleanup (&error);
5407 return o;
5411 * mono_object_new_fast_checked:
5412 * @vtable: virtual table for the object.
5413 * @error: holds the error return value.
5415 * This function allocates a new `MonoObject` with the type derived
5416 * from the @vtable information. The returned object is not tracked
5417 * for finalization. If your object implements a finalizer, you should
5418 * use `mono_object_new_alloc_specific_checked` instead.
5420 * If there is not enough memory, the @error parameter will be set
5421 * and will contain a user-visible message with the amount of bytes
5422 * that were requested.
5424 * Returns: the allocated object, or NULL if there is not enough memory
5427 MonoObject*
5428 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5430 MONO_REQ_GC_UNSAFE_MODE;
5432 MonoObject *o;
5434 mono_error_init (error);
5436 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5438 if (G_UNLIKELY (!o))
5439 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5441 return o;
5444 MonoObject *
5445 ves_icall_object_new_fast (MonoVTable *vtable)
5447 MonoError error;
5448 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5449 mono_error_set_pending_exception (&error);
5451 return o;
5454 MonoObject*
5455 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5457 MONO_REQ_GC_UNSAFE_MODE;
5459 MonoObject *o;
5461 mono_error_init (error);
5463 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5465 if (G_UNLIKELY (!o))
5466 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5467 else if (G_UNLIKELY (vtable->klass->has_finalize))
5468 mono_object_register_finalizer (o);
5470 return o;
5474 * mono_class_get_allocation_ftn:
5475 * @vtable: vtable
5476 * @for_box: the object will be used for boxing
5477 * @pass_size_in_words:
5479 * Return the allocation function appropriate for the given class.
5482 void*
5483 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5485 MONO_REQ_GC_NEUTRAL_MODE;
5487 *pass_size_in_words = FALSE;
5489 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5490 return ves_icall_object_new_specific;
5492 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5494 return ves_icall_object_new_fast;
5497 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5498 * of the overhead of parameter passing.
5501 *pass_size_in_words = TRUE;
5502 #ifdef GC_REDIRECT_TO_LOCAL
5503 return GC_local_gcj_fast_malloc;
5504 #else
5505 return GC_gcj_fast_malloc;
5506 #endif
5510 return ves_icall_object_new_specific;
5514 * mono_object_new_from_token:
5515 * @image: Context where the type_token is hosted
5516 * @token: a token of the type that we want to create
5518 * Returns: A newly created object whose definition is
5519 * looked up using @token in the @image image
5521 MonoObject *
5522 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5524 MONO_REQ_GC_UNSAFE_MODE;
5526 MonoError error;
5527 MonoObject *result;
5528 MonoClass *klass;
5530 klass = mono_class_get_checked (image, token, &error);
5531 mono_error_assert_ok (&error);
5533 result = mono_object_new_checked (domain, klass, &error);
5535 mono_error_cleanup (&error);
5536 return result;
5542 * mono_object_clone:
5543 * @obj: the object to clone
5545 * Returns: A newly created object who is a shallow copy of @obj
5547 MonoObject *
5548 mono_object_clone (MonoObject *obj)
5550 MonoError error;
5551 MonoObject *o = mono_object_clone_checked (obj, &error);
5552 mono_error_cleanup (&error);
5554 return o;
5557 MonoObject *
5558 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5560 MONO_REQ_GC_UNSAFE_MODE;
5562 MonoObject *o;
5563 int size;
5565 mono_error_init (error);
5567 size = obj->vtable->klass->instance_size;
5569 if (obj->vtable->klass->rank)
5570 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5572 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5574 if (G_UNLIKELY (!o)) {
5575 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5576 return NULL;
5579 /* If the object doesn't contain references this will do a simple memmove. */
5580 mono_gc_wbarrier_object_copy (o, obj);
5582 if (obj->vtable->klass->has_finalize)
5583 mono_object_register_finalizer (o);
5584 return o;
5588 * mono_array_full_copy:
5589 * @src: source array to copy
5590 * @dest: destination array
5592 * Copies the content of one array to another with exactly the same type and size.
5594 void
5595 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5597 MONO_REQ_GC_UNSAFE_MODE;
5599 uintptr_t size;
5600 MonoClass *klass = src->obj.vtable->klass;
5602 g_assert (klass == dest->obj.vtable->klass);
5604 size = mono_array_length (src);
5605 g_assert (size == mono_array_length (dest));
5606 size *= mono_array_element_size (klass);
5608 array_full_copy_unchecked_size (src, dest, klass, size);
5611 static void
5612 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5614 #ifdef HAVE_SGEN_GC
5615 if (klass->element_class->valuetype) {
5616 if (klass->element_class->has_references)
5617 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5618 else
5619 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5620 } else {
5621 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5623 #else
5624 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5625 #endif
5629 * mono_array_clone_in_domain:
5630 * @domain: the domain in which the array will be cloned into
5631 * @array: the array to clone
5632 * @error: set on error
5634 * This routine returns a copy of the array that is hosted on the
5635 * specified MonoDomain. On failure returns NULL and sets @error.
5637 MonoArrayHandle
5638 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5640 MONO_REQ_GC_UNSAFE_MODE;
5642 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5643 uintptr_t size = 0;
5644 MonoClass *klass = mono_handle_class (array_handle);
5646 mono_error_init (error);
5648 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5649 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5651 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5652 MonoArrayHandle o;
5653 if (array_bounds == NULL) {
5654 size = mono_array_handle_length (array_handle);
5655 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5656 if (!is_ok (error))
5657 goto leave;
5658 size *= mono_array_element_size (klass);
5659 } else {
5660 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5661 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5662 size = mono_array_element_size (klass);
5663 for (int i = 0; i < klass->rank; ++i) {
5664 sizes [i] = array_bounds [i].length;
5665 size *= array_bounds [i].length;
5666 lower_bounds [i] = array_bounds [i].lower_bound;
5668 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5669 if (!is_ok (error))
5670 goto leave;
5673 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5674 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5675 mono_gchandle_free (dst_handle);
5677 MONO_HANDLE_ASSIGN (result, o);
5679 leave:
5680 mono_gchandle_free (src_handle);
5681 return result;
5685 * mono_array_clone:
5686 * @array: the array to clone
5688 * Returns: A newly created array who is a shallow copy of @array
5690 MonoArray*
5691 mono_array_clone (MonoArray *array)
5693 MONO_REQ_GC_UNSAFE_MODE;
5695 MonoError error;
5696 MonoArray *result = mono_array_clone_checked (array, &error);
5697 mono_error_cleanup (&error);
5698 return result;
5702 * mono_array_clone_checked:
5703 * @array: the array to clone
5704 * @error: set on error
5706 * Returns: A newly created array who is a shallow copy of @array. On
5707 * failure returns NULL and sets @error.
5709 MonoArray*
5710 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5712 MONO_REQ_GC_UNSAFE_MODE;
5713 HANDLE_FUNCTION_ENTER ();
5714 /* FIXME: callers of mono_array_clone_checked should use handles */
5715 mono_error_init (error);
5716 MONO_HANDLE_DCL (MonoArray, array);
5717 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5718 HANDLE_FUNCTION_RETURN_OBJ (result);
5721 /* helper macros to check for overflow when calculating the size of arrays */
5722 #ifdef MONO_BIG_ARRAYS
5723 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5724 #define MYGUINT_MAX MYGUINT64_MAX
5725 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5726 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5727 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5728 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5729 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5730 #else
5731 #define MYGUINT32_MAX 4294967295U
5732 #define MYGUINT_MAX MYGUINT32_MAX
5733 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5734 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5735 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5736 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5737 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5738 #endif
5740 gboolean
5741 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5743 MONO_REQ_GC_NEUTRAL_MODE;
5745 uintptr_t byte_len;
5747 byte_len = mono_array_element_size (klass);
5748 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5749 return FALSE;
5750 byte_len *= len;
5751 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5752 return FALSE;
5753 byte_len += MONO_SIZEOF_MONO_ARRAY;
5755 *res = byte_len;
5757 return TRUE;
5761 * mono_array_new_full:
5762 * @domain: domain where the object is created
5763 * @array_class: array class
5764 * @lengths: lengths for each dimension in the array
5765 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5767 * This routine creates a new array objects with the given dimensions,
5768 * lower bounds and type.
5770 MonoArray*
5771 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5773 MonoError error;
5774 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5775 mono_error_cleanup (&error);
5777 return array;
5780 MonoArray*
5781 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5783 MONO_REQ_GC_UNSAFE_MODE;
5785 uintptr_t byte_len = 0, len, bounds_size;
5786 MonoObject *o;
5787 MonoArray *array;
5788 MonoArrayBounds *bounds;
5789 MonoVTable *vtable;
5790 int i;
5792 mono_error_init (error);
5794 if (!array_class->inited)
5795 mono_class_init (array_class);
5797 len = 1;
5799 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5800 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5801 len = lengths [0];
5802 if (len > MONO_ARRAY_MAX_INDEX) {
5803 mono_error_set_generic_error (error, "System", "OverflowException", "");
5804 return NULL;
5806 bounds_size = 0;
5807 } else {
5808 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5810 for (i = 0; i < array_class->rank; ++i) {
5811 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5812 mono_error_set_generic_error (error, "System", "OverflowException", "");
5813 return NULL;
5815 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5816 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5817 return NULL;
5819 len *= lengths [i];
5823 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5824 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5825 return NULL;
5828 if (bounds_size) {
5829 /* align */
5830 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5831 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5832 return NULL;
5834 byte_len = (byte_len + 3) & ~3;
5835 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5836 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5837 return NULL;
5839 byte_len += bounds_size;
5842 * Following three lines almost taken from mono_object_new ():
5843 * they need to be kept in sync.
5845 vtable = mono_class_vtable_full (domain, array_class, error);
5846 return_val_if_nok (error, NULL);
5848 if (bounds_size)
5849 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5850 else
5851 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5853 if (G_UNLIKELY (!o)) {
5854 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5855 return NULL;
5858 array = (MonoArray*)o;
5860 bounds = array->bounds;
5862 if (bounds_size) {
5863 for (i = 0; i < array_class->rank; ++i) {
5864 bounds [i].length = lengths [i];
5865 if (lower_bounds)
5866 bounds [i].lower_bound = lower_bounds [i];
5870 return array;
5874 * mono_array_new:
5875 * @domain: domain where the object is created
5876 * @eclass: element class
5877 * @n: number of array elements
5879 * This routine creates a new szarray with @n elements of type @eclass.
5881 MonoArray *
5882 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5884 MONO_REQ_GC_UNSAFE_MODE;
5886 MonoError error;
5887 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5888 mono_error_cleanup (&error);
5889 return result;
5893 * mono_array_new_checked:
5894 * @domain: domain where the object is created
5895 * @eclass: element class
5896 * @n: number of array elements
5897 * @error: set on error
5899 * This routine creates a new szarray with @n elements of type @eclass.
5900 * On failure returns NULL and sets @error.
5902 MonoArray *
5903 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5905 MonoClass *ac;
5907 mono_error_init (error);
5909 ac = mono_array_class_get (eclass, 1);
5910 g_assert (ac);
5912 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5913 return_val_if_nok (error, NULL);
5915 return mono_array_new_specific_checked (vtable, n, error);
5918 MonoArray*
5919 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5921 MonoError error;
5922 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5923 mono_error_set_pending_exception (&error);
5925 return arr;
5929 * mono_array_new_specific:
5930 * @vtable: a vtable in the appropriate domain for an initialized class
5931 * @n: number of array elements
5933 * This routine is a fast alternative to mono_array_new() for code which
5934 * can be sure about the domain it operates in.
5936 MonoArray *
5937 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5939 MonoError error;
5940 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5941 mono_error_cleanup (&error);
5943 return arr;
5946 MonoArray*
5947 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5949 MONO_REQ_GC_UNSAFE_MODE;
5951 MonoObject *o;
5952 uintptr_t byte_len;
5954 mono_error_init (error);
5956 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5957 mono_error_set_generic_error (error, "System", "OverflowException", "");
5958 return NULL;
5961 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5962 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5963 return NULL;
5965 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5967 if (G_UNLIKELY (!o)) {
5968 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5969 return NULL;
5972 return (MonoArray*)o;
5975 MonoArray*
5976 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5978 MonoError error;
5979 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5980 mono_error_set_pending_exception (&error);
5982 return arr;
5986 * mono_string_empty_wrapper:
5988 * Returns: The same empty string instance as the managed string.Empty
5990 MonoString*
5991 mono_string_empty_wrapper (void)
5993 MonoDomain *domain = mono_domain_get ();
5994 return mono_string_empty (domain);
5998 * mono_string_empty:
6000 * Returns: The same empty string instance as the managed string.Empty
6002 MonoString*
6003 mono_string_empty (MonoDomain *domain)
6005 g_assert (domain);
6006 g_assert (domain->empty_string);
6007 return domain->empty_string;
6011 * mono_string_new_utf16:
6012 * @text: a pointer to an utf16 string
6013 * @len: the length of the string
6015 * Returns: A newly created string object which contains @text.
6017 MonoString *
6018 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6020 MONO_REQ_GC_UNSAFE_MODE;
6022 MonoError error;
6023 MonoString *res = NULL;
6024 res = mono_string_new_utf16_checked (domain, text, len, &error);
6025 mono_error_cleanup (&error);
6027 return res;
6031 * mono_string_new_utf16_checked:
6032 * @text: a pointer to an utf16 string
6033 * @len: the length of the string
6034 * @error: written on error.
6036 * Returns: A newly created string object which contains @text.
6037 * On error, returns NULL and sets @error.
6039 MonoString *
6040 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6042 MONO_REQ_GC_UNSAFE_MODE;
6044 MonoString *s;
6046 mono_error_init (error);
6048 s = mono_string_new_size_checked (domain, len, error);
6049 if (s != NULL)
6050 memcpy (mono_string_chars (s), text, len * 2);
6052 return s;
6056 * mono_string_new_utf16_handle:
6057 * @text: a pointer to an utf16 string
6058 * @len: the length of the string
6059 * @error: written on error.
6061 * Returns: A newly created string object which contains @text.
6062 * On error, returns NULL and sets @error.
6064 MonoStringHandle
6065 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6067 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6071 * mono_string_new_utf32:
6072 * @text: a pointer to an utf32 string
6073 * @len: the length of the string
6074 * @error: set on failure.
6076 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6078 static MonoString *
6079 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6081 MONO_REQ_GC_UNSAFE_MODE;
6083 MonoString *s;
6084 mono_unichar2 *utf16_output = NULL;
6085 gint32 utf16_len = 0;
6086 GError *gerror = NULL;
6087 glong items_written;
6089 mono_error_init (error);
6090 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6092 if (gerror)
6093 g_error_free (gerror);
6095 while (utf16_output [utf16_len]) utf16_len++;
6097 s = mono_string_new_size_checked (domain, utf16_len, error);
6098 return_val_if_nok (error, NULL);
6100 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6102 g_free (utf16_output);
6104 return s;
6108 * mono_string_new_utf32:
6109 * @text: a pointer to an utf32 string
6110 * @len: the length of the string
6112 * Returns: A newly created string object which contains @text.
6114 MonoString *
6115 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6117 MonoError error;
6118 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6119 mono_error_cleanup (&error);
6120 return result;
6124 * mono_string_new_size:
6125 * @text: a pointer to an utf16 string
6126 * @len: the length of the string
6128 * Returns: A newly created string object of @len
6130 MonoString *
6131 mono_string_new_size (MonoDomain *domain, gint32 len)
6133 MonoError error;
6134 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6135 mono_error_cleanup (&error);
6137 return str;
6140 MonoString *
6141 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6143 MONO_REQ_GC_UNSAFE_MODE;
6145 MonoString *s;
6146 MonoVTable *vtable;
6147 size_t size;
6149 mono_error_init (error);
6151 /* check for overflow */
6152 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6153 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6154 return NULL;
6157 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6158 g_assert (size > 0);
6160 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6161 g_assert (vtable);
6163 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6165 if (G_UNLIKELY (!s)) {
6166 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6167 return NULL;
6170 return s;
6174 * mono_string_new_len:
6175 * @text: a pointer to an utf8 string
6176 * @length: number of bytes in @text to consider
6178 * Returns: A newly created string object which contains @text.
6180 MonoString*
6181 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6183 MONO_REQ_GC_UNSAFE_MODE;
6185 MonoError error;
6186 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6187 mono_error_cleanup (&error);
6188 return result;
6192 * mono_string_new_len_checked:
6193 * @text: a pointer to an utf8 string
6194 * @length: number of bytes in @text to consider
6195 * @error: set on error
6197 * Returns: A newly created string object which contains @text. On
6198 * failure returns NULL and sets @error.
6200 MonoString*
6201 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6203 MONO_REQ_GC_UNSAFE_MODE;
6205 mono_error_init (error);
6207 GError *eg_error = NULL;
6208 MonoString *o = NULL;
6209 guint16 *ut = NULL;
6210 glong items_written;
6212 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6214 if (!eg_error)
6215 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6216 else
6217 g_error_free (eg_error);
6219 g_free (ut);
6221 return o;
6225 * mono_string_new:
6226 * @text: a pointer to an utf8 string
6228 * Returns: A newly created string object which contains @text.
6230 * This function asserts if it cannot allocate a new string.
6232 * @deprecated Use mono_string_new_checked in new code.
6234 MonoString*
6235 mono_string_new (MonoDomain *domain, const char *text)
6237 MonoError error;
6238 MonoString *res = NULL;
6239 res = mono_string_new_checked (domain, text, &error);
6240 mono_error_assert_ok (&error);
6241 return res;
6245 * mono_string_new_checked:
6246 * @text: a pointer to an utf8 string
6247 * @merror: set on error
6249 * Returns: A newly created string object which contains @text.
6250 * On error returns NULL and sets @merror.
6252 MonoString*
6253 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6255 MONO_REQ_GC_UNSAFE_MODE;
6257 GError *eg_error = NULL;
6258 MonoString *o = NULL;
6259 guint16 *ut;
6260 glong items_written;
6261 int l;
6263 mono_error_init (error);
6265 l = strlen (text);
6267 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6269 if (!eg_error)
6270 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6271 else
6272 g_error_free (eg_error);
6274 g_free (ut);
6276 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6277 #if 0
6278 gunichar2 *str;
6279 const gchar *end;
6280 int len;
6281 MonoString *o = NULL;
6283 if (!g_utf8_validate (text, -1, &end)) {
6284 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6285 goto leave;
6288 len = g_utf8_strlen (text, -1);
6289 o = mono_string_new_size_checked (domain, len, error);
6290 if (!o)
6291 goto leave;
6292 str = mono_string_chars (o);
6294 while (text < end) {
6295 *str++ = g_utf8_get_char (text);
6296 text = g_utf8_next_char (text);
6299 leave:
6300 #endif
6301 return o;
6305 * mono_string_new_wrapper:
6306 * @text: pointer to utf8 characters.
6308 * Helper function to create a string object from @text in the current domain.
6310 MonoString*
6311 mono_string_new_wrapper (const char *text)
6313 MONO_REQ_GC_UNSAFE_MODE;
6315 MonoDomain *domain = mono_domain_get ();
6317 if (text)
6318 return mono_string_new (domain, text);
6320 return NULL;
6324 * mono_value_box:
6325 * @class: the class of the value
6326 * @value: a pointer to the unboxed data
6328 * Returns: A newly created object which contains @value.
6330 MonoObject *
6331 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6333 MonoError error;
6334 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6335 mono_error_cleanup (&error);
6336 return result;
6340 * mono_value_box_checked:
6341 * @domain: the domain of the new object
6342 * @class: the class of the value
6343 * @value: a pointer to the unboxed data
6344 * @error: set on error
6346 * Returns: A newly created object which contains @value. On failure
6347 * returns NULL and sets @error.
6349 MonoObject *
6350 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6352 MONO_REQ_GC_UNSAFE_MODE;
6353 MonoObject *res;
6354 int size;
6355 MonoVTable *vtable;
6357 mono_error_init (error);
6359 g_assert (klass->valuetype);
6360 if (mono_class_is_nullable (klass))
6361 return mono_nullable_box ((guint8 *)value, klass, error);
6363 vtable = mono_class_vtable (domain, klass);
6364 if (!vtable)
6365 return NULL;
6366 size = mono_class_instance_size (klass);
6367 res = mono_object_new_alloc_specific_checked (vtable, error);
6368 return_val_if_nok (error, NULL);
6370 size = size - sizeof (MonoObject);
6372 #ifdef HAVE_SGEN_GC
6373 g_assert (size == mono_class_value_size (klass, NULL));
6374 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6375 #else
6376 #if NO_UNALIGNED_ACCESS
6377 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6378 #else
6379 switch (size) {
6380 case 1:
6381 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6382 break;
6383 case 2:
6384 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6385 break;
6386 case 4:
6387 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6388 break;
6389 case 8:
6390 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6391 break;
6392 default:
6393 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6395 #endif
6396 #endif
6397 if (klass->has_finalize) {
6398 mono_object_register_finalizer (res);
6399 return_val_if_nok (error, NULL);
6401 return res;
6405 * mono_value_copy:
6406 * @dest: destination pointer
6407 * @src: source pointer
6408 * @klass: a valuetype class
6410 * Copy a valuetype from @src to @dest. This function must be used
6411 * when @klass contains references fields.
6413 void
6414 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6416 MONO_REQ_GC_UNSAFE_MODE;
6418 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6422 * mono_value_copy_array:
6423 * @dest: destination array
6424 * @dest_idx: index in the @dest array
6425 * @src: source pointer
6426 * @count: number of items
6428 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6429 * This function must be used when @klass contains references fields.
6430 * Overlap is handled.
6432 void
6433 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6435 MONO_REQ_GC_UNSAFE_MODE;
6437 int size = mono_array_element_size (dest->obj.vtable->klass);
6438 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6439 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6440 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6444 * mono_object_get_domain:
6445 * @obj: object to query
6447 * Returns: the MonoDomain where the object is hosted
6449 MonoDomain*
6450 mono_object_get_domain (MonoObject *obj)
6452 MONO_REQ_GC_UNSAFE_MODE;
6454 return mono_object_domain (obj);
6458 * mono_object_get_class:
6459 * @obj: object to query
6461 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6463 * Returns: the MonoClass of the object.
6465 MonoClass*
6466 mono_object_get_class (MonoObject *obj)
6468 MONO_REQ_GC_UNSAFE_MODE;
6470 return mono_object_class (obj);
6473 * mono_object_get_size:
6474 * @o: object to query
6476 * Returns: the size, in bytes, of @o
6478 guint
6479 mono_object_get_size (MonoObject* o)
6481 MONO_REQ_GC_UNSAFE_MODE;
6483 MonoClass* klass = mono_object_class (o);
6484 if (klass == mono_defaults.string_class) {
6485 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6486 } else if (o->vtable->rank) {
6487 MonoArray *array = (MonoArray*)o;
6488 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6489 if (array->bounds) {
6490 size += 3;
6491 size &= ~3;
6492 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6494 return size;
6495 } else {
6496 return mono_class_instance_size (klass);
6501 * mono_object_unbox:
6502 * @obj: object to unbox
6504 * Returns: a pointer to the start of the valuetype boxed in this
6505 * object.
6507 * This method will assert if the object passed is not a valuetype.
6509 gpointer
6510 mono_object_unbox (MonoObject *obj)
6512 MONO_REQ_GC_UNSAFE_MODE;
6514 /* add assert for valuetypes? */
6515 g_assert (obj->vtable->klass->valuetype);
6516 return ((char*)obj) + sizeof (MonoObject);
6520 * mono_object_isinst:
6521 * @obj: an object
6522 * @klass: a pointer to a class
6524 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6526 MonoObject *
6527 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6529 MONO_REQ_GC_UNSAFE_MODE;
6531 HANDLE_FUNCTION_ENTER ();
6532 MONO_HANDLE_DCL (MonoObject, obj);
6533 MonoError error;
6534 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6535 mono_error_cleanup (&error);
6536 HANDLE_FUNCTION_RETURN_OBJ (result);
6541 * mono_object_isinst_checked:
6542 * @obj: an object
6543 * @klass: a pointer to a class
6544 * @error: set on error
6546 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6547 * On failure returns NULL and sets @error.
6549 MonoObject *
6550 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6552 MONO_REQ_GC_UNSAFE_MODE;
6554 HANDLE_FUNCTION_ENTER ();
6555 mono_error_init (error);
6556 MONO_HANDLE_DCL (MonoObject, obj);
6557 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6558 HANDLE_FUNCTION_RETURN_OBJ (result);
6562 * mono_object_handle_isinst:
6563 * @obj: an object
6564 * @klass: a pointer to a class
6565 * @error: set on error
6567 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6568 * On failure returns NULL and sets @error.
6570 MonoObjectHandle
6571 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6573 mono_error_init (error);
6575 if (!klass->inited)
6576 mono_class_init (klass);
6578 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6579 return mono_object_handle_isinst_mbyref (obj, klass, error);
6582 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6584 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6585 MONO_HANDLE_ASSIGN (result, obj);
6586 return result;
6589 MonoObject *
6590 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6592 MONO_REQ_GC_UNSAFE_MODE;
6594 HANDLE_FUNCTION_ENTER ();
6595 MonoError error;
6596 MONO_HANDLE_DCL (MonoObject, obj);
6597 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6598 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6599 HANDLE_FUNCTION_RETURN_OBJ (result);
6602 MonoObjectHandle
6603 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6605 mono_error_init (error);
6607 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6609 if (MONO_HANDLE_IS_NULL (obj))
6610 goto leave;
6612 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6614 if (mono_class_is_interface (klass)) {
6615 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6616 MONO_HANDLE_ASSIGN (result, obj);
6617 goto leave;
6620 /* casting an array one of the invariant interfaces that must act as such */
6621 if (klass->is_array_special_interface) {
6622 if (mono_class_is_assignable_from (klass, vt->klass)) {
6623 MONO_HANDLE_ASSIGN (result, obj);
6624 goto leave;
6628 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6629 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6630 MONO_HANDLE_ASSIGN (result, obj);
6631 goto leave;
6633 } else {
6634 MonoClass *oklass = vt->klass;
6635 if (mono_class_is_transparent_proxy (oklass)){
6636 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6637 oklass = remote_class->proxy_class;
6640 mono_class_setup_supertypes (klass);
6641 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6642 MONO_HANDLE_ASSIGN (result, obj);
6643 goto leave;
6646 #ifndef DISABLE_REMOTING
6647 if (mono_class_is_transparent_proxy (vt->klass))
6649 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6650 if (!custom_type_info)
6651 goto leave;
6652 MonoDomain *domain = mono_domain_get ();
6653 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6654 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6655 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6656 MonoMethod *im = NULL;
6657 gpointer pa [2];
6659 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6660 if (!im) {
6661 mono_error_set_not_supported (error, "Linked away.");
6662 goto leave;
6664 im = mono_object_handle_get_virtual_method (rp, im, error);
6665 if (!is_ok (error))
6666 goto leave;
6667 g_assert (im);
6669 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6670 if (!is_ok (error))
6671 goto leave;
6673 pa [0] = MONO_HANDLE_RAW (reftype);
6674 pa [1] = MONO_HANDLE_RAW (obj);
6675 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6676 if (!is_ok (error))
6677 goto leave;
6679 if (*(MonoBoolean *) mono_object_unbox(res)) {
6680 /* Update the vtable of the remote type, so it can safely cast to this new type */
6681 mono_upgrade_remote_class (domain, obj, klass, error);
6682 if (!is_ok (error))
6683 goto leave;
6684 MONO_HANDLE_ASSIGN (result, obj);
6687 #endif /* DISABLE_REMOTING */
6688 leave:
6689 return result;
6693 * mono_object_castclass_mbyref:
6694 * @obj: an object
6695 * @klass: a pointer to a class
6697 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6699 MonoObject *
6700 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6702 MONO_REQ_GC_UNSAFE_MODE;
6703 HANDLE_FUNCTION_ENTER ();
6704 MonoError error;
6705 MONO_HANDLE_DCL (MonoObject, obj);
6706 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6707 if (MONO_HANDLE_IS_NULL (obj))
6708 goto leave;
6709 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6710 mono_error_cleanup (&error);
6711 leave:
6712 HANDLE_FUNCTION_RETURN_OBJ (result);
6715 typedef struct {
6716 MonoDomain *orig_domain;
6717 MonoString *ins;
6718 MonoString *res;
6719 } LDStrInfo;
6721 static void
6722 str_lookup (MonoDomain *domain, gpointer user_data)
6724 MONO_REQ_GC_UNSAFE_MODE;
6726 LDStrInfo *info = (LDStrInfo *)user_data;
6727 if (info->res || domain == info->orig_domain)
6728 return;
6729 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6732 static MonoString*
6733 mono_string_get_pinned (MonoString *str, MonoError *error)
6735 MONO_REQ_GC_UNSAFE_MODE;
6737 mono_error_init (error);
6739 /* We only need to make a pinned version of a string if this is a moving GC */
6740 if (!mono_gc_is_moving ())
6741 return str;
6742 int size;
6743 MonoString *news;
6744 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6745 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6746 if (news) {
6747 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6748 news->length = mono_string_length (str);
6749 } else {
6750 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6752 return news;
6755 static MonoString*
6756 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6758 MONO_REQ_GC_UNSAFE_MODE;
6760 MonoGHashTable *ldstr_table;
6761 MonoString *s, *res;
6762 MonoDomain *domain;
6764 mono_error_init (error);
6766 domain = ((MonoObject *)str)->vtable->domain;
6767 ldstr_table = domain->ldstr_table;
6768 ldstr_lock ();
6769 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6770 if (res) {
6771 ldstr_unlock ();
6772 return res;
6774 if (insert) {
6775 /* Allocate outside the lock */
6776 ldstr_unlock ();
6777 s = mono_string_get_pinned (str, error);
6778 return_val_if_nok (error, NULL);
6779 if (s) {
6780 ldstr_lock ();
6781 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6782 if (res) {
6783 ldstr_unlock ();
6784 return res;
6786 mono_g_hash_table_insert (ldstr_table, s, s);
6787 ldstr_unlock ();
6789 return s;
6790 } else {
6791 LDStrInfo ldstr_info;
6792 ldstr_info.orig_domain = domain;
6793 ldstr_info.ins = str;
6794 ldstr_info.res = NULL;
6796 mono_domain_foreach (str_lookup, &ldstr_info);
6797 if (ldstr_info.res) {
6799 * the string was already interned in some other domain:
6800 * intern it in the current one as well.
6802 mono_g_hash_table_insert (ldstr_table, str, str);
6803 ldstr_unlock ();
6804 return str;
6807 ldstr_unlock ();
6808 return NULL;
6812 * mono_string_is_interned:
6813 * @o: String to probe
6815 * Returns whether the string has been interned.
6817 MonoString*
6818 mono_string_is_interned (MonoString *o)
6820 MonoError error;
6821 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6822 /* This function does not fail. */
6823 mono_error_assert_ok (&error);
6824 return result;
6828 * mono_string_intern:
6829 * @o: String to intern
6831 * Interns the string passed.
6832 * Returns: The interned string.
6834 MonoString*
6835 mono_string_intern (MonoString *str)
6837 MonoError error;
6838 MonoString *result = mono_string_intern_checked (str, &error);
6839 mono_error_assert_ok (&error);
6840 return result;
6844 * mono_string_intern_checked:
6845 * @o: String to intern
6846 * @error: set on error.
6848 * Interns the string passed.
6849 * Returns: The interned string. On failure returns NULL and sets @error
6851 MonoString*
6852 mono_string_intern_checked (MonoString *str, MonoError *error)
6854 MONO_REQ_GC_UNSAFE_MODE;
6856 mono_error_init (error);
6858 return mono_string_is_interned_lookup (str, TRUE, error);
6862 * mono_ldstr:
6863 * @domain: the domain where the string will be used.
6864 * @image: a metadata context
6865 * @idx: index into the user string table.
6867 * Implementation for the ldstr opcode.
6868 * Returns: a loaded string from the @image/@idx combination.
6870 MonoString*
6871 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6873 MonoError error;
6874 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6875 mono_error_cleanup (&error);
6876 return result;
6880 * mono_ldstr_checked:
6881 * @domain: the domain where the string will be used.
6882 * @image: a metadata context
6883 * @idx: index into the user string table.
6884 * @error: set on error.
6886 * Implementation for the ldstr opcode.
6887 * Returns: a loaded string from the @image/@idx combination.
6888 * On failure returns NULL and sets @error.
6890 MonoString*
6891 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6893 MONO_REQ_GC_UNSAFE_MODE;
6894 mono_error_init (error);
6896 if (image->dynamic) {
6897 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6898 return str;
6899 } else {
6900 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6901 return NULL; /*FIXME we should probably be raising an exception here*/
6902 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6903 return str;
6908 * mono_ldstr_metadata_sig
6909 * @domain: the domain for the string
6910 * @sig: the signature of a metadata string
6911 * @error: set on error
6913 * Returns: a MonoString for a string stored in the metadata. On
6914 * failure returns NULL and sets @error.
6916 static MonoString*
6917 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6919 MONO_REQ_GC_UNSAFE_MODE;
6921 mono_error_init (error);
6922 const char *str = sig;
6923 MonoString *o, *interned;
6924 size_t len2;
6926 len2 = mono_metadata_decode_blob_size (str, &str);
6927 len2 >>= 1;
6929 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6930 return_val_if_nok (error, NULL);
6931 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6933 int i;
6934 guint16 *p2 = (guint16*)mono_string_chars (o);
6935 for (i = 0; i < len2; ++i) {
6936 *p2 = GUINT16_FROM_LE (*p2);
6937 ++p2;
6940 #endif
6941 ldstr_lock ();
6942 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6943 ldstr_unlock ();
6944 if (interned)
6945 return interned; /* o will get garbage collected */
6947 o = mono_string_get_pinned (o, error);
6948 if (o) {
6949 ldstr_lock ();
6950 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6951 if (!interned) {
6952 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6953 interned = o;
6955 ldstr_unlock ();
6958 return interned;
6962 * mono_ldstr_utf8:
6964 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6965 * of an object.
6967 char*
6968 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6970 const char *str;
6971 size_t len2;
6972 long written = 0;
6973 char *as;
6974 GError *gerror = NULL;
6976 mono_error_init (error);
6978 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6979 return NULL; /*FIXME we should probably be raising an exception here*/
6980 str = mono_metadata_user_string (image, idx);
6982 len2 = mono_metadata_decode_blob_size (str, &str);
6983 len2 >>= 1;
6985 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6986 if (gerror) {
6987 mono_error_set_argument (error, "string", "%s", gerror->message);
6988 g_error_free (gerror);
6989 return NULL;
6991 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6992 if (len2 > written) {
6993 /* allocate the total length and copy the part of the string that has been converted */
6994 char *as2 = (char *)g_malloc0 (len2);
6995 memcpy (as2, as, written);
6996 g_free (as);
6997 as = as2;
7000 return as;
7004 * mono_string_to_utf8:
7005 * @s: a System.String
7007 * Returns the UTF8 representation for @s.
7008 * The resulting buffer needs to be freed with mono_free().
7010 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7012 char *
7013 mono_string_to_utf8 (MonoString *s)
7015 MONO_REQ_GC_UNSAFE_MODE;
7017 MonoError error;
7018 char *result = mono_string_to_utf8_checked (s, &error);
7020 if (!is_ok (&error)) {
7021 mono_error_cleanup (&error);
7022 return NULL;
7024 return result;
7028 * mono_string_to_utf8_checked:
7029 * @s: a System.String
7030 * @error: a MonoError.
7032 * Converts a MonoString to its UTF8 representation. May fail; check
7033 * @error to determine whether the conversion was successful.
7034 * The resulting buffer should be freed with mono_free().
7036 char *
7037 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7039 MONO_REQ_GC_UNSAFE_MODE;
7041 long written = 0;
7042 char *as;
7043 GError *gerror = NULL;
7045 mono_error_init (error);
7047 if (s == NULL)
7048 return NULL;
7050 if (!s->length)
7051 return g_strdup ("");
7053 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7054 if (gerror) {
7055 mono_error_set_argument (error, "string", "%s", gerror->message);
7056 g_error_free (gerror);
7057 return NULL;
7059 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7060 if (s->length > written) {
7061 /* allocate the total length and copy the part of the string that has been converted */
7062 char *as2 = (char *)g_malloc0 (s->length);
7063 memcpy (as2, as, written);
7064 g_free (as);
7065 as = as2;
7068 return as;
7071 char *
7072 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7074 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7078 * mono_string_to_utf8_ignore:
7079 * @s: a MonoString
7081 * Converts a MonoString to its UTF8 representation. Will ignore
7082 * invalid surrogate pairs.
7083 * The resulting buffer should be freed with mono_free().
7086 char *
7087 mono_string_to_utf8_ignore (MonoString *s)
7089 MONO_REQ_GC_UNSAFE_MODE;
7091 long written = 0;
7092 char *as;
7094 if (s == NULL)
7095 return NULL;
7097 if (!s->length)
7098 return g_strdup ("");
7100 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7102 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7103 if (s->length > written) {
7104 /* allocate the total length and copy the part of the string that has been converted */
7105 char *as2 = (char *)g_malloc0 (s->length);
7106 memcpy (as2, as, written);
7107 g_free (as);
7108 as = as2;
7111 return as;
7115 * mono_string_to_utf8_image_ignore:
7116 * @s: a System.String
7118 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7120 char *
7121 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7123 MONO_REQ_GC_UNSAFE_MODE;
7125 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7129 * mono_string_to_utf8_mp_ignore:
7130 * @s: a System.String
7132 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7134 char *
7135 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7137 MONO_REQ_GC_UNSAFE_MODE;
7139 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7144 * mono_string_to_utf16:
7145 * @s: a MonoString
7147 * Return an null-terminated array of the utf-16 chars
7148 * contained in @s. The result must be freed with g_free().
7149 * This is a temporary helper until our string implementation
7150 * is reworked to always include the null terminating char.
7152 mono_unichar2*
7153 mono_string_to_utf16 (MonoString *s)
7155 MONO_REQ_GC_UNSAFE_MODE;
7157 char *as;
7159 if (s == NULL)
7160 return NULL;
7162 as = (char *)g_malloc ((s->length * 2) + 2);
7163 as [(s->length * 2)] = '\0';
7164 as [(s->length * 2) + 1] = '\0';
7166 if (!s->length) {
7167 return (gunichar2 *)(as);
7170 memcpy (as, mono_string_chars(s), s->length * 2);
7171 return (gunichar2 *)(as);
7175 * mono_string_to_utf32:
7176 * @s: a MonoString
7178 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7179 * contained in @s. The result must be freed with g_free().
7181 mono_unichar4*
7182 mono_string_to_utf32 (MonoString *s)
7184 MONO_REQ_GC_UNSAFE_MODE;
7186 mono_unichar4 *utf32_output = NULL;
7187 GError *error = NULL;
7188 glong items_written;
7190 if (s == NULL)
7191 return NULL;
7193 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7195 if (error)
7196 g_error_free (error);
7198 return utf32_output;
7202 * mono_string_from_utf16:
7203 * @data: the UTF16 string (LPWSTR) to convert
7205 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7207 * Returns: a MonoString.
7209 MonoString *
7210 mono_string_from_utf16 (gunichar2 *data)
7212 MonoError error;
7213 MonoString *result = mono_string_from_utf16_checked (data, &error);
7214 mono_error_cleanup (&error);
7215 return result;
7219 * mono_string_from_utf16_checked:
7220 * @data: the UTF16 string (LPWSTR) to convert
7221 * @error: set on error
7223 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7225 * Returns: a MonoString. On failure sets @error and returns NULL.
7227 MonoString *
7228 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7231 MONO_REQ_GC_UNSAFE_MODE;
7233 mono_error_init (error);
7234 MonoDomain *domain = mono_domain_get ();
7235 int len = 0;
7237 if (!data)
7238 return NULL;
7240 while (data [len]) len++;
7242 return mono_string_new_utf16_checked (domain, data, len, error);
7246 * mono_string_from_utf32:
7247 * @data: the UTF32 string (LPWSTR) to convert
7249 * Converts a UTF32 (UCS-4)to a MonoString.
7251 * Returns: a MonoString.
7253 MonoString *
7254 mono_string_from_utf32 (mono_unichar4 *data)
7256 MonoError error;
7257 MonoString *result = mono_string_from_utf32_checked (data, &error);
7258 mono_error_cleanup (&error);
7259 return result;
7263 * mono_string_from_utf32_checked:
7264 * @data: the UTF32 string (LPWSTR) to convert
7265 * @error: set on error
7267 * Converts a UTF32 (UCS-4)to a MonoString.
7269 * Returns: a MonoString. On failure returns NULL and sets @error.
7271 MonoString *
7272 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7274 MONO_REQ_GC_UNSAFE_MODE;
7276 mono_error_init (error);
7277 MonoString* result = NULL;
7278 mono_unichar2 *utf16_output = NULL;
7279 GError *gerror = NULL;
7280 glong items_written;
7281 int len = 0;
7283 if (!data)
7284 return NULL;
7286 while (data [len]) len++;
7288 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7290 if (gerror)
7291 g_error_free (gerror);
7293 result = mono_string_from_utf16_checked (utf16_output, error);
7294 g_free (utf16_output);
7295 return result;
7298 static char *
7299 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7301 MONO_REQ_GC_UNSAFE_MODE;
7303 char *r;
7304 char *mp_s;
7305 int len;
7307 if (ignore_error) {
7308 r = mono_string_to_utf8_ignore (s);
7309 } else {
7310 r = mono_string_to_utf8_checked (s, error);
7311 if (!mono_error_ok (error))
7312 return NULL;
7315 if (!mp && !image)
7316 return r;
7318 len = strlen (r) + 1;
7319 if (mp)
7320 mp_s = (char *)mono_mempool_alloc (mp, len);
7321 else
7322 mp_s = (char *)mono_image_alloc (image, len);
7324 memcpy (mp_s, r, len);
7326 g_free (r);
7328 return mp_s;
7332 * mono_string_to_utf8_image:
7333 * @s: a System.String
7335 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7337 char *
7338 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7340 MONO_REQ_GC_UNSAFE_MODE;
7342 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7346 * mono_string_to_utf8_mp:
7347 * @s: a System.String
7349 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7351 char *
7352 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7354 MONO_REQ_GC_UNSAFE_MODE;
7356 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7360 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7362 void
7363 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7365 eh_callbacks = *cbs;
7368 MonoRuntimeExceptionHandlingCallbacks *
7369 mono_get_eh_callbacks (void)
7371 return &eh_callbacks;
7375 * mono_raise_exception:
7376 * @ex: exception object
7378 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7380 void
7381 mono_raise_exception (MonoException *ex)
7383 MONO_REQ_GC_UNSAFE_MODE;
7386 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7387 * that will cause gcc to omit the function epilog, causing problems when
7388 * the JIT tries to walk the stack, since the return address on the stack
7389 * will point into the next function in the executable, not this one.
7391 eh_callbacks.mono_raise_exception (ex);
7394 void
7395 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7397 MONO_REQ_GC_UNSAFE_MODE;
7399 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7403 * mono_wait_handle_new:
7404 * @domain: Domain where the object will be created
7405 * @handle: Handle for the wait handle
7406 * @error: set on error.
7408 * Returns: A new MonoWaitHandle created in the given domain for the
7409 * given handle. On failure returns NULL and sets @rror.
7411 MonoWaitHandle *
7412 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7414 MONO_REQ_GC_UNSAFE_MODE;
7416 MonoWaitHandle *res;
7417 gpointer params [1];
7418 static MonoMethod *handle_set;
7420 mono_error_init (error);
7421 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7422 return_val_if_nok (error, NULL);
7424 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7425 if (!handle_set)
7426 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7428 params [0] = &handle;
7430 mono_runtime_invoke_checked (handle_set, res, params, error);
7431 return res;
7434 HANDLE
7435 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7437 MONO_REQ_GC_UNSAFE_MODE;
7439 static MonoClassField *f_safe_handle = NULL;
7440 MonoSafeHandle *sh;
7442 if (!f_safe_handle) {
7443 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7444 g_assert (f_safe_handle);
7447 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7448 return sh->handle;
7452 static MonoObject*
7453 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7455 MONO_REQ_GC_UNSAFE_MODE;
7457 RuntimeInvokeFunction runtime_invoke;
7459 mono_error_init (error);
7461 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7462 MonoMethod *method = mono_get_context_capture_method ();
7463 MonoMethod *wrapper;
7464 if (!method)
7465 return NULL;
7466 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7467 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7468 return_val_if_nok (error, NULL);
7469 domain->capture_context_method = mono_compile_method_checked (method, error);
7470 return_val_if_nok (error, NULL);
7473 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7475 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7478 * mono_async_result_new:
7479 * @domain:domain where the object will be created.
7480 * @handle: wait handle.
7481 * @state: state to pass to AsyncResult
7482 * @data: C closure data.
7483 * @error: set on error.
7485 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7486 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7487 * On failure returns NULL and sets @error.
7490 MonoAsyncResult *
7491 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7493 MONO_REQ_GC_UNSAFE_MODE;
7495 mono_error_init (error);
7496 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7497 return_val_if_nok (error, NULL);
7498 MonoObject *context = mono_runtime_capture_context (domain, error);
7499 return_val_if_nok (error, NULL);
7500 /* we must capture the execution context from the original thread */
7501 if (context) {
7502 MONO_OBJECT_SETREF (res, execution_context, context);
7503 /* note: result may be null if the flow is suppressed */
7506 res->data = (void **)data;
7507 MONO_OBJECT_SETREF (res, object_data, object_data);
7508 MONO_OBJECT_SETREF (res, async_state, state);
7509 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7510 return_val_if_nok (error, NULL);
7511 if (handle != NULL)
7512 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7514 res->sync_completed = FALSE;
7515 res->completed = FALSE;
7517 return res;
7520 MonoObject *
7521 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7523 MONO_REQ_GC_UNSAFE_MODE;
7525 MonoError error;
7526 MonoAsyncCall *ac;
7527 MonoObject *res;
7529 g_assert (ares);
7530 g_assert (ares->async_delegate);
7532 ac = (MonoAsyncCall*) ares->object_data;
7533 if (!ac) {
7534 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7535 if (mono_error_set_pending_exception (&error))
7536 return NULL;
7537 } else {
7538 gpointer wait_event = NULL;
7540 ac->msg->exc = NULL;
7542 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7544 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7545 mono_threads_begin_abort_protected_block ();
7547 if (!ac->msg->exc) {
7548 MonoException *ex = mono_error_convert_to_exception (&error);
7549 ac->msg->exc = (MonoObject *)ex;
7550 } else {
7551 mono_error_cleanup (&error);
7554 MONO_OBJECT_SETREF (ac, res, res);
7556 mono_monitor_enter ((MonoObject*) ares);
7557 ares->completed = 1;
7558 if (ares->handle)
7559 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7560 mono_monitor_exit ((MonoObject*) ares);
7562 if (wait_event != NULL)
7563 mono_w32event_set (wait_event);
7565 mono_error_init (&error); //the else branch would leave it in an undefined state
7566 if (ac->cb_method)
7567 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7569 mono_threads_end_abort_protected_block ();
7571 if (mono_error_set_pending_exception (&error))
7572 return NULL;
7575 return res;
7578 gboolean
7579 mono_message_init (MonoDomain *domain,
7580 MonoMethodMessage *this_obj,
7581 MonoReflectionMethod *method,
7582 MonoArray *out_args,
7583 MonoError *error)
7585 MONO_REQ_GC_UNSAFE_MODE;
7587 static MonoMethod *init_message_method = NULL;
7589 if (!init_message_method) {
7590 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7591 g_assert (init_message_method != NULL);
7594 mono_error_init (error);
7595 /* FIXME set domain instead? */
7596 g_assert (domain == mono_domain_get ());
7598 gpointer args[2];
7600 args[0] = method;
7601 args[1] = out_args;
7603 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7604 return is_ok (error);
7607 #ifndef DISABLE_REMOTING
7609 * mono_remoting_invoke:
7610 * @real_proxy: pointer to a RealProxy object
7611 * @msg: The MonoMethodMessage to execute
7612 * @exc: used to store exceptions
7613 * @out_args: used to store output arguments
7615 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7616 * IMessage interface and it is not trivial to extract results from there. So
7617 * we call an helper method PrivateInvoke instead of calling
7618 * RealProxy::Invoke() directly.
7620 * Returns: the result object.
7622 MonoObject *
7623 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7625 MONO_REQ_GC_UNSAFE_MODE;
7627 MonoObject *o;
7628 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7629 gpointer pa [4];
7631 g_assert (exc);
7633 mono_error_init (error);
7635 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7637 if (!im) {
7638 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7639 if (!im) {
7640 mono_error_set_not_supported (error, "Linked away.");
7641 return NULL;
7643 real_proxy->vtable->domain->private_invoke_method = im;
7646 pa [0] = real_proxy;
7647 pa [1] = msg;
7648 pa [2] = exc;
7649 pa [3] = out_args;
7651 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7652 return_val_if_nok (error, NULL);
7654 return o;
7656 #endif
7658 MonoObject *
7659 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7660 MonoObject **exc, MonoArray **out_args, MonoError *error)
7662 MONO_REQ_GC_UNSAFE_MODE;
7664 static MonoClass *object_array_klass;
7665 mono_error_init (error);
7667 MonoDomain *domain;
7668 MonoMethod *method;
7669 MonoMethodSignature *sig;
7670 MonoArray *arr;
7671 int i, j, outarg_count = 0;
7673 #ifndef DISABLE_REMOTING
7674 if (target && mono_object_is_transparent_proxy (target)) {
7675 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7676 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7677 target = tp->rp->unwrapped_server;
7678 } else {
7679 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7682 #endif
7684 domain = mono_domain_get ();
7685 method = msg->method->method;
7686 sig = mono_method_signature (method);
7688 for (i = 0; i < sig->param_count; i++) {
7689 if (sig->params [i]->byref)
7690 outarg_count++;
7693 if (!object_array_klass) {
7694 MonoClass *klass;
7696 klass = mono_array_class_get (mono_defaults.object_class, 1);
7697 g_assert (klass);
7699 mono_memory_barrier ();
7700 object_array_klass = klass;
7703 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7704 return_val_if_nok (error, NULL);
7706 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7707 *exc = NULL;
7709 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7710 return_val_if_nok (error, NULL);
7712 for (i = 0, j = 0; i < sig->param_count; i++) {
7713 if (sig->params [i]->byref) {
7714 MonoObject* arg;
7715 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7716 mono_array_setref (*out_args, j, arg);
7717 j++;
7721 return ret;
7725 * prepare_to_string_method:
7726 * @obj: The object
7727 * @target: Set to @obj or unboxed value if a valuetype
7729 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7731 static MonoMethod *
7732 prepare_to_string_method (MonoObject *obj, void **target)
7734 MONO_REQ_GC_UNSAFE_MODE;
7736 static MonoMethod *to_string = NULL;
7737 MonoMethod *method;
7738 g_assert (target);
7739 g_assert (obj);
7741 *target = obj;
7743 if (!to_string)
7744 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7746 method = mono_object_get_virtual_method (obj, to_string);
7748 // Unbox value type if needed
7749 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7750 *target = mono_object_unbox (obj);
7752 return method;
7756 * mono_object_to_string:
7757 * @obj: The object
7758 * @exc: Any exception thrown by ToString (). May be NULL.
7760 * Returns: the result of calling ToString () on an object.
7762 MonoString *
7763 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7765 MonoError error;
7766 MonoString *s = NULL;
7767 void *target;
7768 MonoMethod *method = prepare_to_string_method (obj, &target);
7769 if (exc) {
7770 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7771 if (*exc == NULL && !mono_error_ok (&error))
7772 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7773 else
7774 mono_error_cleanup (&error);
7775 } else {
7776 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7777 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7780 return s;
7784 * mono_object_to_string_checked:
7785 * @obj: The object
7786 * @error: Set on error.
7788 * Returns: the result of calling ToString () on an object. If the
7789 * method cannot be invoked or if it raises an exception, sets @error
7790 * and returns NULL.
7792 MonoString *
7793 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7795 mono_error_init (error);
7796 void *target;
7797 MonoMethod *method = prepare_to_string_method (obj, &target);
7798 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7802 * mono_object_try_to_string:
7803 * @obj: The object
7804 * @exc: Any exception thrown by ToString (). Must not be NULL.
7805 * @error: Set if method cannot be invoked.
7807 * Returns: the result of calling ToString () on an object. If the
7808 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7809 * and returns NULL.
7811 MonoString *
7812 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7814 g_assert (exc);
7815 mono_error_init (error);
7816 void *target;
7817 MonoMethod *method = prepare_to_string_method (obj, &target);
7818 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7823 static char *
7824 get_native_backtrace (MonoException *exc_raw)
7826 HANDLE_FUNCTION_ENTER ();
7827 MONO_HANDLE_DCL(MonoException, exc);
7828 char * trace = mono_exception_handle_get_native_backtrace (exc);
7829 HANDLE_FUNCTION_RETURN_VAL (trace);
7833 * mono_print_unhandled_exception:
7834 * @exc: The exception
7836 * Prints the unhandled exception.
7838 void
7839 mono_print_unhandled_exception (MonoObject *exc)
7841 MONO_REQ_GC_UNSAFE_MODE;
7843 MonoString * str;
7844 char *message = (char*)"";
7845 gboolean free_message = FALSE;
7846 MonoError error;
7848 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7849 message = g_strdup ("OutOfMemoryException");
7850 free_message = TRUE;
7851 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7852 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7853 free_message = TRUE;
7854 } else {
7856 if (((MonoException*)exc)->native_trace_ips) {
7857 message = get_native_backtrace ((MonoException*)exc);
7858 free_message = TRUE;
7859 } else {
7860 MonoObject *other_exc = NULL;
7861 str = mono_object_try_to_string (exc, &other_exc, &error);
7862 if (other_exc == NULL && !is_ok (&error))
7863 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7864 else
7865 mono_error_cleanup (&error);
7866 if (other_exc) {
7867 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7868 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7870 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7871 original_backtrace, nested_backtrace);
7873 g_free (original_backtrace);
7874 g_free (nested_backtrace);
7875 free_message = TRUE;
7876 } else if (str) {
7877 message = mono_string_to_utf8_checked (str, &error);
7878 if (!mono_error_ok (&error)) {
7879 mono_error_cleanup (&error);
7880 message = (char *) "";
7881 } else {
7882 free_message = TRUE;
7889 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7890 * exc->vtable->klass->name, message);
7892 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7894 if (free_message)
7895 g_free (message);
7899 * mono_delegate_ctor_with_method:
7900 * @this: pointer to an uninitialized delegate object
7901 * @target: target object
7902 * @addr: pointer to native code
7903 * @method: method
7904 * @error: set on error.
7906 * Initialize a delegate and sets a specific method, not the one
7907 * associated with addr. This is useful when sharing generic code.
7908 * In that case addr will most probably not be associated with the
7909 * correct instantiation of the method.
7910 * On failure returns FALSE and sets @error.
7912 gboolean
7913 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7915 MONO_REQ_GC_UNSAFE_MODE;
7917 mono_error_init (error);
7918 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7920 g_assert (this_obj);
7921 g_assert (addr);
7923 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7925 if (method)
7926 delegate->method = method;
7928 mono_stats.delegate_creations++;
7930 #ifndef DISABLE_REMOTING
7931 if (target && mono_object_is_transparent_proxy (target)) {
7932 g_assert (method);
7933 method = mono_marshal_get_remoting_invoke (method);
7934 delegate->method_ptr = mono_compile_method_checked (method, error);
7935 return_val_if_nok (error, FALSE);
7936 MONO_OBJECT_SETREF (delegate, target, target);
7937 } else
7938 #endif
7940 delegate->method_ptr = addr;
7941 MONO_OBJECT_SETREF (delegate, target, target);
7944 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7945 if (callbacks.init_delegate)
7946 callbacks.init_delegate (delegate);
7947 return TRUE;
7951 * mono_delegate_ctor:
7952 * @this: pointer to an uninitialized delegate object
7953 * @target: target object
7954 * @addr: pointer to native code
7955 * @error: set on error.
7957 * This is used to initialize a delegate.
7958 * On failure returns FALSE and sets @error.
7960 gboolean
7961 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7963 MONO_REQ_GC_UNSAFE_MODE;
7965 mono_error_init (error);
7966 MonoDomain *domain = mono_domain_get ();
7967 MonoJitInfo *ji;
7968 MonoMethod *method = NULL;
7970 g_assert (addr);
7972 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7973 /* Shared code */
7974 if (!ji && domain != mono_get_root_domain ())
7975 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7976 if (ji) {
7977 method = mono_jit_info_get_method (ji);
7978 g_assert (!mono_class_is_gtd (method->klass));
7981 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7985 * mono_method_call_message_new:
7986 * @method: method to encapsulate
7987 * @params: parameters to the method
7988 * @invoke: optional, delegate invoke.
7989 * @cb: async callback delegate.
7990 * @state: state passed to the async callback.
7991 * @error: set on error.
7993 * Translates arguments pointers into a MonoMethodMessage.
7994 * On failure returns NULL and sets @error.
7996 MonoMethodMessage *
7997 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7998 MonoDelegate **cb, MonoObject **state, MonoError *error)
8000 MONO_REQ_GC_UNSAFE_MODE;
8002 mono_error_init (error);
8004 MonoDomain *domain = mono_domain_get ();
8005 MonoMethodSignature *sig = mono_method_signature (method);
8006 MonoMethodMessage *msg;
8007 int i, count;
8009 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8010 return_val_if_nok (error, NULL);
8012 if (invoke) {
8013 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8014 return_val_if_nok (error, NULL);
8015 mono_message_init (domain, msg, rm, NULL, error);
8016 return_val_if_nok (error, NULL);
8017 count = sig->param_count - 2;
8018 } else {
8019 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8020 return_val_if_nok (error, NULL);
8021 mono_message_init (domain, msg, rm, NULL, error);
8022 return_val_if_nok (error, NULL);
8023 count = sig->param_count;
8026 for (i = 0; i < count; i++) {
8027 gpointer vpos;
8028 MonoClass *klass;
8029 MonoObject *arg;
8031 if (sig->params [i]->byref)
8032 vpos = *((gpointer *)params [i]);
8033 else
8034 vpos = params [i];
8036 klass = mono_class_from_mono_type (sig->params [i]);
8038 if (klass->valuetype) {
8039 arg = mono_value_box_checked (domain, klass, vpos, error);
8040 return_val_if_nok (error, NULL);
8041 } else
8042 arg = *((MonoObject **)vpos);
8044 mono_array_setref (msg->args, i, arg);
8047 if (cb != NULL && state != NULL) {
8048 *cb = *((MonoDelegate **)params [i]);
8049 i++;
8050 *state = *((MonoObject **)params [i]);
8053 return msg;
8057 * mono_method_return_message_restore:
8059 * Restore results from message based processing back to arguments pointers
8061 void
8062 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8064 MONO_REQ_GC_UNSAFE_MODE;
8066 mono_error_init (error);
8068 MonoMethodSignature *sig = mono_method_signature (method);
8069 int i, j, type, size, out_len;
8071 if (out_args == NULL)
8072 return;
8073 out_len = mono_array_length (out_args);
8074 if (out_len == 0)
8075 return;
8077 for (i = 0, j = 0; i < sig->param_count; i++) {
8078 MonoType *pt = sig->params [i];
8080 if (pt->byref) {
8081 char *arg;
8082 if (j >= out_len) {
8083 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8084 return;
8087 arg = (char *)mono_array_get (out_args, gpointer, j);
8088 type = pt->type;
8090 g_assert (type != MONO_TYPE_VOID);
8092 if (MONO_TYPE_IS_REFERENCE (pt)) {
8093 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8094 } else {
8095 if (arg) {
8096 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8097 size = mono_class_value_size (klass, NULL);
8098 if (klass->has_references)
8099 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8100 else
8101 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8102 } else {
8103 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8104 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8108 j++;
8113 #ifndef DISABLE_REMOTING
8116 * mono_load_remote_field:
8117 * @this: pointer to an object
8118 * @klass: klass of the object containing @field
8119 * @field: the field to load
8120 * @res: a storage to store the result
8122 * This method is called by the runtime on attempts to load fields of
8123 * transparent proxy objects. @this points to such TP, @klass is the class of
8124 * the object containing @field. @res is a storage location which can be
8125 * used to store the result.
8127 * Returns: an address pointing to the value of field.
8129 gpointer
8130 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8132 MonoError error;
8133 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8134 mono_error_cleanup (&error);
8135 return result;
8139 * mono_load_remote_field_checked:
8140 * @this: pointer to an object
8141 * @klass: klass of the object containing @field
8142 * @field: the field to load
8143 * @res: a storage to store the result
8144 * @error: set on error
8146 * This method is called by the runtime on attempts to load fields of
8147 * transparent proxy objects. @this points to such TP, @klass is the class of
8148 * the object containing @field. @res is a storage location which can be
8149 * used to store the result.
8151 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8153 gpointer
8154 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8156 MONO_REQ_GC_UNSAFE_MODE;
8158 static MonoMethod *getter = NULL;
8160 mono_error_init (error);
8162 MonoDomain *domain = mono_domain_get ();
8163 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8164 MonoClass *field_class;
8165 MonoMethodMessage *msg;
8166 MonoArray *out_args;
8167 MonoObject *exc;
8168 char* full_name;
8170 g_assert (mono_object_is_transparent_proxy (this_obj));
8171 g_assert (res != NULL);
8173 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8174 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8175 return res;
8178 if (!getter) {
8179 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8180 if (!getter) {
8181 mono_error_set_not_supported (error, "Linked away.");
8182 return NULL;
8186 field_class = mono_class_from_mono_type (field->type);
8188 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8189 return_val_if_nok (error, NULL);
8190 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8191 return_val_if_nok (error, NULL);
8192 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8193 return_val_if_nok (error, NULL);
8194 mono_message_init (domain, msg, rm, out_args, error);
8195 return_val_if_nok (error, NULL);
8197 full_name = mono_type_get_full_name (klass);
8198 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8199 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8200 g_free (full_name);
8202 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8203 return_val_if_nok (error, NULL);
8205 if (exc) {
8206 mono_error_set_exception_instance (error, (MonoException *)exc);
8207 return NULL;
8210 if (mono_array_length (out_args) == 0)
8211 return NULL;
8213 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8215 if (field_class->valuetype) {
8216 return ((char *)*res) + sizeof (MonoObject);
8217 } else
8218 return res;
8222 * mono_load_remote_field_new:
8223 * @this:
8224 * @klass:
8225 * @field:
8227 * Missing documentation.
8229 MonoObject *
8230 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8232 MonoError error;
8234 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8235 mono_error_cleanup (&error);
8236 return result;
8240 * mono_load_remote_field_new_checked:
8241 * @this: pointer to an object
8242 * @klass: klass of the object containing @field
8243 * @field: the field to load
8244 * @error: set on error.
8246 * This method is called by the runtime on attempts to load fields of
8247 * transparent proxy objects. @this points to such TP, @klass is the class of
8248 * the object containing @field.
8250 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8252 MonoObject *
8253 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8255 MONO_REQ_GC_UNSAFE_MODE;
8257 mono_error_init (error);
8259 static MonoMethod *tp_load = NULL;
8261 g_assert (mono_object_is_transparent_proxy (this_obj));
8263 if (!tp_load) {
8264 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8265 if (!tp_load) {
8266 mono_error_set_not_supported (error, "Linked away.");
8267 return NULL;
8271 /* MonoType *type = mono_class_get_type (klass); */
8273 gpointer args[2];
8274 args [0] = &klass;
8275 args [1] = &field;
8277 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8281 * mono_store_remote_field:
8282 * @this_obj: pointer to an object
8283 * @klass: klass of the object containing @field
8284 * @field: the field to load
8285 * @val: the value/object to store
8287 * This method is called by the runtime on attempts to store fields of
8288 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8289 * the object containing @field. @val is the new value to store in @field.
8291 void
8292 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8294 MonoError error;
8295 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8296 mono_error_cleanup (&error);
8300 * mono_store_remote_field_checked:
8301 * @this_obj: pointer to an object
8302 * @klass: klass of the object containing @field
8303 * @field: the field to load
8304 * @val: the value/object to store
8305 * @error: set on error
8307 * This method is called by the runtime on attempts to store fields of
8308 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8309 * the object containing @field. @val is the new value to store in @field.
8311 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8313 gboolean
8314 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8317 MONO_REQ_GC_UNSAFE_MODE;
8319 mono_error_init (error);
8321 MonoDomain *domain = mono_domain_get ();
8322 MonoClass *field_class;
8323 MonoObject *arg;
8325 g_assert (mono_object_is_transparent_proxy (this_obj));
8327 field_class = mono_class_from_mono_type (field->type);
8329 if (field_class->valuetype) {
8330 arg = mono_value_box_checked (domain, field_class, val, error);
8331 return_val_if_nok (error, FALSE);
8332 } else {
8333 arg = *((MonoObject**)val);
8336 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8340 * mono_store_remote_field_new:
8341 * @this_obj:
8342 * @klass:
8343 * @field:
8344 * @arg:
8346 * Missing documentation
8348 void
8349 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8351 MonoError error;
8352 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8353 mono_error_cleanup (&error);
8357 * mono_store_remote_field_new_checked:
8358 * @this_obj:
8359 * @klass:
8360 * @field:
8361 * @arg:
8362 * @error:
8364 * Missing documentation
8366 gboolean
8367 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8369 MONO_REQ_GC_UNSAFE_MODE;
8371 static MonoMethod *tp_store = NULL;
8373 mono_error_init (error);
8375 g_assert (mono_object_is_transparent_proxy (this_obj));
8377 if (!tp_store) {
8378 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8379 if (!tp_store) {
8380 mono_error_set_not_supported (error, "Linked away.");
8381 return FALSE;
8385 gpointer args[3];
8386 args [0] = &klass;
8387 args [1] = &field;
8388 args [2] = arg;
8390 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8391 return is_ok (error);
8393 #endif
8396 * mono_create_ftnptr:
8398 * Given a function address, create a function descriptor for it.
8399 * This is only needed on some platforms.
8401 gpointer
8402 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8404 return callbacks.create_ftnptr (domain, addr);
8408 * mono_get_addr_from_ftnptr:
8410 * Given a pointer to a function descriptor, return the function address.
8411 * This is only needed on some platforms.
8413 gpointer
8414 mono_get_addr_from_ftnptr (gpointer descr)
8416 return callbacks.get_addr_from_ftnptr (descr);
8420 * mono_string_chars:
8421 * @s: a MonoString
8423 * Returns a pointer to the UCS16 characters stored in the MonoString
8425 gunichar2 *
8426 mono_string_chars (MonoString *s)
8428 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8430 return s->chars;
8434 * mono_string_length:
8435 * @s: MonoString
8437 * Returns the lenght in characters of the string
8440 mono_string_length (MonoString *s)
8442 MONO_REQ_GC_UNSAFE_MODE;
8444 return s->length;
8448 * mono_string_handle_length:
8449 * @s: MonoString
8451 * Returns the lenght in characters of the string
8454 mono_string_handle_length (MonoStringHandle s)
8456 MONO_REQ_GC_UNSAFE_MODE;
8458 return MONO_HANDLE_GETVAL (s, length);
8463 * mono_array_length:
8464 * @array: a MonoArray*
8466 * Returns the total number of elements in the array. This works for
8467 * both vectors and multidimensional arrays.
8469 uintptr_t
8470 mono_array_length (MonoArray *array)
8472 MONO_REQ_GC_UNSAFE_MODE;
8474 return array->max_length;
8478 * mono_array_addr_with_size:
8479 * @array: a MonoArray*
8480 * @size: size of the array elements
8481 * @idx: index into the array
8483 * Use this function to obtain the address for the @idx item on the
8484 * @array containing elements of size @size.
8486 * This method performs no bounds checking or type checking.
8488 * Returns the address of the @idx element in the array.
8490 char*
8491 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8493 MONO_REQ_GC_UNSAFE_MODE;
8495 return ((char*)(array)->vector) + size * idx;
8499 MonoArray *
8500 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8502 MonoDomain *domain = mono_domain_get ();
8503 MonoArray *res;
8504 int len, i;
8506 mono_error_init (error);
8507 if (!list)
8508 return NULL;
8510 len = g_list_length (list);
8511 res = mono_array_new_checked (domain, eclass, len, error);
8512 return_val_if_nok (error, NULL);
8514 for (i = 0; list; list = list->next, i++)
8515 mono_array_set (res, gpointer, i, list->data);
8517 return res;
8520 #if NEVER_DEFINED
8522 * The following section is purely to declare prototypes and
8523 * document the API, as these C files are processed by our
8524 * tool
8528 * mono_array_set:
8529 * @array: array to alter
8530 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8531 * @index: index into the array
8532 * @value: value to set
8534 * Value Type version: This sets the @index's element of the @array
8535 * with elements of size sizeof(type) to the provided @value.
8537 * This macro does not attempt to perform type checking or bounds checking.
8539 * Use this to set value types in a `MonoArray`.
8541 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8546 * mono_array_setref:
8547 * @array: array to alter
8548 * @index: index into the array
8549 * @value: value to set
8551 * Reference Type version: This sets the @index's element of the
8552 * @array with elements of size sizeof(type) to the provided @value.
8554 * This macro does not attempt to perform type checking or bounds checking.
8556 * Use this to reference types in a `MonoArray`.
8558 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8563 * mono_array_get:
8564 * @array: array on which to operate on
8565 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8566 * @index: index into the array
8568 * Use this macro to retrieve the @index element of an @array and
8569 * extract the value assuming that the elements of the array match
8570 * the provided type value.
8572 * This method can be used with both arrays holding value types and
8573 * reference types. For reference types, the @type parameter should
8574 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8576 * This macro does not attempt to perform type checking or bounds checking.
8578 * Returns: The element at the @index position in the @array.
8580 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8583 #endif