Merge pull request #3100 from lambdageek/dev/monoerror-exns
[mono-project.git] / mono / metadata / object.c
blobc9ed5ebe1e8572240f3025476c134e47cf805906
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/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/utils/strenc.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-memory-model.h>
48 #include <mono/utils/checked-build.h>
49 #include <mono/utils/mono-threads.h>
50 #include <mono/utils/mono-threads-coop.h>
51 #include "cominterop.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 /* Class lazy loading functions */
66 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
67 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
68 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
69 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
70 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
73 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
74 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
75 static mono_mutex_t ldstr_section;
77 /**
78 * mono_runtime_object_init:
79 * @this_obj: the object to initialize
81 * This function calls the zero-argument constructor (which must
82 * exist) for the given object.
84 void
85 mono_runtime_object_init (MonoObject *this_obj)
87 MonoError error;
88 mono_runtime_object_init_checked (this_obj, &error);
89 mono_error_assert_ok (&error);
92 /**
93 * mono_runtime_object_init_checked:
94 * @this_obj: the object to initialize
95 * @error: set on error.
97 * This function calls the zero-argument constructor (which must
98 * exist) for the given object and returns TRUE on success, or FALSE
99 * on error and sets @error.
101 gboolean
102 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
104 MONO_REQ_GC_UNSAFE_MODE;
106 MonoMethod *method = NULL;
107 MonoClass *klass = this_obj->vtable->klass;
109 mono_error_init (error);
110 method = mono_class_get_method_from_name (klass, ".ctor", 0);
111 if (!method)
112 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
114 if (method->klass->valuetype)
115 this_obj = (MonoObject *)mono_object_unbox (this_obj);
117 mono_runtime_invoke_checked (method, this_obj, NULL, error);
118 return is_ok (error);
121 /* The pseudo algorithm for type initialization from the spec
122 Note it doesn't say anything about domains - only threads.
124 2. If the type is initialized you are done.
125 2.1. If the type is not yet initialized, try to take an
126 initialization lock.
127 2.2. If successful, record this thread as responsible for
128 initializing the type and proceed to step 2.3.
129 2.2.1. If not, see whether this thread or any thread
130 waiting for this thread to complete already holds the lock.
131 2.2.2. If so, return since blocking would create a deadlock. This thread
132 will now see an incompletely initialized state for the type,
133 but no deadlock will arise.
134 2.2.3 If not, block until the type is initialized then return.
135 2.3 Initialize the parent type and then all interfaces implemented
136 by this type.
137 2.4 Execute the type initialization code for this type.
138 2.5 Mark the type as initialized, release the initialization lock,
139 awaken any threads waiting for this type to be initialized,
140 and return.
144 typedef struct
146 MonoNativeThreadId initializing_tid;
147 guint32 waiting_count;
148 gboolean done;
149 MonoCoopMutex initialization_section;
150 } TypeInitializationLock;
152 /* for locking access to type_initialization_hash and blocked_thread_hash */
153 static MonoCoopMutex type_initialization_section;
155 static inline void
156 mono_type_initialization_lock (void)
158 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
159 mono_coop_mutex_lock (&type_initialization_section);
162 static inline void
163 mono_type_initialization_unlock (void)
165 mono_coop_mutex_unlock (&type_initialization_section);
168 static void
169 mono_type_init_lock (TypeInitializationLock *lock)
171 MONO_REQ_GC_NEUTRAL_MODE;
173 mono_coop_mutex_lock (&lock->initialization_section);
176 static void
177 mono_type_init_unlock (TypeInitializationLock *lock)
179 mono_coop_mutex_unlock (&lock->initialization_section);
182 /* from vtable to lock */
183 static GHashTable *type_initialization_hash;
185 /* from thread id to thread id being waited on */
186 static GHashTable *blocked_thread_hash;
188 /* Main thread */
189 static MonoThread *main_thread;
191 /* Functions supplied by the runtime */
192 static MonoRuntimeCallbacks callbacks;
195 * mono_thread_set_main:
196 * @thread: thread to set as the main thread
198 * This function can be used to instruct the runtime to treat @thread
199 * as the main thread, ie, the thread that would normally execute the Main()
200 * method. This basically means that at the end of @thread, the runtime will
201 * wait for the existing foreground threads to quit and other such details.
203 void
204 mono_thread_set_main (MonoThread *thread)
206 MONO_REQ_GC_UNSAFE_MODE;
208 static gboolean registered = FALSE;
210 if (!registered) {
211 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
212 registered = TRUE;
215 main_thread = thread;
218 MonoThread*
219 mono_thread_get_main (void)
221 MONO_REQ_GC_UNSAFE_MODE;
223 return main_thread;
226 void
227 mono_type_initialization_init (void)
229 mono_coop_mutex_init_recursive (&type_initialization_section);
230 type_initialization_hash = g_hash_table_new (NULL, NULL);
231 blocked_thread_hash = g_hash_table_new (NULL, NULL);
232 mono_os_mutex_init_recursive (&ldstr_section);
235 void
236 mono_type_initialization_cleanup (void)
238 #if 0
239 /* This is causing race conditions with
240 * mono_release_type_locks
242 mono_coop_mutex_destroy (&type_initialization_section);
243 g_hash_table_destroy (type_initialization_hash);
244 type_initialization_hash = NULL;
245 #endif
246 mono_os_mutex_destroy (&ldstr_section);
247 g_hash_table_destroy (blocked_thread_hash);
248 blocked_thread_hash = NULL;
250 free_main_args ();
254 * get_type_init_exception_for_vtable:
256 * Return the stored type initialization exception for VTABLE.
258 static MonoException*
259 get_type_init_exception_for_vtable (MonoVTable *vtable)
261 MONO_REQ_GC_UNSAFE_MODE;
263 MonoError error;
264 MonoDomain *domain = vtable->domain;
265 MonoClass *klass = vtable->klass;
266 MonoException *ex;
267 gchar *full_name;
269 if (!vtable->init_failed)
270 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
273 * If the initializing thread was rudely aborted, the exception is not stored
274 * in the hash.
276 ex = NULL;
277 mono_domain_lock (domain);
278 if (domain->type_init_exception_hash)
279 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
280 mono_domain_unlock (domain);
282 if (!ex) {
283 if (klass->name_space && *klass->name_space)
284 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
285 else
286 full_name = g_strdup (klass->name);
287 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
288 g_free (full_name);
289 return_val_if_nok (&error, NULL);
292 return ex;
296 * mono_runtime_class_init:
297 * @vtable: vtable that needs to be initialized
299 * This routine calls the class constructor for @vtable.
301 void
302 mono_runtime_class_init (MonoVTable *vtable)
304 MONO_REQ_GC_UNSAFE_MODE;
305 MonoError error;
307 mono_runtime_class_init_full (vtable, &error);
308 mono_error_assert_ok (&error);
312 * mono_runtime_class_init_full:
313 * @vtable that neeeds to be initialized
314 * @error set on error
316 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
319 gboolean
320 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
322 MONO_REQ_GC_UNSAFE_MODE;
324 MonoMethod *method = NULL;
325 MonoClass *klass;
326 gchar *full_name;
327 MonoDomain *domain = vtable->domain;
328 TypeInitializationLock *lock;
329 MonoNativeThreadId tid;
330 int do_initialization = 0;
331 MonoDomain *last_domain = NULL;
333 mono_error_init (error);
335 if (vtable->initialized)
336 return TRUE;
338 klass = vtable->klass;
340 if (!klass->image->checked_module_cctor) {
341 mono_image_check_for_module_cctor (klass->image);
342 if (klass->image->has_module_cctor) {
343 MonoClass *module_klass;
344 MonoVTable *module_vtable;
346 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
347 if (!module_klass) {
348 return FALSE;
351 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
352 if (!module_vtable)
353 return FALSE;
354 if (!mono_runtime_class_init_full (module_vtable, error))
355 return FALSE;
358 method = mono_class_get_cctor (klass);
359 if (!method) {
360 vtable->initialized = 1;
361 return TRUE;
364 tid = mono_native_thread_id_get ();
366 mono_type_initialization_lock ();
367 /* double check... */
368 if (vtable->initialized) {
369 mono_type_initialization_unlock ();
370 return TRUE;
372 if (vtable->init_failed) {
373 mono_type_initialization_unlock ();
375 /* The type initialization already failed once, rethrow the same exception */
376 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
377 return FALSE;
379 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
380 if (lock == NULL) {
381 /* This thread will get to do the initialization */
382 if (mono_domain_get () != domain) {
383 /* Transfer into the target domain */
384 last_domain = mono_domain_get ();
385 if (!mono_domain_set (domain, FALSE)) {
386 vtable->initialized = 1;
387 mono_type_initialization_unlock ();
388 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
389 return FALSE;
392 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
393 mono_coop_mutex_init_recursive (&lock->initialization_section);
394 lock->initializing_tid = tid;
395 lock->waiting_count = 1;
396 lock->done = FALSE;
397 /* grab the vtable lock while this thread still owns type_initialization_section */
398 /* This is why type_initialization_lock needs to enter blocking mode */
399 mono_type_init_lock (lock);
400 g_hash_table_insert (type_initialization_hash, vtable, lock);
401 do_initialization = 1;
402 } else {
403 gpointer blocked;
404 TypeInitializationLock *pending_lock;
406 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
407 mono_type_initialization_unlock ();
408 return TRUE;
410 /* see if the thread doing the initialization is already blocked on this thread */
411 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
412 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
413 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
414 if (!pending_lock->done) {
415 mono_type_initialization_unlock ();
416 return TRUE;
417 } else {
418 /* the thread doing the initialization is blocked on this thread,
419 but on a lock that has already been freed. It just hasn't got
420 time to awake */
421 break;
424 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
426 ++lock->waiting_count;
427 /* record the fact that we are waiting on the initializing thread */
428 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
430 mono_type_initialization_unlock ();
432 if (do_initialization) {
433 MonoException *exc = NULL;
434 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
435 if (exc != NULL && mono_error_ok (error)) {
436 mono_error_set_exception_instance (error, exc);
439 /* If the initialization failed, mark the class as unusable. */
440 /* Avoid infinite loops */
441 if (!(mono_error_ok(error) ||
442 (klass->image == mono_defaults.corlib &&
443 !strcmp (klass->name_space, "System") &&
444 !strcmp (klass->name, "TypeInitializationException")))) {
445 vtable->init_failed = 1;
447 if (klass->name_space && *klass->name_space)
448 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
449 else
450 full_name = g_strdup (klass->name);
452 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
453 g_free (full_name);
454 return_val_if_nok (error, FALSE);
456 mono_error_set_exception_instance (error, exc_to_throw);
458 MonoException *exc_to_store = mono_error_convert_to_exception (error);
459 /* What we really want to do here is clone the error object and store one copy in the
460 * domain's exception hash and use the other one to error out here. */
461 mono_error_init (error);
462 mono_error_set_exception_instance (error, exc_to_store);
464 * Store the exception object so it could be thrown on subsequent
465 * accesses.
467 mono_domain_lock (domain);
468 if (!domain->type_init_exception_hash)
469 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");
470 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
471 mono_domain_unlock (domain);
474 if (last_domain)
475 mono_domain_set (last_domain, TRUE);
476 lock->done = TRUE;
477 mono_type_init_unlock (lock);
478 } else {
479 /* this just blocks until the initializing thread is done */
480 mono_type_init_lock (lock);
481 mono_type_init_unlock (lock);
484 mono_type_initialization_lock ();
485 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
486 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
487 --lock->waiting_count;
488 if (lock->waiting_count == 0) {
489 mono_coop_mutex_destroy (&lock->initialization_section);
490 g_hash_table_remove (type_initialization_hash, vtable);
491 g_free (lock);
493 mono_memory_barrier ();
494 if (!vtable->init_failed)
495 vtable->initialized = 1;
496 mono_type_initialization_unlock ();
498 if (vtable->init_failed) {
499 /* Either we were the initializing thread or we waited for the initialization */
500 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
501 return FALSE;
503 return TRUE;
506 static
507 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
509 MONO_REQ_GC_NEUTRAL_MODE;
511 MonoVTable *vtable = (MonoVTable*)key;
513 TypeInitializationLock *lock = (TypeInitializationLock*) value;
514 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
515 lock->done = TRUE;
517 * Have to set this since it cannot be set by the normal code in
518 * mono_runtime_class_init (). In this case, the exception object is not stored,
519 * and get_type_init_exception_for_class () needs to be aware of this.
521 vtable->init_failed = 1;
522 mono_type_init_unlock (lock);
523 --lock->waiting_count;
524 if (lock->waiting_count == 0) {
525 mono_coop_mutex_destroy (&lock->initialization_section);
526 g_free (lock);
527 return TRUE;
530 return FALSE;
533 void
534 mono_release_type_locks (MonoInternalThread *thread)
536 MONO_REQ_GC_UNSAFE_MODE;
538 mono_type_initialization_lock ();
539 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
540 mono_type_initialization_unlock ();
543 #ifndef DISABLE_REMOTING
545 static gpointer
546 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
548 g_error ("remoting not installed");
549 return NULL;
552 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
553 #endif
555 static gpointer
556 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
558 g_assert_not_reached ();
559 return NULL;
562 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
563 static MonoImtThunkBuilder imt_thunk_builder;
564 static gboolean always_build_imt_thunks;
566 #if (MONO_IMT_SIZE > 32)
567 #error "MONO_IMT_SIZE cannot be larger than 32"
568 #endif
570 void
571 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
573 memcpy (&callbacks, cbs, sizeof (*cbs));
576 MonoRuntimeCallbacks*
577 mono_get_runtime_callbacks (void)
579 return &callbacks;
582 #ifndef DISABLE_REMOTING
583 void
584 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
586 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
588 #endif
590 void
591 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
593 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
596 void
597 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
598 imt_thunk_builder = func;
601 void
602 mono_set_always_build_imt_thunks (gboolean value)
604 always_build_imt_thunks = value;
608 * mono_compile_method:
609 * @method: The method to compile.
611 * This JIT-compiles the method, and returns the pointer to the native code
612 * produced.
614 gpointer
615 mono_compile_method (MonoMethod *method)
617 MonoError error;
618 gpointer result = mono_compile_method_checked (method, &error);
619 mono_error_cleanup (&error);
620 return result;
624 * mono_compile_method:
625 * @method: The method to compile.
626 * @error: set on error.
628 * This JIT-compiles the method, and returns the pointer to the native code
629 * produced. On failure returns NULL and sets @error.
631 gpointer
632 mono_compile_method_checked (MonoMethod *method, MonoError *error)
634 gpointer res;
636 MONO_REQ_GC_NEUTRAL_MODE
638 mono_error_init (error);
640 if (!callbacks.compile_method) {
641 g_error ("compile method called on uninitialized runtime");
642 return NULL;
644 res = callbacks.compile_method (method, error);
645 return res;
648 gpointer
649 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
651 gpointer res;
653 MONO_REQ_GC_NEUTRAL_MODE;
655 mono_error_init (error);
656 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
657 return res;
660 gpointer
661 mono_runtime_create_delegate_trampoline (MonoClass *klass)
663 MONO_REQ_GC_NEUTRAL_MODE
665 return arch_create_delegate_trampoline (mono_domain_get (), klass);
668 static MonoFreeMethodFunc default_mono_free_method = NULL;
671 * mono_install_free_method:
672 * @func: pointer to the MonoFreeMethodFunc used to release a method
674 * This is an internal VM routine, it is used for the engines to
675 * register a handler to release the resources associated with a method.
677 * Methods are freed when no more references to the delegate that holds
678 * them are left.
680 void
681 mono_install_free_method (MonoFreeMethodFunc func)
683 default_mono_free_method = func;
687 * mono_runtime_free_method:
688 * @domain; domain where the method is hosted
689 * @method: method to release
691 * This routine is invoked to free the resources associated with
692 * a method that has been JIT compiled. This is used to discard
693 * methods that were used only temporarily (for example, used in marshalling)
696 void
697 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
699 MONO_REQ_GC_NEUTRAL_MODE
701 if (default_mono_free_method != NULL)
702 default_mono_free_method (domain, method);
704 mono_method_clear_object (domain, method);
706 mono_free_method (method);
710 * The vtables in the root appdomain are assumed to be reachable by other
711 * roots, and we don't use typed allocation in the other domains.
714 /* The sync block is no longer a GC pointer */
715 #define GC_HEADER_BITMAP (0)
717 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
719 static gsize*
720 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
722 MONO_REQ_GC_NEUTRAL_MODE;
724 MonoClassField *field;
725 MonoClass *p;
726 guint32 pos;
727 int max_size;
729 if (static_fields)
730 max_size = mono_class_data_size (klass) / sizeof (gpointer);
731 else
732 max_size = klass->instance_size / sizeof (gpointer);
733 if (max_size > size) {
734 g_assert (offset <= 0);
735 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
736 size = max_size;
739 #ifdef HAVE_SGEN_GC
740 /*An Ephemeron cannot be marked by sgen*/
741 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
742 *max_set = 0;
743 memset (bitmap, 0, size / 8);
744 return bitmap;
746 #endif
748 for (p = klass; p != NULL; p = p->parent) {
749 gpointer iter = NULL;
750 while ((field = mono_class_get_fields (p, &iter))) {
751 MonoType *type;
753 if (static_fields) {
754 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
755 continue;
756 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
757 continue;
758 } else {
759 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
760 continue;
762 /* FIXME: should not happen, flag as type load error */
763 if (field->type->byref)
764 break;
766 if (static_fields && field->offset == -1)
767 /* special static */
768 continue;
770 pos = field->offset / sizeof (gpointer);
771 pos += offset;
773 type = mono_type_get_underlying_type (field->type);
774 switch (type->type) {
775 case MONO_TYPE_I:
776 case MONO_TYPE_PTR:
777 case MONO_TYPE_FNPTR:
778 break;
779 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
780 case MONO_TYPE_U:
781 #ifdef HAVE_SGEN_GC
782 break;
783 #else
784 if (klass->image != mono_defaults.corlib)
785 break;
786 #endif
787 case MONO_TYPE_STRING:
788 case MONO_TYPE_SZARRAY:
789 case MONO_TYPE_CLASS:
790 case MONO_TYPE_OBJECT:
791 case MONO_TYPE_ARRAY:
792 g_assert ((field->offset % sizeof(gpointer)) == 0);
794 g_assert (pos < size || pos <= max_size);
795 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
796 *max_set = MAX (*max_set, pos);
797 break;
798 case MONO_TYPE_GENERICINST:
799 if (!mono_type_generic_inst_is_valuetype (type)) {
800 g_assert ((field->offset % sizeof(gpointer)) == 0);
802 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
803 *max_set = MAX (*max_set, pos);
804 break;
805 } else {
806 /* fall through */
808 case MONO_TYPE_VALUETYPE: {
809 MonoClass *fclass = mono_class_from_mono_type (field->type);
810 if (fclass->has_references) {
811 /* remove the object header */
812 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
814 break;
816 case MONO_TYPE_I1:
817 case MONO_TYPE_U1:
818 case MONO_TYPE_I2:
819 case MONO_TYPE_U2:
820 case MONO_TYPE_I4:
821 case MONO_TYPE_U4:
822 case MONO_TYPE_I8:
823 case MONO_TYPE_U8:
824 case MONO_TYPE_R4:
825 case MONO_TYPE_R8:
826 case MONO_TYPE_BOOLEAN:
827 case MONO_TYPE_CHAR:
828 break;
829 default:
830 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
831 break;
834 if (static_fields)
835 break;
837 return bitmap;
841 * mono_class_compute_bitmap:
843 * Mono internal function to compute a bitmap of reference fields in a class.
845 gsize*
846 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
848 MONO_REQ_GC_NEUTRAL_MODE;
850 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
853 #if 0
855 * similar to the above, but sets the bits in the bitmap for any non-ref field
856 * and ignores static fields
858 static gsize*
859 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
861 MonoClassField *field;
862 MonoClass *p;
863 guint32 pos, pos2;
864 int max_size;
866 max_size = class->instance_size / sizeof (gpointer);
867 if (max_size >= size) {
868 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
871 for (p = class; p != NULL; p = p->parent) {
872 gpointer iter = NULL;
873 while ((field = mono_class_get_fields (p, &iter))) {
874 MonoType *type;
876 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
877 continue;
878 /* FIXME: should not happen, flag as type load error */
879 if (field->type->byref)
880 break;
882 pos = field->offset / sizeof (gpointer);
883 pos += offset;
885 type = mono_type_get_underlying_type (field->type);
886 switch (type->type) {
887 #if SIZEOF_VOID_P == 8
888 case MONO_TYPE_I:
889 case MONO_TYPE_U:
890 case MONO_TYPE_PTR:
891 case MONO_TYPE_FNPTR:
892 #endif
893 case MONO_TYPE_I8:
894 case MONO_TYPE_U8:
895 case MONO_TYPE_R8:
896 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
897 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
898 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 /* fall through */
901 #if SIZEOF_VOID_P == 4
902 case MONO_TYPE_I:
903 case MONO_TYPE_U:
904 case MONO_TYPE_PTR:
905 case MONO_TYPE_FNPTR:
906 #endif
907 case MONO_TYPE_I4:
908 case MONO_TYPE_U4:
909 case MONO_TYPE_R4:
910 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
911 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
912 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
914 /* fall through */
915 case MONO_TYPE_CHAR:
916 case MONO_TYPE_I2:
917 case MONO_TYPE_U2:
918 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
919 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
920 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 /* fall through */
923 case MONO_TYPE_BOOLEAN:
924 case MONO_TYPE_I1:
925 case MONO_TYPE_U1:
926 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
927 break;
928 case MONO_TYPE_STRING:
929 case MONO_TYPE_SZARRAY:
930 case MONO_TYPE_CLASS:
931 case MONO_TYPE_OBJECT:
932 case MONO_TYPE_ARRAY:
933 break;
934 case MONO_TYPE_GENERICINST:
935 if (!mono_type_generic_inst_is_valuetype (type)) {
936 break;
937 } else {
938 /* fall through */
940 case MONO_TYPE_VALUETYPE: {
941 MonoClass *fclass = mono_class_from_mono_type (field->type);
942 /* remove the object header */
943 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
944 break;
946 default:
947 g_assert_not_reached ();
948 break;
952 return bitmap;
956 * mono_class_insecure_overlapping:
957 * check if a class with explicit layout has references and non-references
958 * fields overlapping.
960 * Returns: TRUE if it is insecure to load the type.
962 gboolean
963 mono_class_insecure_overlapping (MonoClass *klass)
965 int max_set = 0;
966 gsize *bitmap;
967 gsize default_bitmap [4] = {0};
968 gsize *nrbitmap;
969 gsize default_nrbitmap [4] = {0};
970 int i, insecure = FALSE;
971 return FALSE;
973 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
974 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
976 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
977 int idx = i % (sizeof (bitmap [0]) * 8);
978 if (bitmap [idx] & nrbitmap [idx]) {
979 insecure = TRUE;
980 break;
983 if (bitmap != default_bitmap)
984 g_free (bitmap);
985 if (nrbitmap != default_nrbitmap)
986 g_free (nrbitmap);
987 if (insecure) {
988 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
989 return FALSE;
991 return insecure;
993 #endif
995 MonoString*
996 ves_icall_string_alloc (int length)
998 MonoError error;
999 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1000 mono_error_set_pending_exception (&error);
1002 return str;
1005 void
1006 mono_class_compute_gc_descriptor (MonoClass *klass)
1008 MONO_REQ_GC_NEUTRAL_MODE;
1010 int max_set = 0;
1011 gsize *bitmap;
1012 gsize default_bitmap [4] = {0};
1013 static gboolean gcj_inited = FALSE;
1015 if (!gcj_inited) {
1016 mono_loader_lock ();
1018 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1019 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1021 gcj_inited = TRUE;
1022 mono_loader_unlock ();
1025 if (!klass->inited)
1026 mono_class_init (klass);
1028 if (klass->gc_descr_inited)
1029 return;
1031 klass->gc_descr_inited = TRUE;
1032 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1034 bitmap = default_bitmap;
1035 if (klass == mono_defaults.string_class) {
1036 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1037 } else if (klass->rank) {
1038 mono_class_compute_gc_descriptor (klass->element_class);
1039 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1040 gsize abm = 1;
1041 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1042 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1043 class->name_space, class->name);*/
1044 } else {
1045 /* remove the object header */
1046 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1047 klass->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));
1048 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1049 class->name_space, class->name);*/
1050 if (bitmap != default_bitmap)
1051 g_free (bitmap);
1053 } else {
1054 /*static int count = 0;
1055 if (count++ > 58)
1056 return;*/
1057 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1058 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1060 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1061 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1063 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1064 if (bitmap != default_bitmap)
1065 g_free (bitmap);
1070 * field_is_special_static:
1071 * @fklass: The MonoClass to look up.
1072 * @field: The MonoClassField describing the field.
1074 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1075 * SPECIAL_STATIC_NONE otherwise.
1077 static gint32
1078 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1080 MONO_REQ_GC_NEUTRAL_MODE;
1082 MonoError error;
1083 MonoCustomAttrInfo *ainfo;
1084 int i;
1085 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1086 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1087 if (!ainfo)
1088 return FALSE;
1089 for (i = 0; i < ainfo->num_attrs; ++i) {
1090 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1091 if (klass->image == mono_defaults.corlib) {
1092 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1093 mono_custom_attrs_free (ainfo);
1094 return SPECIAL_STATIC_THREAD;
1096 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1097 mono_custom_attrs_free (ainfo);
1098 return SPECIAL_STATIC_CONTEXT;
1102 mono_custom_attrs_free (ainfo);
1103 return SPECIAL_STATIC_NONE;
1106 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1107 #define mix(a,b,c) { \
1108 a -= c; a ^= rot(c, 4); c += b; \
1109 b -= a; b ^= rot(a, 6); a += c; \
1110 c -= b; c ^= rot(b, 8); b += a; \
1111 a -= c; a ^= rot(c,16); c += b; \
1112 b -= a; b ^= rot(a,19); a += c; \
1113 c -= b; c ^= rot(b, 4); b += a; \
1115 #define final(a,b,c) { \
1116 c ^= b; c -= rot(b,14); \
1117 a ^= c; a -= rot(c,11); \
1118 b ^= a; b -= rot(a,25); \
1119 c ^= b; c -= rot(b,16); \
1120 a ^= c; a -= rot(c,4); \
1121 b ^= a; b -= rot(a,14); \
1122 c ^= b; c -= rot(b,24); \
1126 * mono_method_get_imt_slot:
1128 * The IMT slot is embedded into AOTed code, so this must return the same value
1129 * for the same method across all executions. This means:
1130 * - pointers shouldn't be used as hash values.
1131 * - mono_metadata_str_hash () should be used for hashing strings.
1133 guint32
1134 mono_method_get_imt_slot (MonoMethod *method)
1136 MONO_REQ_GC_NEUTRAL_MODE;
1138 MonoMethodSignature *sig;
1139 int hashes_count;
1140 guint32 *hashes_start, *hashes;
1141 guint32 a, b, c;
1142 int i;
1144 /* This can be used to stress tests the collision code */
1145 //return 0;
1148 * We do this to simplify generic sharing. It will hurt
1149 * performance in cases where a class implements two different
1150 * instantiations of the same generic interface.
1151 * The code in build_imt_slots () depends on this.
1153 if (method->is_inflated)
1154 method = ((MonoMethodInflated*)method)->declaring;
1156 sig = mono_method_signature (method);
1157 hashes_count = sig->param_count + 4;
1158 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1159 hashes = hashes_start;
1161 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1162 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1163 method->klass->name_space, method->klass->name, method->name);
1166 /* Initialize hashes */
1167 hashes [0] = mono_metadata_str_hash (method->klass->name);
1168 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1169 hashes [2] = mono_metadata_str_hash (method->name);
1170 hashes [3] = mono_metadata_type_hash (sig->ret);
1171 for (i = 0; i < sig->param_count; i++) {
1172 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1175 /* Setup internal state */
1176 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1178 /* Handle most of the hashes */
1179 while (hashes_count > 3) {
1180 a += hashes [0];
1181 b += hashes [1];
1182 c += hashes [2];
1183 mix (a,b,c);
1184 hashes_count -= 3;
1185 hashes += 3;
1188 /* Handle the last 3 hashes (all the case statements fall through) */
1189 switch (hashes_count) {
1190 case 3 : c += hashes [2];
1191 case 2 : b += hashes [1];
1192 case 1 : a += hashes [0];
1193 final (a,b,c);
1194 case 0: /* nothing left to add */
1195 break;
1198 free (hashes_start);
1199 /* Report the result */
1200 return c % MONO_IMT_SIZE;
1202 #undef rot
1203 #undef mix
1204 #undef final
1206 #define DEBUG_IMT 0
1208 static void
1209 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1210 MONO_REQ_GC_NEUTRAL_MODE;
1212 guint32 imt_slot = mono_method_get_imt_slot (method);
1213 MonoImtBuilderEntry *entry;
1215 if (slot_num >= 0 && imt_slot != slot_num) {
1216 /* we build just a single imt slot and this is not it */
1217 return;
1220 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1221 entry->key = method;
1222 entry->value.vtable_slot = vtable_slot;
1223 entry->next = imt_builder [imt_slot];
1224 if (imt_builder [imt_slot] != NULL) {
1225 entry->children = imt_builder [imt_slot]->children + 1;
1226 if (entry->children == 1) {
1227 mono_stats.imt_slots_with_collisions++;
1228 *imt_collisions_bitmap |= (1 << imt_slot);
1230 } else {
1231 entry->children = 0;
1232 mono_stats.imt_used_slots++;
1234 imt_builder [imt_slot] = entry;
1235 #if DEBUG_IMT
1237 char *method_name = mono_method_full_name (method, TRUE);
1238 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1239 method, method_name, imt_slot, vtable_slot, entry->children);
1240 g_free (method_name);
1242 #endif
1245 #if DEBUG_IMT
1246 static void
1247 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1248 if (e != NULL) {
1249 MonoMethod *method = e->key;
1250 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1251 message,
1252 num,
1253 method,
1254 method->klass->name_space,
1255 method->klass->name,
1256 method->name);
1257 } else {
1258 printf (" * %s: NULL\n", message);
1261 #endif
1263 static int
1264 compare_imt_builder_entries (const void *p1, const void *p2) {
1265 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1266 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1268 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1271 static int
1272 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1274 MONO_REQ_GC_NEUTRAL_MODE;
1276 int count = end - start;
1277 int chunk_start = out_array->len;
1278 if (count < 4) {
1279 int i;
1280 for (i = start; i < end; ++i) {
1281 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1282 item->key = sorted_array [i]->key;
1283 item->value = sorted_array [i]->value;
1284 item->has_target_code = sorted_array [i]->has_target_code;
1285 item->is_equals = TRUE;
1286 if (i < end - 1)
1287 item->check_target_idx = out_array->len + 1;
1288 else
1289 item->check_target_idx = 0;
1290 g_ptr_array_add (out_array, item);
1292 } else {
1293 int middle = start + count / 2;
1294 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1296 item->key = sorted_array [middle]->key;
1297 item->is_equals = FALSE;
1298 g_ptr_array_add (out_array, item);
1299 imt_emit_ir (sorted_array, start, middle, out_array);
1300 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1302 return chunk_start;
1305 static GPtrArray*
1306 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1307 MONO_REQ_GC_NEUTRAL_MODE;
1309 int number_of_entries = entries->children + 1;
1310 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1311 GPtrArray *result = g_ptr_array_new ();
1312 MonoImtBuilderEntry *current_entry;
1313 int i;
1315 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1316 sorted_array [i] = current_entry;
1318 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1320 /*for (i = 0; i < number_of_entries; i++) {
1321 print_imt_entry (" sorted array:", sorted_array [i], i);
1324 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1326 free (sorted_array);
1327 return result;
1330 static gpointer
1331 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1333 MONO_REQ_GC_NEUTRAL_MODE;
1335 if (imt_builder_entry != NULL) {
1336 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1337 /* No collision, return the vtable slot contents */
1338 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1339 } else {
1340 /* Collision, build the thunk */
1341 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1342 gpointer result;
1343 int i;
1344 result = imt_thunk_builder (vtable, domain,
1345 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1346 for (i = 0; i < imt_ir->len; ++i)
1347 g_free (g_ptr_array_index (imt_ir, i));
1348 g_ptr_array_free (imt_ir, TRUE);
1349 return result;
1351 } else {
1352 if (fail_tramp)
1353 return fail_tramp;
1354 else
1355 /* Empty slot */
1356 return NULL;
1360 static MonoImtBuilderEntry*
1361 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1364 * LOCKING: requires the loader and domain locks.
1367 static void
1368 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1370 MONO_REQ_GC_NEUTRAL_MODE;
1372 int i;
1373 GSList *list_item;
1374 guint32 imt_collisions_bitmap = 0;
1375 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1376 int method_count = 0;
1377 gboolean record_method_count_for_max_collisions = FALSE;
1378 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1380 #if DEBUG_IMT
1381 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1382 #endif
1383 for (i = 0; i < klass->interface_offsets_count; ++i) {
1384 MonoClass *iface = klass->interfaces_packed [i];
1385 int interface_offset = klass->interface_offsets_packed [i];
1386 int method_slot_in_interface, vt_slot;
1388 if (mono_class_has_variant_generic_params (iface))
1389 has_variant_iface = TRUE;
1391 mono_class_setup_methods (iface);
1392 vt_slot = interface_offset;
1393 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1394 MonoMethod *method;
1396 if (slot_num >= 0 && iface->is_inflated) {
1398 * The imt slot of the method is the same as for its declaring method,
1399 * see the comment in mono_method_get_imt_slot (), so we can
1400 * avoid inflating methods which will be discarded by
1401 * add_imt_builder_entry anyway.
1403 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1404 if (mono_method_get_imt_slot (method) != slot_num) {
1405 vt_slot ++;
1406 continue;
1409 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1410 if (method->is_generic) {
1411 has_generic_virtual = TRUE;
1412 vt_slot ++;
1413 continue;
1416 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1417 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1418 vt_slot ++;
1422 if (extra_interfaces) {
1423 int interface_offset = klass->vtable_size;
1425 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1426 MonoClass* iface = (MonoClass *)list_item->data;
1427 int method_slot_in_interface;
1428 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1429 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1431 if (method->is_generic)
1432 has_generic_virtual = TRUE;
1433 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1435 interface_offset += iface->method.count;
1438 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1439 /* overwrite the imt slot only if we're building all the entries or if
1440 * we're building this specific one
1442 if (slot_num < 0 || i == slot_num) {
1443 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1445 if (entries) {
1446 if (imt_builder [i]) {
1447 MonoImtBuilderEntry *entry;
1449 /* Link entries with imt_builder [i] */
1450 for (entry = entries; entry->next; entry = entry->next) {
1451 #if DEBUG_IMT
1452 MonoMethod *method = (MonoMethod*)entry->key;
1453 char *method_name = mono_method_full_name (method, TRUE);
1454 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1455 g_free (method_name);
1456 #endif
1458 entry->next = imt_builder [i];
1459 entries->children += imt_builder [i]->children + 1;
1461 imt_builder [i] = entries;
1464 if (has_generic_virtual || has_variant_iface) {
1466 * There might be collisions later when the the thunk is expanded.
1468 imt_collisions_bitmap |= (1 << i);
1471 * The IMT thunk might be called with an instance of one of the
1472 * generic virtual methods, so has to fallback to the IMT trampoline.
1474 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1475 } else {
1476 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1478 #if DEBUG_IMT
1479 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1480 #endif
1483 if (imt_builder [i] != NULL) {
1484 int methods_in_slot = imt_builder [i]->children + 1;
1485 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1486 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1487 record_method_count_for_max_collisions = TRUE;
1489 method_count += methods_in_slot;
1493 mono_stats.imt_number_of_methods += method_count;
1494 if (record_method_count_for_max_collisions) {
1495 mono_stats.imt_method_count_when_max_collisions = method_count;
1498 for (i = 0; i < MONO_IMT_SIZE; i++) {
1499 MonoImtBuilderEntry* entry = imt_builder [i];
1500 while (entry != NULL) {
1501 MonoImtBuilderEntry* next = entry->next;
1502 g_free (entry);
1503 entry = next;
1506 free (imt_builder);
1507 /* we OR the bitmap since we may build just a single imt slot at a time */
1508 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1511 static void
1512 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1513 MONO_REQ_GC_NEUTRAL_MODE;
1515 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1519 * mono_vtable_build_imt_slot:
1520 * @vtable: virtual object table struct
1521 * @imt_slot: slot in the IMT table
1523 * Fill the given @imt_slot in the IMT table of @vtable with
1524 * a trampoline or a thunk for the case of collisions.
1525 * This is part of the internal mono API.
1527 * LOCKING: Take the domain lock.
1529 void
1530 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1532 MONO_REQ_GC_NEUTRAL_MODE;
1534 gpointer *imt = (gpointer*)vtable;
1535 imt -= MONO_IMT_SIZE;
1536 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1538 /* no support for extra interfaces: the proxy objects will need
1539 * to build the complete IMT
1540 * Update and heck needs to ahppen inside the proper domain lock, as all
1541 * the changes made to a MonoVTable.
1543 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1544 mono_domain_lock (vtable->domain);
1545 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1546 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1547 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1548 mono_domain_unlock (vtable->domain);
1549 mono_loader_unlock ();
1554 * The first two free list entries both belong to the wait list: The
1555 * first entry is the pointer to the head of the list and the second
1556 * entry points to the last element. That way appending and removing
1557 * the first element are both O(1) operations.
1559 #ifdef MONO_SMALL_CONFIG
1560 #define NUM_FREE_LISTS 6
1561 #else
1562 #define NUM_FREE_LISTS 12
1563 #endif
1564 #define FIRST_FREE_LIST_SIZE 64
1565 #define MAX_WAIT_LENGTH 50
1566 #define THUNK_THRESHOLD 10
1569 * LOCKING: The domain lock must be held.
1571 static void
1572 init_thunk_free_lists (MonoDomain *domain)
1574 MONO_REQ_GC_NEUTRAL_MODE;
1576 if (domain->thunk_free_lists)
1577 return;
1578 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1581 static int
1582 list_index_for_size (int item_size)
1584 int i = 2;
1585 int size = FIRST_FREE_LIST_SIZE;
1587 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1588 i++;
1589 size <<= 1;
1592 return i;
1596 * mono_method_alloc_generic_virtual_thunk:
1597 * @domain: a domain
1598 * @size: size in bytes
1600 * Allocs size bytes to be used for the code of a generic virtual
1601 * thunk. It's either allocated from the domain's code manager or
1602 * reused from a previously invalidated piece.
1604 * LOCKING: The domain lock must be held.
1606 gpointer
1607 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1609 MONO_REQ_GC_NEUTRAL_MODE;
1611 static gboolean inited = FALSE;
1612 static int generic_virtual_thunks_size = 0;
1614 guint32 *p;
1615 int i;
1616 MonoThunkFreeList **l;
1618 init_thunk_free_lists (domain);
1620 size += sizeof (guint32);
1621 if (size < sizeof (MonoThunkFreeList))
1622 size = sizeof (MonoThunkFreeList);
1624 i = list_index_for_size (size);
1625 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1626 if ((*l)->size >= size) {
1627 MonoThunkFreeList *item = *l;
1628 *l = item->next;
1629 return ((guint32*)item) + 1;
1633 /* no suitable item found - search lists of larger sizes */
1634 while (++i < NUM_FREE_LISTS) {
1635 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1636 if (!item)
1637 continue;
1638 g_assert (item->size > size);
1639 domain->thunk_free_lists [i] = item->next;
1640 return ((guint32*)item) + 1;
1643 /* still nothing found - allocate it */
1644 if (!inited) {
1645 mono_counters_register ("Generic virtual thunk bytes",
1646 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1647 inited = TRUE;
1649 generic_virtual_thunks_size += size;
1651 p = (guint32 *)mono_domain_code_reserve (domain, size);
1652 *p = size;
1654 mono_domain_lock (domain);
1655 if (!domain->generic_virtual_thunks)
1656 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1657 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1658 mono_domain_unlock (domain);
1660 return p + 1;
1664 * LOCKING: The domain lock must be held.
1666 static void
1667 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1669 MONO_REQ_GC_NEUTRAL_MODE;
1671 guint32 *p = (guint32 *)code;
1672 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1673 gboolean found = FALSE;
1675 mono_domain_lock (domain);
1676 if (!domain->generic_virtual_thunks)
1677 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1678 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1679 found = TRUE;
1680 mono_domain_unlock (domain);
1682 if (!found)
1683 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1684 return;
1685 init_thunk_free_lists (domain);
1687 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1688 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1689 int length = item->length;
1690 int i;
1692 /* unlink the first item from the wait list */
1693 domain->thunk_free_lists [0] = item->next;
1694 domain->thunk_free_lists [0]->length = length - 1;
1696 i = list_index_for_size (item->size);
1698 /* put it in the free list */
1699 item->next = domain->thunk_free_lists [i];
1700 domain->thunk_free_lists [i] = item;
1703 l->next = NULL;
1704 if (domain->thunk_free_lists [1]) {
1705 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1706 domain->thunk_free_lists [0]->length++;
1707 } else {
1708 g_assert (!domain->thunk_free_lists [0]);
1710 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1711 domain->thunk_free_lists [0]->length = 1;
1715 typedef struct _GenericVirtualCase {
1716 MonoMethod *method;
1717 gpointer code;
1718 int count;
1719 struct _GenericVirtualCase *next;
1720 } GenericVirtualCase;
1723 * get_generic_virtual_entries:
1725 * Return IMT entries for the generic virtual method instances and
1726 * variant interface methods for vtable slot
1727 * VTABLE_SLOT.
1729 static MonoImtBuilderEntry*
1730 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1732 MONO_REQ_GC_NEUTRAL_MODE;
1734 GenericVirtualCase *list;
1735 MonoImtBuilderEntry *entries;
1737 mono_domain_lock (domain);
1738 if (!domain->generic_virtual_cases)
1739 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1741 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1743 entries = NULL;
1744 for (; list; list = list->next) {
1745 MonoImtBuilderEntry *entry;
1747 if (list->count < THUNK_THRESHOLD)
1748 continue;
1750 entry = g_new0 (MonoImtBuilderEntry, 1);
1751 entry->key = list->method;
1752 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1753 entry->has_target_code = 1;
1754 if (entries)
1755 entry->children = entries->children + 1;
1756 entry->next = entries;
1757 entries = entry;
1760 mono_domain_unlock (domain);
1762 /* FIXME: Leaking memory ? */
1763 return entries;
1767 * mono_method_add_generic_virtual_invocation:
1768 * @domain: a domain
1769 * @vtable_slot: pointer to the vtable slot
1770 * @method: the inflated generic virtual method
1771 * @code: the method's code
1773 * Registers a call via unmanaged code to a generic virtual method
1774 * instantiation or variant interface method. If the number of calls reaches a threshold
1775 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1776 * virtual method thunk.
1778 void
1779 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1780 gpointer *vtable_slot,
1781 MonoMethod *method, gpointer code)
1783 MONO_REQ_GC_NEUTRAL_MODE;
1785 static gboolean inited = FALSE;
1786 static int num_added = 0;
1788 GenericVirtualCase *gvc, *list;
1789 MonoImtBuilderEntry *entries;
1790 int i;
1791 GPtrArray *sorted;
1793 mono_domain_lock (domain);
1794 if (!domain->generic_virtual_cases)
1795 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1797 /* Check whether the case was already added */
1798 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1799 gvc = list;
1800 while (gvc) {
1801 if (gvc->method == method)
1802 break;
1803 gvc = gvc->next;
1806 /* If not found, make a new one */
1807 if (!gvc) {
1808 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1809 gvc->method = method;
1810 gvc->code = code;
1811 gvc->count = 0;
1812 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1814 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1816 if (!inited) {
1817 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1818 inited = TRUE;
1820 num_added++;
1823 if (++gvc->count == THUNK_THRESHOLD) {
1824 gpointer *old_thunk = (void **)*vtable_slot;
1825 gpointer vtable_trampoline = NULL;
1826 gpointer imt_trampoline = NULL;
1828 if ((gpointer)vtable_slot < (gpointer)vtable) {
1829 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1830 int imt_slot = MONO_IMT_SIZE + displacement;
1832 /* Force the rebuild of the thunk at the next call */
1833 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1834 *vtable_slot = imt_trampoline;
1835 } else {
1836 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1838 entries = get_generic_virtual_entries (domain, vtable_slot);
1840 sorted = imt_sort_slot_entries (entries);
1842 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1843 vtable_trampoline);
1845 while (entries) {
1846 MonoImtBuilderEntry *next = entries->next;
1847 g_free (entries);
1848 entries = next;
1851 for (i = 0; i < sorted->len; ++i)
1852 g_free (g_ptr_array_index (sorted, i));
1853 g_ptr_array_free (sorted, TRUE);
1856 #ifndef __native_client__
1857 /* We don't re-use any thunks as there is a lot of overhead */
1858 /* to deleting and re-using code in Native Client. */
1859 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1860 invalidate_generic_virtual_thunk (domain, old_thunk);
1861 #endif
1864 mono_domain_unlock (domain);
1867 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1870 * mono_class_vtable:
1871 * @domain: the application domain
1872 * @class: the class to initialize
1874 * VTables are domain specific because we create domain specific code, and
1875 * they contain the domain specific static class data.
1876 * On failure, NULL is returned, and class->exception_type is set.
1878 MonoVTable *
1879 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1881 MonoError error;
1882 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1883 mono_error_cleanup (&error);
1884 return vtable;
1888 * mono_class_vtable_full:
1889 * @domain: the application domain
1890 * @class: the class to initialize
1891 * @error set on failure.
1893 * VTables are domain specific because we create domain specific code, and
1894 * they contain the domain specific static class data.
1896 MonoVTable *
1897 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1899 MONO_REQ_GC_UNSAFE_MODE;
1901 MonoClassRuntimeInfo *runtime_info;
1903 mono_error_init (error);
1905 g_assert (klass);
1907 if (mono_class_has_failure (klass)) {
1908 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1909 return NULL;
1912 /* this check can be inlined in jitted code, too */
1913 runtime_info = klass->runtime_info;
1914 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1915 return runtime_info->domain_vtables [domain->domain_id];
1916 return mono_class_create_runtime_vtable (domain, klass, error);
1920 * mono_class_try_get_vtable:
1921 * @domain: the application domain
1922 * @class: the class to initialize
1924 * This function tries to get the associated vtable from @class if
1925 * it was already created.
1927 MonoVTable *
1928 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1930 MONO_REQ_GC_NEUTRAL_MODE;
1932 MonoClassRuntimeInfo *runtime_info;
1934 g_assert (klass);
1936 runtime_info = klass->runtime_info;
1937 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1938 return runtime_info->domain_vtables [domain->domain_id];
1939 return NULL;
1942 static gpointer*
1943 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1945 MONO_REQ_GC_NEUTRAL_MODE;
1947 size_t alloc_offset;
1950 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1951 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1952 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1954 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1955 g_assert ((imt_table_bytes & 7) == 4);
1956 vtable_size += 4;
1957 alloc_offset = 4;
1958 } else {
1959 alloc_offset = 0;
1962 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1965 static MonoVTable *
1966 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1968 MONO_REQ_GC_UNSAFE_MODE;
1970 MonoVTable *vt;
1971 MonoClassRuntimeInfo *runtime_info, *old_info;
1972 MonoClassField *field;
1973 char *t;
1974 int i, vtable_slots;
1975 size_t imt_table_bytes;
1976 int gc_bits;
1977 guint32 vtable_size, class_size;
1978 gpointer iter;
1979 gpointer *interface_offsets;
1981 mono_error_init (error);
1983 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1984 mono_domain_lock (domain);
1985 runtime_info = klass->runtime_info;
1986 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1987 mono_domain_unlock (domain);
1988 mono_loader_unlock ();
1989 return runtime_info->domain_vtables [domain->domain_id];
1991 if (!klass->inited || mono_class_has_failure (klass)) {
1992 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1993 mono_domain_unlock (domain);
1994 mono_loader_unlock ();
1995 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1996 return NULL;
2000 /* Array types require that their element type be valid*/
2001 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
2002 MonoClass *element_class = klass->element_class;
2003 if (!element_class->inited)
2004 mono_class_init (element_class);
2006 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
2007 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
2008 mono_class_setup_vtable (element_class);
2010 if (mono_class_has_failure (element_class)) {
2011 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2012 if (!mono_class_has_failure (klass))
2013 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
2014 mono_domain_unlock (domain);
2015 mono_loader_unlock ();
2016 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2017 return NULL;
2022 * For some classes, mono_class_init () already computed klass->vtable_size, and
2023 * that is all that is needed because of the vtable trampolines.
2025 if (!klass->vtable_size)
2026 mono_class_setup_vtable (klass);
2028 if (klass->generic_class && !klass->vtable)
2029 mono_class_check_vtable_constraints (klass, NULL);
2031 /* Initialize klass->has_finalize */
2032 mono_class_has_finalizer (klass);
2034 if (mono_class_has_failure (klass)) {
2035 mono_domain_unlock (domain);
2036 mono_loader_unlock ();
2037 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2038 return NULL;
2041 vtable_slots = klass->vtable_size;
2042 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2043 class_size = mono_class_data_size (klass);
2044 if (class_size)
2045 vtable_slots++;
2047 if (klass->interface_offsets_count) {
2048 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2049 mono_stats.imt_number_of_tables++;
2050 mono_stats.imt_tables_size += imt_table_bytes;
2051 } else {
2052 imt_table_bytes = 0;
2055 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2057 mono_stats.used_class_count++;
2058 mono_stats.class_vtable_size += vtable_size;
2060 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2061 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2062 g_assert (!((gsize)vt & 7));
2064 vt->klass = klass;
2065 vt->rank = klass->rank;
2066 vt->domain = domain;
2068 mono_class_compute_gc_descriptor (klass);
2070 * We can't use typed allocation in the non-root domains, since the
2071 * collector needs the GC descriptor stored in the vtable even after
2072 * the mempool containing the vtable is destroyed when the domain is
2073 * unloaded. An alternative might be to allocate vtables in the GC
2074 * heap, but this does not seem to work (it leads to crashes inside
2075 * libgc). If that approach is tried, two gc descriptors need to be
2076 * allocated for each class: one for the root domain, and one for all
2077 * other domains. The second descriptor should contain a bit for the
2078 * vtable field in MonoObject, since we can no longer assume the
2079 * vtable is reachable by other roots after the appdomain is unloaded.
2081 #ifdef HAVE_BOEHM_GC
2082 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2083 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2084 else
2085 #endif
2086 vt->gc_descr = klass->gc_descr;
2088 gc_bits = mono_gc_get_vtable_bits (klass);
2089 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2091 vt->gc_bits = gc_bits;
2093 if (class_size) {
2094 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2095 if (klass->has_static_refs) {
2096 MonoGCDescriptor statics_gc_descr;
2097 int max_set = 0;
2098 gsize default_bitmap [4] = {0};
2099 gsize *bitmap;
2101 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2102 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2103 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2104 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2105 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2106 if (bitmap != default_bitmap)
2107 g_free (bitmap);
2108 } else {
2109 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2111 vt->has_static_fields = TRUE;
2112 mono_stats.class_static_data_size += class_size;
2115 iter = NULL;
2116 while ((field = mono_class_get_fields (klass, &iter))) {
2117 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2118 continue;
2119 if (mono_field_is_deleted (field))
2120 continue;
2121 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2122 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2123 if (special_static != SPECIAL_STATIC_NONE) {
2124 guint32 size, offset;
2125 gint32 align;
2126 gsize default_bitmap [4] = {0};
2127 gsize *bitmap;
2128 int max_set = 0;
2129 int numbits;
2130 MonoClass *fclass;
2131 if (mono_type_is_reference (field->type)) {
2132 default_bitmap [0] = 1;
2133 numbits = 1;
2134 bitmap = default_bitmap;
2135 } else if (mono_type_is_struct (field->type)) {
2136 fclass = mono_class_from_mono_type (field->type);
2137 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2138 numbits = max_set + 1;
2139 } else {
2140 default_bitmap [0] = 0;
2141 numbits = 0;
2142 bitmap = default_bitmap;
2144 size = mono_type_size (field->type, &align);
2145 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2146 if (!domain->special_static_fields)
2147 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2148 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2149 if (bitmap != default_bitmap)
2150 g_free (bitmap);
2152 * This marks the field as special static to speed up the
2153 * checks in mono_field_static_get/set_value ().
2155 field->offset = -1;
2156 continue;
2159 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2160 MonoClass *fklass = mono_class_from_mono_type (field->type);
2161 const char *data = mono_field_get_data (field);
2163 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2164 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2165 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2166 if (!data)
2167 continue;
2168 if (fklass->valuetype) {
2169 memcpy (t, data, mono_class_value_size (fklass, NULL));
2170 } else {
2171 /* it's a pointer type: add check */
2172 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2173 *t = *(char *)data;
2175 continue;
2179 vt->max_interface_id = klass->max_interface_id;
2180 vt->interface_bitmap = klass->interface_bitmap;
2182 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2183 // class->name, klass->interface_offsets_count);
2185 /* Initialize vtable */
2186 if (callbacks.get_vtable_trampoline) {
2187 // This also covers the AOT case
2188 for (i = 0; i < klass->vtable_size; ++i) {
2189 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2191 } else {
2192 mono_class_setup_vtable (klass);
2194 for (i = 0; i < klass->vtable_size; ++i) {
2195 MonoMethod *cm;
2197 cm = klass->vtable [i];
2198 if (cm) {
2199 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2200 if (!is_ok (error)) {
2201 mono_domain_unlock (domain);
2202 mono_loader_unlock ();
2203 return NULL;
2209 if (imt_table_bytes) {
2210 /* Now that the vtable is full, we can actually fill up the IMT */
2211 for (i = 0; i < MONO_IMT_SIZE; ++i)
2212 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2216 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2217 * re-acquire them and check if another thread has created the vtable in the meantime.
2219 /* Special case System.MonoType to avoid infinite recursion */
2220 if (klass != mono_defaults.runtimetype_class) {
2221 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2222 if (!is_ok (error)) {
2223 mono_domain_unlock (domain);
2224 mono_loader_unlock ();
2225 return NULL;
2228 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2229 /* This is unregistered in
2230 unregister_vtable_reflection_type() in
2231 domain.c. */
2232 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2235 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2237 /* class_vtable_array keeps an array of created vtables
2239 g_ptr_array_add (domain->class_vtable_array, vt);
2240 /* klass->runtime_info is protected by the loader lock, both when
2241 * it it enlarged and when it is stored info.
2245 * Store the vtable in klass->runtime_info.
2246 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2248 mono_memory_barrier ();
2250 old_info = klass->runtime_info;
2251 if (old_info && old_info->max_domain >= domain->domain_id) {
2252 /* someone already created a large enough runtime info */
2253 old_info->domain_vtables [domain->domain_id] = vt;
2254 } else {
2255 int new_size = domain->domain_id;
2256 if (old_info)
2257 new_size = MAX (new_size, old_info->max_domain);
2258 new_size++;
2259 /* make the new size a power of two */
2260 i = 2;
2261 while (new_size > i)
2262 i <<= 1;
2263 new_size = i;
2264 /* this is a bounded memory retention issue: may want to
2265 * handle it differently when we'll have a rcu-like system.
2267 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2268 runtime_info->max_domain = new_size - 1;
2269 /* copy the stuff from the older info */
2270 if (old_info) {
2271 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2273 runtime_info->domain_vtables [domain->domain_id] = vt;
2274 /* keep this last*/
2275 mono_memory_barrier ();
2276 klass->runtime_info = runtime_info;
2279 if (klass == mono_defaults.runtimetype_class) {
2280 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2281 if (!is_ok (error)) {
2282 mono_domain_unlock (domain);
2283 mono_loader_unlock ();
2284 return NULL;
2287 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2288 /* This is unregistered in
2289 unregister_vtable_reflection_type() in
2290 domain.c. */
2291 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2294 mono_domain_unlock (domain);
2295 mono_loader_unlock ();
2297 /* make sure the parent is initialized */
2298 /*FIXME shouldn't this fail the current type?*/
2299 if (klass->parent)
2300 mono_class_vtable_full (domain, klass->parent, error);
2302 return vt;
2305 #ifndef DISABLE_REMOTING
2307 * mono_class_proxy_vtable:
2308 * @domain: the application domain
2309 * @remove_class: the remote class
2310 * @error: set on error
2312 * Creates a vtable for transparent proxies. It is basically
2313 * a copy of the real vtable of the class wrapped in @remote_class,
2314 * but all function pointers invoke the remoting functions, and
2315 * vtable->klass points to the transparent proxy class, and not to @class.
2317 * On failure returns NULL and sets @error
2319 static MonoVTable *
2320 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2322 MONO_REQ_GC_UNSAFE_MODE;
2324 MonoVTable *vt, *pvt;
2325 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2326 MonoClass *k;
2327 GSList *extra_interfaces = NULL;
2328 MonoClass *klass = remote_class->proxy_class;
2329 gpointer *interface_offsets;
2330 uint8_t *bitmap = NULL;
2331 int bsize;
2332 size_t imt_table_bytes;
2334 #ifdef COMPRESSED_INTERFACE_BITMAP
2335 int bcsize;
2336 #endif
2338 mono_error_init (error);
2340 vt = mono_class_vtable (domain, klass);
2341 g_assert (vt); /*FIXME property handle failure*/
2342 max_interface_id = vt->max_interface_id;
2344 /* Calculate vtable space for extra interfaces */
2345 for (j = 0; j < remote_class->interface_count; j++) {
2346 MonoClass* iclass = remote_class->interfaces[j];
2347 GPtrArray *ifaces;
2348 int method_count;
2350 /*FIXME test for interfaces with variant generic arguments*/
2351 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2352 continue; /* interface implemented by the class */
2353 if (g_slist_find (extra_interfaces, iclass))
2354 continue;
2356 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2358 method_count = mono_class_num_methods (iclass);
2360 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2361 if (!is_ok (error))
2362 goto failure;
2363 if (ifaces) {
2364 for (i = 0; i < ifaces->len; ++i) {
2365 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2366 /*FIXME test for interfaces with variant generic arguments*/
2367 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2368 continue; /* interface implemented by the class */
2369 if (g_slist_find (extra_interfaces, ic))
2370 continue;
2371 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2372 method_count += mono_class_num_methods (ic);
2374 g_ptr_array_free (ifaces, TRUE);
2375 ifaces = NULL;
2378 extra_interface_vtsize += method_count * sizeof (gpointer);
2379 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2382 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2383 mono_stats.imt_number_of_tables++;
2384 mono_stats.imt_tables_size += imt_table_bytes;
2386 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2388 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2390 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2391 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2392 g_assert (!((gsize)pvt & 7));
2394 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2396 pvt->klass = mono_defaults.transparent_proxy_class;
2397 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2398 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2400 /* initialize vtable */
2401 mono_class_setup_vtable (klass);
2402 for (i = 0; i < klass->vtable_size; ++i) {
2403 MonoMethod *cm;
2405 if ((cm = klass->vtable [i])) {
2406 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2407 if (!is_ok (error))
2408 goto failure;
2409 } else
2410 pvt->vtable [i] = NULL;
2413 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2414 /* create trampolines for abstract methods */
2415 for (k = klass; k; k = k->parent) {
2416 MonoMethod* m;
2417 gpointer iter = NULL;
2418 while ((m = mono_class_get_methods (k, &iter)))
2419 if (!pvt->vtable [m->slot]) {
2420 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2421 if (!is_ok (error))
2422 goto failure;
2427 pvt->max_interface_id = max_interface_id;
2428 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2429 #ifdef COMPRESSED_INTERFACE_BITMAP
2430 bitmap = (uint8_t *)g_malloc0 (bsize);
2431 #else
2432 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2433 #endif
2435 for (i = 0; i < klass->interface_offsets_count; ++i) {
2436 int interface_id = klass->interfaces_packed [i]->interface_id;
2437 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2440 if (extra_interfaces) {
2441 int slot = klass->vtable_size;
2442 MonoClass* interf;
2443 gpointer iter;
2444 MonoMethod* cm;
2445 GSList *list_item;
2447 /* Create trampolines for the methods of the interfaces */
2448 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2449 interf = (MonoClass *)list_item->data;
2451 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2453 iter = NULL;
2454 j = 0;
2455 while ((cm = mono_class_get_methods (interf, &iter))) {
2456 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2457 if (!is_ok (error))
2458 goto failure;
2461 slot += mono_class_num_methods (interf);
2465 /* Now that the vtable is full, we can actually fill up the IMT */
2466 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2467 if (extra_interfaces) {
2468 g_slist_free (extra_interfaces);
2471 #ifdef COMPRESSED_INTERFACE_BITMAP
2472 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2473 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2474 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2475 g_free (bitmap);
2476 #else
2477 pvt->interface_bitmap = bitmap;
2478 #endif
2479 return pvt;
2480 failure:
2481 if (extra_interfaces)
2482 g_slist_free (extra_interfaces);
2483 #ifdef COMPRESSED_INTERFACE_BITMAP
2484 g_free (bitmap);
2485 #endif
2486 return NULL;
2489 #endif /* DISABLE_REMOTING */
2492 * mono_class_field_is_special_static:
2494 * Returns whether @field is a thread/context static field.
2496 gboolean
2497 mono_class_field_is_special_static (MonoClassField *field)
2499 MONO_REQ_GC_NEUTRAL_MODE
2501 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2502 return FALSE;
2503 if (mono_field_is_deleted (field))
2504 return FALSE;
2505 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2506 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2507 return TRUE;
2509 return FALSE;
2513 * mono_class_field_get_special_static_type:
2514 * @field: The MonoClassField describing the field.
2516 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2517 * SPECIAL_STATIC_NONE otherwise.
2519 guint32
2520 mono_class_field_get_special_static_type (MonoClassField *field)
2522 MONO_REQ_GC_NEUTRAL_MODE
2524 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2525 return SPECIAL_STATIC_NONE;
2526 if (mono_field_is_deleted (field))
2527 return SPECIAL_STATIC_NONE;
2528 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2529 return field_is_special_static (field->parent, field);
2530 return SPECIAL_STATIC_NONE;
2534 * mono_class_has_special_static_fields:
2536 * Returns whenever @klass has any thread/context static fields.
2538 gboolean
2539 mono_class_has_special_static_fields (MonoClass *klass)
2541 MONO_REQ_GC_NEUTRAL_MODE
2543 MonoClassField *field;
2544 gpointer iter;
2546 iter = NULL;
2547 while ((field = mono_class_get_fields (klass, &iter))) {
2548 g_assert (field->parent == klass);
2549 if (mono_class_field_is_special_static (field))
2550 return TRUE;
2553 return FALSE;
2556 #ifndef DISABLE_REMOTING
2558 * create_remote_class_key:
2559 * Creates an array of pointers that can be used as a hash key for a remote class.
2560 * The first element of the array is the number of pointers.
2562 static gpointer*
2563 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2565 MONO_REQ_GC_NEUTRAL_MODE;
2567 gpointer *key;
2568 int i, j;
2570 if (remote_class == NULL) {
2571 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2572 key = (void **)g_malloc (sizeof(gpointer) * 3);
2573 key [0] = GINT_TO_POINTER (2);
2574 key [1] = mono_defaults.marshalbyrefobject_class;
2575 key [2] = extra_class;
2576 } else {
2577 key = (void **)g_malloc (sizeof(gpointer) * 2);
2578 key [0] = GINT_TO_POINTER (1);
2579 key [1] = extra_class;
2581 } else {
2582 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2583 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2584 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2585 key [1] = remote_class->proxy_class;
2587 // Keep the list of interfaces sorted
2588 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2589 if (extra_class && remote_class->interfaces [i] > extra_class) {
2590 key [j++] = extra_class;
2591 extra_class = NULL;
2593 key [j] = remote_class->interfaces [i];
2595 if (extra_class)
2596 key [j] = extra_class;
2597 } else {
2598 // Replace the old class. The interface list is the same
2599 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2600 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2601 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2602 for (i = 0; i < remote_class->interface_count; i++)
2603 key [2 + i] = remote_class->interfaces [i];
2607 return key;
2611 * copy_remote_class_key:
2613 * Make a copy of KEY in the domain and return the copy.
2615 static gpointer*
2616 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2618 MONO_REQ_GC_NEUTRAL_MODE
2620 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2621 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2623 memcpy (mp_key, key, key_size);
2625 return mp_key;
2629 * mono_remote_class:
2630 * @domain: the application domain
2631 * @class_name: name of the remote class
2632 * @error: set on error
2634 * Creates and initializes a MonoRemoteClass object for a remote type.
2636 * On failure returns NULL and sets @error
2638 MonoRemoteClass*
2639 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2641 MONO_REQ_GC_UNSAFE_MODE;
2643 MonoRemoteClass *rc;
2644 gpointer* key, *mp_key;
2645 char *name;
2647 mono_error_init (error);
2649 key = create_remote_class_key (NULL, proxy_class);
2651 mono_domain_lock (domain);
2652 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2654 if (rc) {
2655 g_free (key);
2656 mono_domain_unlock (domain);
2657 return rc;
2660 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2661 if (!is_ok (error)) {
2662 g_free (key);
2663 mono_domain_unlock (domain);
2664 return NULL;
2667 mp_key = copy_remote_class_key (domain, key);
2668 g_free (key);
2669 key = mp_key;
2671 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2672 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2673 rc->interface_count = 1;
2674 rc->interfaces [0] = proxy_class;
2675 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2676 } else {
2677 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2678 rc->interface_count = 0;
2679 rc->proxy_class = proxy_class;
2682 rc->default_vtable = NULL;
2683 rc->xdomain_vtable = NULL;
2684 rc->proxy_class_name = name;
2685 #ifndef DISABLE_PERFCOUNTERS
2686 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2687 #endif
2689 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2691 mono_domain_unlock (domain);
2692 return rc;
2696 * clone_remote_class:
2697 * Creates a copy of the remote_class, adding the provided class or interface
2699 static MonoRemoteClass*
2700 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2702 MONO_REQ_GC_NEUTRAL_MODE;
2704 MonoRemoteClass *rc;
2705 gpointer* key, *mp_key;
2707 key = create_remote_class_key (remote_class, extra_class);
2708 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2709 if (rc != NULL) {
2710 g_free (key);
2711 return rc;
2714 mp_key = copy_remote_class_key (domain, key);
2715 g_free (key);
2716 key = mp_key;
2718 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2719 int i,j;
2720 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2721 rc->proxy_class = remote_class->proxy_class;
2722 rc->interface_count = remote_class->interface_count + 1;
2724 // Keep the list of interfaces sorted, since the hash key of
2725 // the remote class depends on this
2726 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2727 if (remote_class->interfaces [i] > extra_class && i == j)
2728 rc->interfaces [j++] = extra_class;
2729 rc->interfaces [j] = remote_class->interfaces [i];
2731 if (i == j)
2732 rc->interfaces [j] = extra_class;
2733 } else {
2734 // Replace the old class. The interface array is the same
2735 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2736 rc->proxy_class = extra_class;
2737 rc->interface_count = remote_class->interface_count;
2738 if (rc->interface_count > 0)
2739 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2742 rc->default_vtable = NULL;
2743 rc->xdomain_vtable = NULL;
2744 rc->proxy_class_name = remote_class->proxy_class_name;
2746 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2748 return rc;
2751 gpointer
2752 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2754 MONO_REQ_GC_UNSAFE_MODE;
2756 mono_error_init (error);
2758 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2759 mono_domain_lock (domain);
2760 if (rp->target_domain_id != -1) {
2761 if (remote_class->xdomain_vtable == NULL)
2762 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2763 mono_domain_unlock (domain);
2764 mono_loader_unlock ();
2765 return_val_if_nok (error, NULL);
2766 return remote_class->xdomain_vtable;
2768 if (remote_class->default_vtable == NULL) {
2769 MonoType *type;
2770 MonoClass *klass;
2771 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2772 klass = mono_class_from_mono_type (type);
2773 #ifndef DISABLE_COM
2774 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)))
2775 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2776 else
2777 #endif
2778 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2779 /* N.B. both branches of the if modify error */
2780 if (!is_ok (error)) {
2781 mono_domain_unlock (domain);
2782 mono_loader_unlock ();
2783 return NULL;
2787 mono_domain_unlock (domain);
2788 mono_loader_unlock ();
2789 return remote_class->default_vtable;
2793 * mono_upgrade_remote_class:
2794 * @domain: the application domain
2795 * @tproxy: the proxy whose remote class has to be upgraded.
2796 * @klass: class to which the remote class can be casted.
2797 * @error: set on error
2799 * Updates the vtable of the remote class by adding the necessary method slots
2800 * and interface offsets so it can be safely casted to klass. klass can be a
2801 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2803 gboolean
2804 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2806 MONO_REQ_GC_UNSAFE_MODE;
2808 MonoTransparentProxy *tproxy;
2809 MonoRemoteClass *remote_class;
2810 gboolean redo_vtable;
2812 mono_error_init (error);
2813 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2814 mono_domain_lock (domain);
2816 tproxy = (MonoTransparentProxy*) proxy_object;
2817 remote_class = tproxy->remote_class;
2819 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2820 int i;
2821 redo_vtable = TRUE;
2822 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2823 if (remote_class->interfaces [i] == klass)
2824 redo_vtable = FALSE;
2826 else {
2827 redo_vtable = (remote_class->proxy_class != klass);
2830 if (redo_vtable) {
2831 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2832 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2833 if (!is_ok (error))
2834 goto leave;
2837 leave:
2838 mono_domain_unlock (domain);
2839 mono_loader_unlock ();
2840 return is_ok (error);
2842 #endif /* DISABLE_REMOTING */
2846 * mono_object_get_virtual_method:
2847 * @obj: object to operate on.
2848 * @method: method
2850 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2851 * the instance of a callvirt of method.
2853 MonoMethod*
2854 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2856 MONO_REQ_GC_UNSAFE_MODE;
2858 MonoClass *klass;
2859 MonoMethod **vtable;
2860 gboolean is_proxy = FALSE;
2861 MonoMethod *res = NULL;
2863 klass = mono_object_class (obj);
2864 #ifndef DISABLE_REMOTING
2865 if (klass == mono_defaults.transparent_proxy_class) {
2866 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2867 is_proxy = TRUE;
2869 #endif
2871 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2872 return method;
2874 mono_class_setup_vtable (klass);
2875 vtable = klass->vtable;
2877 if (method->slot == -1) {
2878 /* method->slot might not be set for instances of generic methods */
2879 if (method->is_inflated) {
2880 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2881 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2882 } else {
2883 if (!is_proxy)
2884 g_assert_not_reached ();
2888 /* check method->slot is a valid index: perform isinstance? */
2889 if (method->slot != -1) {
2890 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2891 if (!is_proxy) {
2892 gboolean variance_used = FALSE;
2893 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2894 g_assert (iface_offset > 0);
2895 res = vtable [iface_offset + method->slot];
2897 } else {
2898 res = vtable [method->slot];
2902 #ifndef DISABLE_REMOTING
2903 if (is_proxy) {
2904 /* It may be an interface, abstract class method or generic method */
2905 if (!res || mono_method_signature (res)->generic_param_count)
2906 res = method;
2908 /* generic methods demand invoke_with_check */
2909 if (mono_method_signature (res)->generic_param_count)
2910 res = mono_marshal_get_remoting_invoke_with_check (res);
2911 else {
2912 #ifndef DISABLE_COM
2913 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2914 res = mono_cominterop_get_invoke (res);
2915 else
2916 #endif
2917 res = mono_marshal_get_remoting_invoke (res);
2919 } else
2920 #endif
2922 if (method->is_inflated) {
2923 MonoError error;
2924 /* Have to inflate the result */
2925 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2926 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2930 g_assert (res);
2932 return res;
2935 static MonoObject*
2936 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2938 MONO_REQ_GC_UNSAFE_MODE;
2940 MonoObject *result = NULL;
2942 g_assert (callbacks.runtime_invoke);
2944 mono_error_init (error);
2946 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2947 mono_profiler_method_start_invoke (method);
2949 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2951 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2952 mono_profiler_method_end_invoke (method);
2954 if (!mono_error_ok (error))
2955 return NULL;
2957 return result;
2961 * mono_runtime_invoke:
2962 * @method: method to invoke
2963 * @obJ: object instance
2964 * @params: arguments to the method
2965 * @exc: exception information.
2967 * Invokes the method represented by @method on the object @obj.
2969 * obj is the 'this' pointer, it should be NULL for static
2970 * methods, a MonoObject* for object instances and a pointer to
2971 * the value type for value types.
2973 * The params array contains the arguments to the method with the
2974 * same convention: MonoObject* pointers for object instances and
2975 * pointers to the value type otherwise.
2977 * From unmanaged code you'll usually use the
2978 * mono_runtime_invoke() variant.
2980 * Note that this function doesn't handle virtual methods for
2981 * you, it will exec the exact method you pass: we still need to
2982 * expose a function to lookup the derived class implementation
2983 * of a virtual method (there are examples of this in the code,
2984 * though).
2986 * You can pass NULL as the exc argument if you don't want to
2987 * catch exceptions, otherwise, *exc will be set to the exception
2988 * thrown, if any. if an exception is thrown, you can't use the
2989 * MonoObject* result from the function.
2991 * If the method returns a value type, it is boxed in an object
2992 * reference.
2994 MonoObject*
2995 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2997 MonoError error;
2998 MonoObject *res;
2999 if (exc) {
3000 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
3001 if (*exc == NULL && !mono_error_ok(&error)) {
3002 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3003 } else
3004 mono_error_cleanup (&error);
3005 } else {
3006 res = mono_runtime_invoke_checked (method, obj, params, &error);
3007 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3009 return res;
3013 * mono_runtime_try_invoke:
3014 * @method: method to invoke
3015 * @obJ: object instance
3016 * @params: arguments to the method
3017 * @exc: exception information.
3018 * @error: set on error
3020 * Invokes the method represented by @method on the object @obj.
3022 * obj is the 'this' pointer, it should be NULL for static
3023 * methods, a MonoObject* for object instances and a pointer to
3024 * the value type for value types.
3026 * The params array contains the arguments to the method with the
3027 * same convention: MonoObject* pointers for object instances and
3028 * pointers to the value type otherwise.
3030 * From unmanaged code you'll usually use the
3031 * mono_runtime_invoke() variant.
3033 * Note that this function doesn't handle virtual methods for
3034 * you, it will exec the exact method you pass: we still need to
3035 * expose a function to lookup the derived class implementation
3036 * of a virtual method (there are examples of this in the code,
3037 * though).
3039 * For this function, you must not pass NULL as the exc argument if
3040 * you don't want to catch exceptions, use
3041 * mono_runtime_invoke_checked(). If an exception is thrown, you
3042 * can't use the MonoObject* result from the function.
3044 * If this method cannot be invoked, @error will be set and @exc and
3045 * the return value must not be used.
3047 * If the method returns a value type, it is boxed in an object
3048 * reference.
3050 MonoObject*
3051 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3053 MONO_REQ_GC_UNSAFE_MODE;
3055 g_assert (exc != NULL);
3057 if (mono_runtime_get_no_exec ())
3058 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3060 return do_runtime_invoke (method, obj, params, exc, error);
3064 * mono_runtime_invoke_checked:
3065 * @method: method to invoke
3066 * @obJ: object instance
3067 * @params: arguments to the method
3068 * @error: set on error
3070 * Invokes the method represented by @method on the object @obj.
3072 * obj is the 'this' pointer, it should be NULL for static
3073 * methods, a MonoObject* for object instances and a pointer to
3074 * the value type for value types.
3076 * The params array contains the arguments to the method with the
3077 * same convention: MonoObject* pointers for object instances and
3078 * pointers to the value type otherwise.
3080 * From unmanaged code you'll usually use the
3081 * mono_runtime_invoke() variant.
3083 * Note that this function doesn't handle virtual methods for
3084 * you, it will exec the exact method you pass: we still need to
3085 * expose a function to lookup the derived class implementation
3086 * of a virtual method (there are examples of this in the code,
3087 * though).
3089 * If an exception is thrown, you can't use the MonoObject* result
3090 * from the function.
3092 * If this method cannot be invoked, @error will be set. If the
3093 * method throws an exception (and we're in coop mode) the exception
3094 * will be set in @error.
3096 * If the method returns a value type, it is boxed in an object
3097 * reference.
3099 MonoObject*
3100 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3102 MONO_REQ_GC_UNSAFE_MODE;
3104 if (mono_runtime_get_no_exec ())
3105 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3107 return do_runtime_invoke (method, obj, params, NULL, error);
3111 * mono_method_get_unmanaged_thunk:
3112 * @method: method to generate a thunk for.
3114 * Returns an unmanaged->managed thunk that can be used to call
3115 * a managed method directly from C.
3117 * The thunk's C signature closely matches the managed signature:
3119 * C#: public bool Equals (object obj);
3120 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3121 * MonoObject*, MonoException**);
3123 * The 1st ("this") parameter must not be used with static methods:
3125 * C#: public static bool ReferenceEquals (object a, object b);
3126 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3127 * MonoException**);
3129 * The last argument must be a non-null pointer of a MonoException* pointer.
3130 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3131 * exception has been thrown in managed code. Otherwise it will point
3132 * to the MonoException* caught by the thunk. In this case, the result of
3133 * the thunk is undefined:
3135 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3136 * MonoException *ex = NULL;
3137 * Equals func = mono_method_get_unmanaged_thunk (method);
3138 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3139 * if (ex) {
3140 * // handle exception
3143 * The calling convention of the thunk matches the platform's default
3144 * convention. This means that under Windows, C declarations must
3145 * contain the __stdcall attribute:
3147 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3148 * MonoObject*, MonoException**);
3150 * LIMITATIONS
3152 * Value type arguments and return values are treated as they were objects:
3154 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3155 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3157 * Arguments must be properly boxed upon trunk's invocation, while return
3158 * values must be unboxed.
3160 gpointer
3161 mono_method_get_unmanaged_thunk (MonoMethod *method)
3163 MONO_REQ_GC_NEUTRAL_MODE;
3164 MONO_REQ_API_ENTRYPOINT;
3166 MonoError error;
3167 gpointer res;
3169 g_assert (!mono_threads_is_coop_enabled ());
3171 MONO_ENTER_GC_UNSAFE;
3172 method = mono_marshal_get_thunk_invoke_wrapper (method);
3173 res = mono_compile_method_checked (method, &error);
3174 mono_error_cleanup (&error);
3175 MONO_EXIT_GC_UNSAFE;
3177 return res;
3180 void
3181 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3183 MONO_REQ_GC_UNSAFE_MODE;
3185 int t;
3186 if (type->byref) {
3187 /* object fields cannot be byref, so we don't need a
3188 wbarrier here */
3189 gpointer *p = (gpointer*)dest;
3190 *p = value;
3191 return;
3193 t = type->type;
3194 handle_enum:
3195 switch (t) {
3196 case MONO_TYPE_BOOLEAN:
3197 case MONO_TYPE_I1:
3198 case MONO_TYPE_U1: {
3199 guint8 *p = (guint8*)dest;
3200 *p = value ? *(guint8*)value : 0;
3201 return;
3203 case MONO_TYPE_I2:
3204 case MONO_TYPE_U2:
3205 case MONO_TYPE_CHAR: {
3206 guint16 *p = (guint16*)dest;
3207 *p = value ? *(guint16*)value : 0;
3208 return;
3210 #if SIZEOF_VOID_P == 4
3211 case MONO_TYPE_I:
3212 case MONO_TYPE_U:
3213 #endif
3214 case MONO_TYPE_I4:
3215 case MONO_TYPE_U4: {
3216 gint32 *p = (gint32*)dest;
3217 *p = value ? *(gint32*)value : 0;
3218 return;
3220 #if SIZEOF_VOID_P == 8
3221 case MONO_TYPE_I:
3222 case MONO_TYPE_U:
3223 #endif
3224 case MONO_TYPE_I8:
3225 case MONO_TYPE_U8: {
3226 gint64 *p = (gint64*)dest;
3227 *p = value ? *(gint64*)value : 0;
3228 return;
3230 case MONO_TYPE_R4: {
3231 float *p = (float*)dest;
3232 *p = value ? *(float*)value : 0;
3233 return;
3235 case MONO_TYPE_R8: {
3236 double *p = (double*)dest;
3237 *p = value ? *(double*)value : 0;
3238 return;
3240 case MONO_TYPE_STRING:
3241 case MONO_TYPE_SZARRAY:
3242 case MONO_TYPE_CLASS:
3243 case MONO_TYPE_OBJECT:
3244 case MONO_TYPE_ARRAY:
3245 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3246 return;
3247 case MONO_TYPE_FNPTR:
3248 case MONO_TYPE_PTR: {
3249 gpointer *p = (gpointer*)dest;
3250 *p = deref_pointer? *(gpointer*)value: value;
3251 return;
3253 case MONO_TYPE_VALUETYPE:
3254 /* note that 't' and 'type->type' can be different */
3255 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3256 t = mono_class_enum_basetype (type->data.klass)->type;
3257 goto handle_enum;
3258 } else {
3259 MonoClass *klass = mono_class_from_mono_type (type);
3260 int size = mono_class_value_size (klass, NULL);
3261 if (value == NULL)
3262 mono_gc_bzero_atomic (dest, size);
3263 else
3264 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3266 return;
3267 case MONO_TYPE_GENERICINST:
3268 t = type->data.generic_class->container_class->byval_arg.type;
3269 goto handle_enum;
3270 default:
3271 g_error ("got type %x", type->type);
3276 * mono_field_set_value:
3277 * @obj: Instance object
3278 * @field: MonoClassField describing the field to set
3279 * @value: The value to be set
3281 * Sets the value of the field described by @field in the object instance @obj
3282 * to the value passed in @value. This method should only be used for instance
3283 * fields. For static fields, use mono_field_static_set_value.
3285 * The value must be on the native format of the field type.
3287 void
3288 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3290 MONO_REQ_GC_UNSAFE_MODE;
3292 void *dest;
3294 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3296 dest = (char*)obj + field->offset;
3297 mono_copy_value (field->type, dest, value, FALSE);
3301 * mono_field_static_set_value:
3302 * @field: MonoClassField describing the field to set
3303 * @value: The value to be set
3305 * Sets the value of the static field described by @field
3306 * to the value passed in @value.
3308 * The value must be on the native format of the field type.
3310 void
3311 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3313 MONO_REQ_GC_UNSAFE_MODE;
3315 void *dest;
3317 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3318 /* you cant set a constant! */
3319 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3321 if (field->offset == -1) {
3322 /* Special static */
3323 gpointer addr;
3325 mono_domain_lock (vt->domain);
3326 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3327 mono_domain_unlock (vt->domain);
3328 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3329 } else {
3330 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3332 mono_copy_value (field->type, dest, value, FALSE);
3336 * mono_vtable_get_static_field_data:
3338 * Internal use function: return a pointer to the memory holding the static fields
3339 * for a class or NULL if there are no static fields.
3340 * This is exported only for use by the debugger.
3342 void *
3343 mono_vtable_get_static_field_data (MonoVTable *vt)
3345 MONO_REQ_GC_NEUTRAL_MODE
3347 if (!vt->has_static_fields)
3348 return NULL;
3349 return vt->vtable [vt->klass->vtable_size];
3352 static guint8*
3353 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3355 MONO_REQ_GC_UNSAFE_MODE;
3357 guint8 *src;
3359 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3360 if (field->offset == -1) {
3361 /* Special static */
3362 gpointer addr;
3364 mono_domain_lock (vt->domain);
3365 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3366 mono_domain_unlock (vt->domain);
3367 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3368 } else {
3369 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3371 } else {
3372 src = (guint8*)obj + field->offset;
3375 return src;
3379 * mono_field_get_value:
3380 * @obj: Object instance
3381 * @field: MonoClassField describing the field to fetch information from
3382 * @value: pointer to the location where the value will be stored
3384 * Use this routine to get the value of the field @field in the object
3385 * passed.
3387 * The pointer provided by value must be of the field type, for reference
3388 * types this is a MonoObject*, for value types its the actual pointer to
3389 * the value type.
3391 * For example:
3392 * int i;
3393 * mono_field_get_value (obj, int_field, &i);
3395 void
3396 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3398 MONO_REQ_GC_UNSAFE_MODE;
3400 void *src;
3402 g_assert (obj);
3404 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3406 src = (char*)obj + field->offset;
3407 mono_copy_value (field->type, value, src, TRUE);
3411 * mono_field_get_value_object:
3412 * @domain: domain where the object will be created (if boxing)
3413 * @field: MonoClassField describing the field to fetch information from
3414 * @obj: The object instance for the field.
3416 * Returns: a new MonoObject with the value from the given field. If the
3417 * field represents a value type, the value is boxed.
3420 MonoObject *
3421 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3423 MonoError error;
3424 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3425 mono_error_assert_ok (&error);
3426 return result;
3430 * mono_field_get_value_object_checked:
3431 * @domain: domain where the object will be created (if boxing)
3432 * @field: MonoClassField describing the field to fetch information from
3433 * @obj: The object instance for the field.
3434 * @error: Set on error.
3436 * Returns: a new MonoObject with the value from the given field. If the
3437 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3440 MonoObject *
3441 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3443 MONO_REQ_GC_UNSAFE_MODE;
3445 mono_error_init (error);
3447 MonoObject *o;
3448 MonoClass *klass;
3449 MonoVTable *vtable = NULL;
3450 gchar *v;
3451 gboolean is_static = FALSE;
3452 gboolean is_ref = FALSE;
3453 gboolean is_literal = FALSE;
3454 gboolean is_ptr = FALSE;
3455 MonoType *type = mono_field_get_type_checked (field, error);
3457 return_val_if_nok (error, NULL);
3459 switch (type->type) {
3460 case MONO_TYPE_STRING:
3461 case MONO_TYPE_OBJECT:
3462 case MONO_TYPE_CLASS:
3463 case MONO_TYPE_ARRAY:
3464 case MONO_TYPE_SZARRAY:
3465 is_ref = TRUE;
3466 break;
3467 case MONO_TYPE_U1:
3468 case MONO_TYPE_I1:
3469 case MONO_TYPE_BOOLEAN:
3470 case MONO_TYPE_U2:
3471 case MONO_TYPE_I2:
3472 case MONO_TYPE_CHAR:
3473 case MONO_TYPE_U:
3474 case MONO_TYPE_I:
3475 case MONO_TYPE_U4:
3476 case MONO_TYPE_I4:
3477 case MONO_TYPE_R4:
3478 case MONO_TYPE_U8:
3479 case MONO_TYPE_I8:
3480 case MONO_TYPE_R8:
3481 case MONO_TYPE_VALUETYPE:
3482 is_ref = type->byref;
3483 break;
3484 case MONO_TYPE_GENERICINST:
3485 is_ref = !mono_type_generic_inst_is_valuetype (type);
3486 break;
3487 case MONO_TYPE_PTR:
3488 is_ptr = TRUE;
3489 break;
3490 default:
3491 g_error ("type 0x%x not handled in "
3492 "mono_field_get_value_object", type->type);
3493 return NULL;
3496 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3497 is_literal = TRUE;
3499 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3500 is_static = TRUE;
3502 if (!is_literal) {
3503 vtable = mono_class_vtable_full (domain, field->parent, error);
3504 return_val_if_nok (error, NULL);
3506 if (!vtable->initialized) {
3507 mono_runtime_class_init_full (vtable, error);
3508 return_val_if_nok (error, NULL);
3511 } else {
3512 g_assert (obj);
3515 if (is_ref) {
3516 if (is_literal) {
3517 get_default_field_value (domain, field, &o, error);
3518 return_val_if_nok (error, NULL);
3519 } else if (is_static) {
3520 mono_field_static_get_value_checked (vtable, field, &o, error);
3521 return_val_if_nok (error, NULL);
3522 } else {
3523 mono_field_get_value (obj, field, &o);
3525 return o;
3528 if (is_ptr) {
3529 static MonoMethod *m;
3530 gpointer args [2];
3531 gpointer *ptr;
3532 gpointer v;
3534 if (!m) {
3535 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3536 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3537 g_assert (m);
3540 v = &ptr;
3541 if (is_literal) {
3542 get_default_field_value (domain, field, v, error);
3543 return_val_if_nok (error, NULL);
3544 } else if (is_static) {
3545 mono_field_static_get_value_checked (vtable, field, v, error);
3546 return_val_if_nok (error, NULL);
3547 } else {
3548 mono_field_get_value (obj, field, v);
3551 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3552 args [0] = ptr ? *ptr : NULL;
3553 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3554 return_val_if_nok (error, NULL);
3556 o = mono_runtime_invoke_checked (m, NULL, args, error);
3557 return_val_if_nok (error, NULL);
3559 return o;
3562 /* boxed value type */
3563 klass = mono_class_from_mono_type (type);
3565 if (mono_class_is_nullable (klass))
3566 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3568 o = mono_object_new_checked (domain, klass, error);
3569 return_val_if_nok (error, NULL);
3570 v = ((gchar *) o) + sizeof (MonoObject);
3572 if (is_literal) {
3573 get_default_field_value (domain, field, v, error);
3574 return_val_if_nok (error, NULL);
3575 } else if (is_static) {
3576 mono_field_static_get_value_checked (vtable, field, v, error);
3577 return_val_if_nok (error, NULL);
3578 } else {
3579 mono_field_get_value (obj, field, v);
3582 return o;
3586 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3588 MONO_REQ_GC_UNSAFE_MODE;
3590 mono_error_init (error);
3591 int retval = 0;
3592 const char *p = blob;
3593 mono_metadata_decode_blob_size (p, &p);
3595 switch (type) {
3596 case MONO_TYPE_BOOLEAN:
3597 case MONO_TYPE_U1:
3598 case MONO_TYPE_I1:
3599 *(guint8 *) value = *p;
3600 break;
3601 case MONO_TYPE_CHAR:
3602 case MONO_TYPE_U2:
3603 case MONO_TYPE_I2:
3604 *(guint16*) value = read16 (p);
3605 break;
3606 case MONO_TYPE_U4:
3607 case MONO_TYPE_I4:
3608 *(guint32*) value = read32 (p);
3609 break;
3610 case MONO_TYPE_U8:
3611 case MONO_TYPE_I8:
3612 *(guint64*) value = read64 (p);
3613 break;
3614 case MONO_TYPE_R4:
3615 readr4 (p, (float*) value);
3616 break;
3617 case MONO_TYPE_R8:
3618 readr8 (p, (double*) value);
3619 break;
3620 case MONO_TYPE_STRING:
3621 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3622 break;
3623 case MONO_TYPE_CLASS:
3624 *(gpointer*) value = NULL;
3625 break;
3626 default:
3627 retval = -1;
3628 g_warning ("type 0x%02x should not be in constant table", type);
3630 return retval;
3633 static void
3634 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3636 MONO_REQ_GC_NEUTRAL_MODE;
3638 MonoTypeEnum def_type;
3639 const char* data;
3641 mono_error_init (error);
3643 data = mono_class_get_field_default_value (field, &def_type);
3644 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3647 void
3648 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3650 MONO_REQ_GC_UNSAFE_MODE;
3652 void *src;
3654 mono_error_init (error);
3656 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3658 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3659 get_default_field_value (vt->domain, field, value, error);
3660 return;
3663 if (field->offset == -1) {
3664 /* Special static */
3665 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3666 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3667 } else {
3668 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3670 mono_copy_value (field->type, value, src, TRUE);
3674 * mono_field_static_get_value:
3675 * @vt: vtable to the object
3676 * @field: MonoClassField describing the field to fetch information from
3677 * @value: where the value is returned
3679 * Use this routine to get the value of the static field @field value.
3681 * The pointer provided by value must be of the field type, for reference
3682 * types this is a MonoObject*, for value types its the actual pointer to
3683 * the value type.
3685 * For example:
3686 * int i;
3687 * mono_field_static_get_value (vt, int_field, &i);
3689 void
3690 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3692 MONO_REQ_GC_NEUTRAL_MODE;
3694 MonoError error;
3695 mono_field_static_get_value_checked (vt, field, value, &error);
3696 mono_error_cleanup (&error);
3700 * mono_field_static_get_value_checked:
3701 * @vt: vtable to the object
3702 * @field: MonoClassField describing the field to fetch information from
3703 * @value: where the value is returned
3704 * @error: set on error
3706 * Use this routine to get the value of the static field @field value.
3708 * The pointer provided by value must be of the field type, for reference
3709 * types this is a MonoObject*, for value types its the actual pointer to
3710 * the value type.
3712 * For example:
3713 * int i;
3714 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3715 * if (!is_ok (error)) { ... }
3717 * On failure sets @error.
3719 void
3720 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3722 MONO_REQ_GC_NEUTRAL_MODE;
3724 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3728 * mono_property_set_value:
3729 * @prop: MonoProperty to set
3730 * @obj: instance object on which to act
3731 * @params: parameters to pass to the propery
3732 * @exc: optional exception
3734 * Invokes the property's set method with the given arguments on the
3735 * object instance obj (or NULL for static properties).
3737 * You can pass NULL as the exc argument if you don't want to
3738 * catch exceptions, otherwise, *exc will be set to the exception
3739 * thrown, if any. if an exception is thrown, you can't use the
3740 * MonoObject* result from the function.
3742 void
3743 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3745 MONO_REQ_GC_UNSAFE_MODE;
3747 MonoError error;
3748 do_runtime_invoke (prop->set, obj, params, exc, &error);
3749 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3750 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3751 } else {
3752 mono_error_cleanup (&error);
3757 * mono_property_set_value_checked:
3758 * @prop: MonoProperty to set
3759 * @obj: instance object on which to act
3760 * @params: parameters to pass to the propery
3761 * @error: set on error
3763 * Invokes the property's set method with the given arguments on the
3764 * object instance obj (or NULL for static properties).
3766 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3767 * If an exception is thrown, it will be caught and returned via @error.
3769 gboolean
3770 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3772 MONO_REQ_GC_UNSAFE_MODE;
3774 MonoObject *exc;
3776 mono_error_init (error);
3777 do_runtime_invoke (prop->set, obj, params, &exc, error);
3778 if (exc != NULL && is_ok (error))
3779 mono_error_set_exception_instance (error, (MonoException*)exc);
3780 return is_ok (error);
3784 * mono_property_get_value:
3785 * @prop: MonoProperty to fetch
3786 * @obj: instance object on which to act
3787 * @params: parameters to pass to the propery
3788 * @exc: optional exception
3790 * Invokes the property's get method with the given arguments on the
3791 * object instance obj (or NULL for static properties).
3793 * You can pass NULL as the exc argument if you don't want to
3794 * catch exceptions, otherwise, *exc will be set to the exception
3795 * thrown, if any. if an exception is thrown, you can't use the
3796 * MonoObject* result from the function.
3798 * Returns: the value from invoking the get method on the property.
3800 MonoObject*
3801 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3803 MONO_REQ_GC_UNSAFE_MODE;
3805 MonoError error;
3806 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3807 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3808 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3809 } else {
3810 mono_error_cleanup (&error); /* FIXME don't raise here */
3813 return val;
3817 * mono_property_get_value_checked:
3818 * @prop: MonoProperty to fetch
3819 * @obj: instance object on which to act
3820 * @params: parameters to pass to the propery
3821 * @error: set on error
3823 * Invokes the property's get method with the given arguments on the
3824 * object instance obj (or NULL for static properties).
3826 * If an exception is thrown, you can't use the
3827 * MonoObject* result from the function. The exception will be propagated via @error.
3829 * Returns: the value from invoking the get method on the property. On
3830 * failure returns NULL and sets @error.
3832 MonoObject*
3833 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3835 MONO_REQ_GC_UNSAFE_MODE;
3837 MonoObject *exc;
3838 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3839 if (exc != NULL && !is_ok (error))
3840 mono_error_set_exception_instance (error, (MonoException*) exc);
3841 if (!is_ok (error))
3842 val = NULL;
3843 return val;
3848 * mono_nullable_init:
3849 * @buf: The nullable structure to initialize.
3850 * @value: the value to initialize from
3851 * @klass: the type for the object
3853 * Initialize the nullable structure pointed to by @buf from @value which
3854 * should be a boxed value type. The size of @buf should be able to hold
3855 * as much data as the @klass->instance_size (which is the number of bytes
3856 * that will be copies).
3858 * Since Nullables have variable structure, we can not define a C
3859 * structure for them.
3861 void
3862 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3864 MONO_REQ_GC_UNSAFE_MODE;
3866 MonoClass *param_class = klass->cast_class;
3868 mono_class_setup_fields_locking (klass);
3869 g_assert (klass->fields_inited);
3871 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3872 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3874 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3875 if (value) {
3876 if (param_class->has_references)
3877 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3878 else
3879 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3880 } else {
3881 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3886 * mono_nullable_box:
3887 * @buf: The buffer representing the data to be boxed
3888 * @klass: the type to box it as.
3889 * @error: set on oerr
3891 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3892 * @buf. On failure returns NULL and sets @error
3894 MonoObject*
3895 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3897 MONO_REQ_GC_UNSAFE_MODE;
3899 mono_error_init (error);
3900 MonoClass *param_class = klass->cast_class;
3902 mono_class_setup_fields_locking (klass);
3903 g_assert (klass->fields_inited);
3905 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3906 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3908 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3909 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3910 return_val_if_nok (error, NULL);
3911 if (param_class->has_references)
3912 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3913 else
3914 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3915 return o;
3917 else
3918 return NULL;
3922 * mono_get_delegate_invoke:
3923 * @klass: The delegate class
3925 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3927 MonoMethod *
3928 mono_get_delegate_invoke (MonoClass *klass)
3930 MONO_REQ_GC_NEUTRAL_MODE;
3932 MonoMethod *im;
3934 /* This is called at runtime, so avoid the slower search in metadata */
3935 mono_class_setup_methods (klass);
3936 if (mono_class_has_failure (klass))
3937 return NULL;
3938 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3939 return im;
3943 * mono_get_delegate_begin_invoke:
3944 * @klass: The delegate class
3946 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3948 MonoMethod *
3949 mono_get_delegate_begin_invoke (MonoClass *klass)
3951 MONO_REQ_GC_NEUTRAL_MODE;
3953 MonoMethod *im;
3955 /* This is called at runtime, so avoid the slower search in metadata */
3956 mono_class_setup_methods (klass);
3957 if (mono_class_has_failure (klass))
3958 return NULL;
3959 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3960 return im;
3964 * mono_get_delegate_end_invoke:
3965 * @klass: The delegate class
3967 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3969 MonoMethod *
3970 mono_get_delegate_end_invoke (MonoClass *klass)
3972 MONO_REQ_GC_NEUTRAL_MODE;
3974 MonoMethod *im;
3976 /* This is called at runtime, so avoid the slower search in metadata */
3977 mono_class_setup_methods (klass);
3978 if (mono_class_has_failure (klass))
3979 return NULL;
3980 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3981 return im;
3985 * mono_runtime_delegate_invoke:
3986 * @delegate: pointer to a delegate object.
3987 * @params: parameters for the delegate.
3988 * @exc: Pointer to the exception result.
3990 * Invokes the delegate method @delegate with the parameters provided.
3992 * You can pass NULL as the exc argument if you don't want to
3993 * catch exceptions, otherwise, *exc will be set to the exception
3994 * thrown, if any. if an exception is thrown, you can't use the
3995 * MonoObject* result from the function.
3997 MonoObject*
3998 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4000 MONO_REQ_GC_UNSAFE_MODE;
4002 MonoError error;
4003 if (exc) {
4004 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
4005 if (*exc) {
4006 mono_error_cleanup (&error);
4007 return NULL;
4008 } else {
4009 if (!is_ok (&error))
4010 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4011 return result;
4013 } else {
4014 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
4015 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4016 return result;
4021 * mono_runtime_delegate_try_invoke:
4022 * @delegate: pointer to a delegate object.
4023 * @params: parameters for the delegate.
4024 * @exc: Pointer to the exception result.
4025 * @error: set on error
4027 * Invokes the delegate method @delegate with the parameters provided.
4029 * You can pass NULL as the exc argument if you don't want to
4030 * catch exceptions, otherwise, *exc will be set to the exception
4031 * thrown, if any. On failure to execute, @error will be set.
4032 * if an exception is thrown, you can't use the
4033 * MonoObject* result from the function.
4035 MonoObject*
4036 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4038 MONO_REQ_GC_UNSAFE_MODE;
4040 mono_error_init (error);
4041 MonoMethod *im;
4042 MonoClass *klass = delegate->vtable->klass;
4043 MonoObject *o;
4045 im = mono_get_delegate_invoke (klass);
4046 if (!im)
4047 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4049 if (exc) {
4050 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4051 } else {
4052 o = mono_runtime_invoke_checked (im, delegate, params, error);
4055 return o;
4059 * mono_runtime_delegate_invoke_checked:
4060 * @delegate: pointer to a delegate object.
4061 * @params: parameters for the delegate.
4062 * @error: set on error
4064 * Invokes the delegate method @delegate with the parameters provided.
4066 * On failure @error will be set and you can't use the MonoObject*
4067 * result from the function.
4069 MonoObject*
4070 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4072 mono_error_init (error);
4073 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4076 static char **main_args = NULL;
4077 static int num_main_args = 0;
4080 * mono_runtime_get_main_args:
4082 * Returns: a MonoArray with the arguments passed to the main program
4084 MonoArray*
4085 mono_runtime_get_main_args (void)
4087 MONO_REQ_GC_UNSAFE_MODE;
4088 MonoError error;
4089 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4090 mono_error_assert_ok (&error);
4091 return result;
4095 * mono_runtime_get_main_args:
4096 * @error: set on error
4098 * Returns: a MonoArray with the arguments passed to the main
4099 * program. On failure returns NULL and sets @error.
4101 MonoArray*
4102 mono_runtime_get_main_args_checked (MonoError *error)
4104 MonoArray *res;
4105 int i;
4106 MonoDomain *domain = mono_domain_get ();
4108 mono_error_init (error);
4110 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4111 return_val_if_nok (error, NULL);
4113 for (i = 0; i < num_main_args; ++i)
4114 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4116 return res;
4119 static void
4120 free_main_args (void)
4122 MONO_REQ_GC_NEUTRAL_MODE;
4124 int i;
4126 for (i = 0; i < num_main_args; ++i)
4127 g_free (main_args [i]);
4128 g_free (main_args);
4129 num_main_args = 0;
4130 main_args = NULL;
4134 * mono_runtime_set_main_args:
4135 * @argc: number of arguments from the command line
4136 * @argv: array of strings from the command line
4138 * Set the command line arguments from an embedding application that doesn't otherwise call
4139 * mono_runtime_run_main ().
4142 mono_runtime_set_main_args (int argc, char* argv[])
4144 MONO_REQ_GC_NEUTRAL_MODE;
4146 int i;
4148 free_main_args ();
4149 main_args = g_new0 (char*, argc);
4150 num_main_args = argc;
4152 for (i = 0; i < argc; ++i) {
4153 gchar *utf8_arg;
4155 utf8_arg = mono_utf8_from_external (argv[i]);
4156 if (utf8_arg == NULL) {
4157 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4158 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4159 exit (-1);
4162 main_args [i] = utf8_arg;
4165 return 0;
4169 * mono_runtime_run_main:
4170 * @method: the method to start the application with (usually Main)
4171 * @argc: number of arguments from the command line
4172 * @argv: array of strings from the command line
4173 * @exc: excetption results
4175 * Execute a standard Main() method (argc/argv contains the
4176 * executable name). This method also sets the command line argument value
4177 * needed by System.Environment.
4182 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4183 MonoObject **exc)
4185 MONO_REQ_GC_UNSAFE_MODE;
4187 MonoError error;
4188 int i;
4189 MonoArray *args = NULL;
4190 MonoDomain *domain = mono_domain_get ();
4191 gchar *utf8_fullpath;
4192 MonoMethodSignature *sig;
4194 g_assert (method != NULL);
4196 mono_thread_set_main (mono_thread_current ());
4198 main_args = g_new0 (char*, argc);
4199 num_main_args = argc;
4201 if (!g_path_is_absolute (argv [0])) {
4202 gchar *basename = g_path_get_basename (argv [0]);
4203 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4204 basename,
4205 NULL);
4207 utf8_fullpath = mono_utf8_from_external (fullpath);
4208 if(utf8_fullpath == NULL) {
4209 /* Printing the arg text will cause glib to
4210 * whinge about "Invalid UTF-8", but at least
4211 * its relevant, and shows the problem text
4212 * string.
4214 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4215 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4216 exit (-1);
4219 g_free (fullpath);
4220 g_free (basename);
4221 } else {
4222 utf8_fullpath = mono_utf8_from_external (argv[0]);
4223 if(utf8_fullpath == NULL) {
4224 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4225 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4226 exit (-1);
4230 main_args [0] = utf8_fullpath;
4232 for (i = 1; i < argc; ++i) {
4233 gchar *utf8_arg;
4235 utf8_arg=mono_utf8_from_external (argv[i]);
4236 if(utf8_arg==NULL) {
4237 /* Ditto the comment about Invalid UTF-8 here */
4238 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4239 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4240 exit (-1);
4243 main_args [i] = utf8_arg;
4245 argc--;
4246 argv++;
4248 sig = mono_method_signature (method);
4249 if (!sig) {
4250 g_print ("Unable to load Main method.\n");
4251 exit (-1);
4254 if (sig->param_count) {
4255 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4256 mono_error_assert_ok (&error);
4257 for (i = 0; i < argc; ++i) {
4258 /* The encodings should all work, given that
4259 * we've checked all these args for the
4260 * main_args array.
4262 gchar *str = mono_utf8_from_external (argv [i]);
4263 MonoString *arg = mono_string_new (domain, str);
4264 mono_array_setref (args, i, arg);
4265 g_free (str);
4267 } else {
4268 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4269 mono_error_assert_ok (&error);
4272 mono_assembly_set_main (method->klass->image->assembly);
4274 return mono_runtime_exec_main (method, args, exc);
4277 static MonoObject*
4278 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4280 static MonoMethod *serialize_method;
4282 MonoError error;
4283 void *params [1];
4284 MonoObject *array;
4286 if (!serialize_method) {
4287 MonoClass *klass = mono_class_get_remoting_services_class ();
4288 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4291 if (!serialize_method) {
4292 *failure = TRUE;
4293 return NULL;
4296 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4298 params [0] = obj;
4299 *exc = NULL;
4301 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4302 if (*exc == NULL && !mono_error_ok (&error))
4303 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4304 else
4305 mono_error_cleanup (&error);
4307 if (*exc)
4308 *failure = TRUE;
4310 return array;
4313 static MonoObject*
4314 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4316 MONO_REQ_GC_UNSAFE_MODE;
4318 static MonoMethod *deserialize_method;
4320 MonoError error;
4321 void *params [1];
4322 MonoObject *result;
4324 if (!deserialize_method) {
4325 MonoClass *klass = mono_class_get_remoting_services_class ();
4326 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4328 if (!deserialize_method) {
4329 *failure = TRUE;
4330 return NULL;
4333 params [0] = obj;
4334 *exc = NULL;
4336 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4337 if (*exc == NULL && !mono_error_ok (&error))
4338 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4339 else
4340 mono_error_cleanup (&error);
4342 if (*exc)
4343 *failure = TRUE;
4345 return result;
4348 #ifndef DISABLE_REMOTING
4349 static MonoObject*
4350 make_transparent_proxy (MonoObject *obj, MonoError *error)
4352 MONO_REQ_GC_UNSAFE_MODE;
4354 static MonoMethod *get_proxy_method;
4356 MonoDomain *domain = mono_domain_get ();
4357 MonoRealProxy *real_proxy;
4358 MonoReflectionType *reflection_type;
4359 MonoTransparentProxy *transparent_proxy;
4361 mono_error_init (error);
4363 if (!get_proxy_method)
4364 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4366 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4368 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4369 return_val_if_nok (error, NULL);
4370 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4371 return_val_if_nok (error, NULL);
4373 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4374 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4376 MonoObject *exc = NULL;
4378 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4379 if (exc != NULL && is_ok (error))
4380 mono_error_set_exception_instance (error, (MonoException*)exc);
4382 return (MonoObject*) transparent_proxy;
4384 #endif /* DISABLE_REMOTING */
4387 * mono_object_xdomain_representation
4388 * @obj: an object
4389 * @target_domain: a domain
4390 * @error: set on error.
4392 * Creates a representation of obj in the domain target_domain. This
4393 * is either a copy of obj arrived through via serialization and
4394 * deserialization or a proxy, depending on whether the object is
4395 * serializable or marshal by ref. obj must not be in target_domain.
4397 * If the object cannot be represented in target_domain, NULL is
4398 * returned and @error is set appropriately.
4400 MonoObject*
4401 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4403 MONO_REQ_GC_UNSAFE_MODE;
4405 mono_error_init (error);
4406 MonoObject *deserialized = NULL;
4408 #ifndef DISABLE_REMOTING
4409 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4410 deserialized = make_transparent_proxy (obj, error);
4412 else
4413 #endif
4415 gboolean failure = FALSE;
4416 MonoDomain *domain = mono_domain_get ();
4417 MonoObject *serialized;
4418 MonoObject *exc = NULL;
4420 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4421 serialized = serialize_object (obj, &failure, &exc);
4422 mono_domain_set_internal_with_options (target_domain, FALSE);
4423 if (!failure)
4424 deserialized = deserialize_object (serialized, &failure, &exc);
4425 if (domain != target_domain)
4426 mono_domain_set_internal_with_options (domain, FALSE);
4427 if (failure)
4428 mono_error_set_exception_instance (error, (MonoException*)exc);
4431 return deserialized;
4434 /* Used in call_unhandled_exception_delegate */
4435 static MonoObject *
4436 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4438 MONO_REQ_GC_UNSAFE_MODE;
4440 mono_error_init (error);
4441 MonoClass *klass;
4442 gpointer args [2];
4443 MonoMethod *method = NULL;
4444 MonoBoolean is_terminating = TRUE;
4445 MonoObject *obj;
4447 klass = mono_class_get_unhandled_exception_event_args_class ();
4448 mono_class_init (klass);
4450 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4451 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4452 g_assert (method);
4454 args [0] = exc;
4455 args [1] = &is_terminating;
4457 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4458 return_val_if_nok (error, NULL);
4460 mono_runtime_invoke_checked (method, obj, args, error);
4461 return_val_if_nok (error, NULL);
4463 return obj;
4466 /* Used in mono_unhandled_exception */
4467 static void
4468 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4469 MONO_REQ_GC_UNSAFE_MODE;
4471 MonoError error;
4472 MonoObject *e = NULL;
4473 gpointer pa [2];
4474 MonoDomain *current_domain = mono_domain_get ();
4476 if (domain != current_domain)
4477 mono_domain_set_internal_with_options (domain, FALSE);
4479 g_assert (domain == mono_object_domain (domain->domain));
4481 if (mono_object_domain (exc) != domain) {
4483 exc = mono_object_xdomain_representation (exc, domain, &error);
4484 if (!exc) {
4485 if (!is_ok (&error)) {
4486 MonoError inner_error;
4487 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4488 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4489 mono_error_assert_ok (&inner_error);
4490 } else {
4491 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4492 "System.Runtime.Serialization", "SerializationException",
4493 "Could not serialize unhandled exception.");
4497 g_assert (mono_object_domain (exc) == domain);
4499 pa [0] = domain->domain;
4500 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4501 mono_error_assert_ok (&error);
4502 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4503 if (!is_ok (&error)) {
4504 if (e == NULL)
4505 e = (MonoObject*)mono_error_convert_to_exception (&error);
4506 else
4507 mono_error_cleanup (&error);
4510 if (domain != current_domain)
4511 mono_domain_set_internal_with_options (current_domain, FALSE);
4513 if (e) {
4514 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4515 if (!mono_error_ok (&error)) {
4516 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4517 mono_error_cleanup (&error);
4518 } else {
4519 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4520 g_free (msg);
4525 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4528 * mono_runtime_unhandled_exception_policy_set:
4529 * @policy: the new policy
4531 * This is a VM internal routine.
4533 * Sets the runtime policy for handling unhandled exceptions.
4535 void
4536 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4537 runtime_unhandled_exception_policy = policy;
4541 * mono_runtime_unhandled_exception_policy_get:
4543 * This is a VM internal routine.
4545 * Gets the runtime policy for handling unhandled exceptions.
4547 MonoRuntimeUnhandledExceptionPolicy
4548 mono_runtime_unhandled_exception_policy_get (void) {
4549 return runtime_unhandled_exception_policy;
4553 * mono_unhandled_exception:
4554 * @exc: exception thrown
4556 * This is a VM internal routine.
4558 * We call this function when we detect an unhandled exception
4559 * in the default domain.
4561 * It invokes the * UnhandledException event in AppDomain or prints
4562 * a warning to the console
4564 void
4565 mono_unhandled_exception (MonoObject *exc)
4567 MONO_REQ_GC_UNSAFE_MODE;
4569 MonoError error;
4570 MonoClassField *field;
4571 MonoDomain *current_domain, *root_domain;
4572 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4574 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4575 return;
4577 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4578 g_assert (field);
4580 current_domain = mono_domain_get ();
4581 root_domain = mono_get_root_domain ();
4583 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4584 mono_error_assert_ok (&error);
4585 if (current_domain != root_domain) {
4586 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4587 mono_error_assert_ok (&error);
4590 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4591 mono_print_unhandled_exception (exc);
4592 } else {
4593 if (root_appdomain_delegate)
4594 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4595 if (current_appdomain_delegate)
4596 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4599 /* set exitcode only if we will abort the process */
4600 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4601 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4603 mono_environment_exitcode_set (1);
4608 * mono_runtime_exec_managed_code:
4609 * @domain: Application domain
4610 * @main_func: function to invoke from the execution thread
4611 * @main_args: parameter to the main_func
4613 * Launch a new thread to execute a function
4615 * main_func is called back from the thread with main_args as the
4616 * parameter. The callback function is expected to start Main()
4617 * eventually. This function then waits for all managed threads to
4618 * finish.
4619 * It is not necesseray anymore to execute managed code in a subthread,
4620 * so this function should not be used anymore by default: just
4621 * execute the code and then call mono_thread_manage ().
4623 void
4624 mono_runtime_exec_managed_code (MonoDomain *domain,
4625 MonoMainThreadFunc main_func,
4626 gpointer main_args)
4628 MonoError error;
4629 mono_thread_create_checked (domain, main_func, main_args, &error);
4630 mono_error_assert_ok (&error);
4632 mono_thread_manage ();
4636 * Execute a standard Main() method (args doesn't contain the
4637 * executable name).
4640 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4642 MONO_REQ_GC_UNSAFE_MODE;
4644 MonoError error;
4645 MonoDomain *domain;
4646 gpointer pa [1];
4647 int rval;
4648 MonoCustomAttrInfo* cinfo;
4649 gboolean has_stathread_attribute;
4650 MonoInternalThread* thread = mono_thread_internal_current ();
4652 g_assert (args);
4654 pa [0] = args;
4656 domain = mono_object_domain (args);
4657 if (!domain->entry_assembly) {
4658 gchar *str;
4659 MonoAssembly *assembly;
4661 assembly = method->klass->image->assembly;
4662 domain->entry_assembly = assembly;
4663 /* Domains created from another domain already have application_base and configuration_file set */
4664 if (domain->setup->application_base == NULL) {
4665 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4668 if (domain->setup->configuration_file == NULL) {
4669 str = g_strconcat (assembly->image->name, ".config", NULL);
4670 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4671 g_free (str);
4672 mono_domain_set_options_from_config (domain);
4676 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4677 mono_error_cleanup (&error); /* FIXME warn here? */
4678 if (cinfo) {
4679 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4680 if (!cinfo->cached)
4681 mono_custom_attrs_free (cinfo);
4682 } else {
4683 has_stathread_attribute = FALSE;
4685 if (has_stathread_attribute) {
4686 thread->apartment_state = ThreadApartmentState_STA;
4687 } else {
4688 thread->apartment_state = ThreadApartmentState_MTA;
4690 mono_thread_init_apartment_state ();
4692 /* FIXME: check signature of method */
4693 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4694 MonoObject *res;
4695 if (exc) {
4696 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4697 if (*exc == NULL && !mono_error_ok (&error))
4698 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4699 else
4700 mono_error_cleanup (&error);
4701 } else {
4702 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4703 mono_error_raise_exception (&error); /* FIXME don't raise here */
4706 if (!exc || !*exc)
4707 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4708 else
4709 rval = -1;
4711 mono_environment_exitcode_set (rval);
4712 } else {
4713 if (exc) {
4714 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4715 if (*exc == NULL && !mono_error_ok (&error))
4716 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4717 else
4718 mono_error_cleanup (&error);
4719 } else {
4720 mono_runtime_invoke_checked (method, NULL, pa, &error);
4721 mono_error_raise_exception (&error); /* FIXME don't raise here */
4724 if (!exc || !*exc)
4725 rval = 0;
4726 else {
4727 /* If the return type of Main is void, only
4728 * set the exitcode if an exception was thrown
4729 * (we don't want to blow away an
4730 * explicitly-set exit code)
4732 rval = -1;
4733 mono_environment_exitcode_set (rval);
4737 return rval;
4740 /** invoke_array_extract_argument:
4741 * @params: array of arguments to the method.
4742 * @i: the index of the argument to extract.
4743 * @t: ith type from the method signature.
4744 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4745 * @error: set on error.
4747 * Given an array of method arguments, return the ith one using the corresponding type
4748 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4750 * On failure sets @error and returns NULL.
4752 static gpointer
4753 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4755 MonoType *t_orig = t;
4756 gpointer result = NULL;
4757 mono_error_init (error);
4758 again:
4759 switch (t->type) {
4760 case MONO_TYPE_U1:
4761 case MONO_TYPE_I1:
4762 case MONO_TYPE_BOOLEAN:
4763 case MONO_TYPE_U2:
4764 case MONO_TYPE_I2:
4765 case MONO_TYPE_CHAR:
4766 case MONO_TYPE_U:
4767 case MONO_TYPE_I:
4768 case MONO_TYPE_U4:
4769 case MONO_TYPE_I4:
4770 case MONO_TYPE_U8:
4771 case MONO_TYPE_I8:
4772 case MONO_TYPE_R4:
4773 case MONO_TYPE_R8:
4774 case MONO_TYPE_VALUETYPE:
4775 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4776 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4777 result = mono_array_get (params, MonoObject*, i);
4778 if (t->byref)
4779 *has_byref_nullables = TRUE;
4780 } else {
4781 /* MS seems to create the objects if a null is passed in */
4782 if (!mono_array_get (params, MonoObject*, i)) {
4783 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4784 return_val_if_nok (error, NULL);
4785 mono_array_setref (params, i, o);
4788 if (t->byref) {
4790 * We can't pass the unboxed vtype byref to the callee, since
4791 * that would mean the callee would be able to modify boxed
4792 * primitive types. So we (and MS) make a copy of the boxed
4793 * object, pass that to the callee, and replace the original
4794 * boxed object in the arg array with the copy.
4796 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4797 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4798 return_val_if_nok (error, NULL);
4799 mono_array_setref (params, i, copy);
4802 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4804 break;
4805 case MONO_TYPE_STRING:
4806 case MONO_TYPE_OBJECT:
4807 case MONO_TYPE_CLASS:
4808 case MONO_TYPE_ARRAY:
4809 case MONO_TYPE_SZARRAY:
4810 if (t->byref)
4811 result = mono_array_addr (params, MonoObject*, i);
4812 // FIXME: I need to check this code path
4813 else
4814 result = mono_array_get (params, MonoObject*, i);
4815 break;
4816 case MONO_TYPE_GENERICINST:
4817 if (t->byref)
4818 t = &t->data.generic_class->container_class->this_arg;
4819 else
4820 t = &t->data.generic_class->container_class->byval_arg;
4821 goto again;
4822 case MONO_TYPE_PTR: {
4823 MonoObject *arg;
4825 /* The argument should be an IntPtr */
4826 arg = mono_array_get (params, MonoObject*, i);
4827 if (arg == NULL) {
4828 result = NULL;
4829 } else {
4830 g_assert (arg->vtable->klass == mono_defaults.int_class);
4831 result = ((MonoIntPtr*)arg)->m_value;
4833 break;
4835 default:
4836 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4838 return result;
4841 * mono_runtime_invoke_array:
4842 * @method: method to invoke
4843 * @obJ: object instance
4844 * @params: arguments to the method
4845 * @exc: exception information.
4847 * Invokes the method represented by @method on the object @obj.
4849 * obj is the 'this' pointer, it should be NULL for static
4850 * methods, a MonoObject* for object instances and a pointer to
4851 * the value type for value types.
4853 * The params array contains the arguments to the method with the
4854 * same convention: MonoObject* pointers for object instances and
4855 * pointers to the value type otherwise. The _invoke_array
4856 * variant takes a C# object[] as the params argument (MonoArray
4857 * *params): in this case the value types are boxed inside the
4858 * respective reference representation.
4860 * From unmanaged code you'll usually use the
4861 * mono_runtime_invoke_checked() variant.
4863 * Note that this function doesn't handle virtual methods for
4864 * you, it will exec the exact method you pass: we still need to
4865 * expose a function to lookup the derived class implementation
4866 * of a virtual method (there are examples of this in the code,
4867 * though).
4869 * You can pass NULL as the exc argument if you don't want to
4870 * catch exceptions, otherwise, *exc will be set to the exception
4871 * thrown, if any. if an exception is thrown, you can't use the
4872 * MonoObject* result from the function.
4874 * If the method returns a value type, it is boxed in an object
4875 * reference.
4877 MonoObject*
4878 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4879 MonoObject **exc)
4881 MonoError error;
4882 if (exc) {
4883 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4884 if (*exc) {
4885 mono_error_cleanup (&error);
4886 return NULL;
4887 } else {
4888 if (!is_ok (&error))
4889 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4890 return result;
4892 } else {
4893 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4894 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4895 return result;
4900 * mono_runtime_invoke_array_checked:
4901 * @method: method to invoke
4902 * @obJ: object instance
4903 * @params: arguments to the method
4904 * @error: set on failure.
4906 * Invokes the method represented by @method on the object @obj.
4908 * obj is the 'this' pointer, it should be NULL for static
4909 * methods, a MonoObject* for object instances and a pointer to
4910 * the value type for value types.
4912 * The params array contains the arguments to the method with the
4913 * same convention: MonoObject* pointers for object instances and
4914 * pointers to the value type otherwise. The _invoke_array
4915 * variant takes a C# object[] as the params argument (MonoArray
4916 * *params): in this case the value types are boxed inside the
4917 * respective reference representation.
4919 * From unmanaged code you'll usually use the
4920 * mono_runtime_invoke_checked() variant.
4922 * Note that this function doesn't handle virtual methods for
4923 * you, it will exec the exact method you pass: we still need to
4924 * expose a function to lookup the derived class implementation
4925 * of a virtual method (there are examples of this in the code,
4926 * though).
4928 * On failure or exception, @error will be set. In that case, you
4929 * can't use the 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_checked (MonoMethod *method, void *obj, MonoArray *params,
4936 MonoError *error)
4938 mono_error_init (error);
4939 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4943 * mono_runtime_try_invoke_array:
4944 * @method: method to invoke
4945 * @obJ: object instance
4946 * @params: arguments to the method
4947 * @exc: exception information.
4948 * @error: set on failure.
4950 * Invokes the method represented by @method on the object @obj.
4952 * obj is the 'this' pointer, it should be NULL for static
4953 * methods, a MonoObject* for object instances and a pointer to
4954 * the value type for value types.
4956 * The params array contains the arguments to the method with the
4957 * same convention: MonoObject* pointers for object instances and
4958 * pointers to the value type otherwise. The _invoke_array
4959 * variant takes a C# object[] as the params argument (MonoArray
4960 * *params): in this case the value types are boxed inside the
4961 * respective reference representation.
4963 * From unmanaged code you'll usually use the
4964 * mono_runtime_invoke_checked() variant.
4966 * Note that this function doesn't handle virtual methods for
4967 * you, it will exec the exact method you pass: we still need to
4968 * expose a function to lookup the derived class implementation
4969 * of a virtual method (there are examples of this in the code,
4970 * though).
4972 * You can pass NULL as the exc argument if you don't want to catch
4973 * exceptions, otherwise, *exc will be set to the exception thrown, if
4974 * any. On other failures, @error will be set. If an exception is
4975 * thrown or there's an error, you can't use the MonoObject* result
4976 * from the function.
4978 * If the method returns a value type, it is boxed in an object
4979 * reference.
4981 MonoObject*
4982 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4983 MonoObject **exc, MonoError *error)
4985 MONO_REQ_GC_UNSAFE_MODE;
4987 mono_error_init (error);
4989 MonoMethodSignature *sig = mono_method_signature (method);
4990 gpointer *pa = NULL;
4991 MonoObject *res;
4992 int i;
4993 gboolean has_byref_nullables = FALSE;
4995 if (NULL != params) {
4996 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4997 for (i = 0; i < mono_array_length (params); i++) {
4998 MonoType *t = sig->params [i];
4999 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5000 return_val_if_nok (error, NULL);
5004 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5005 void *o = obj;
5007 if (mono_class_is_nullable (method->klass)) {
5008 /* Need to create a boxed vtype instead */
5009 g_assert (!obj);
5011 if (!params)
5012 return NULL;
5013 else {
5014 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5018 if (!obj) {
5019 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5020 mono_error_assert_ok (error);
5021 g_assert (obj); /*maybe we should raise a TLE instead?*/
5022 #ifndef DISABLE_REMOTING
5023 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5024 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5026 #endif
5027 if (method->klass->valuetype)
5028 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5029 else
5030 o = obj;
5031 } else if (method->klass->valuetype) {
5032 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5033 return_val_if_nok (error, NULL);
5036 if (exc) {
5037 mono_runtime_try_invoke (method, o, pa, exc, error);
5038 } else {
5039 mono_runtime_invoke_checked (method, o, pa, error);
5042 return (MonoObject *)obj;
5043 } else {
5044 if (mono_class_is_nullable (method->klass)) {
5045 MonoObject *nullable;
5047 /* Convert the unboxed vtype into a Nullable structure */
5048 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5049 return_val_if_nok (error, NULL);
5051 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5052 return_val_if_nok (error, NULL);
5053 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5054 obj = mono_object_unbox (nullable);
5057 /* obj must be already unboxed if needed */
5058 if (exc) {
5059 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5060 } else {
5061 res = mono_runtime_invoke_checked (method, obj, pa, error);
5063 return_val_if_nok (error, NULL);
5065 if (sig->ret->type == MONO_TYPE_PTR) {
5066 MonoClass *pointer_class;
5067 static MonoMethod *box_method;
5068 void *box_args [2];
5069 MonoObject *box_exc;
5072 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5073 * convert it to a Pointer object.
5075 pointer_class = mono_class_get_pointer_class ();
5076 if (!box_method)
5077 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5079 g_assert (res->vtable->klass == mono_defaults.int_class);
5080 box_args [0] = ((MonoIntPtr*)res)->m_value;
5081 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5082 return_val_if_nok (error, NULL);
5084 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5085 g_assert (box_exc == NULL);
5086 mono_error_assert_ok (error);
5089 if (has_byref_nullables) {
5091 * The runtime invoke wrapper already converted byref nullables back,
5092 * and stored them in pa, we just need to copy them back to the
5093 * managed array.
5095 for (i = 0; i < mono_array_length (params); i++) {
5096 MonoType *t = sig->params [i];
5098 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5099 mono_array_setref (params, i, pa [i]);
5103 return res;
5108 * mono_object_new:
5109 * @klass: the class of the object that we want to create
5111 * Returns: a newly created object whose definition is
5112 * looked up using @klass. This will not invoke any constructors,
5113 * so the consumer of this routine has to invoke any constructors on
5114 * its own to initialize the object.
5116 * It returns NULL on failure.
5118 MonoObject *
5119 mono_object_new (MonoDomain *domain, MonoClass *klass)
5121 MONO_REQ_GC_UNSAFE_MODE;
5123 MonoError error;
5125 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5127 mono_error_cleanup (&error);
5128 return result;
5131 MonoObject *
5132 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5134 MONO_REQ_GC_UNSAFE_MODE;
5136 MonoError error;
5138 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5140 mono_error_set_pending_exception (&error);
5141 return result;
5145 * mono_object_new_checked:
5146 * @klass: the class of the object that we want to create
5147 * @error: set on error
5149 * Returns: a newly created object whose definition is
5150 * looked up using @klass. This will not invoke any constructors,
5151 * so the consumer of this routine has to invoke any constructors on
5152 * its own to initialize the object.
5154 * It returns NULL on failure and sets @error.
5156 MonoObject *
5157 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5159 MONO_REQ_GC_UNSAFE_MODE;
5161 MonoVTable *vtable;
5163 vtable = mono_class_vtable (domain, klass);
5164 g_assert (vtable); /* FIXME don't swallow the error */
5166 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5167 return o;
5171 * mono_object_new_pinned:
5173 * Same as mono_object_new, but the returned object will be pinned.
5174 * For SGEN, these objects will only be freed at appdomain unload.
5176 MonoObject *
5177 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5179 MONO_REQ_GC_UNSAFE_MODE;
5181 MonoVTable *vtable;
5183 mono_error_init (error);
5185 vtable = mono_class_vtable (domain, klass);
5186 g_assert (vtable); /* FIXME don't swallow the error */
5188 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5190 if (G_UNLIKELY (!o))
5191 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5192 else if (G_UNLIKELY (vtable->klass->has_finalize))
5193 mono_object_register_finalizer (o);
5195 return o;
5199 * mono_object_new_specific:
5200 * @vtable: the vtable of the object that we want to create
5202 * Returns: A newly created object with class and domain specified
5203 * by @vtable
5205 MonoObject *
5206 mono_object_new_specific (MonoVTable *vtable)
5208 MonoError error;
5209 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5210 mono_error_cleanup (&error);
5212 return o;
5215 MonoObject *
5216 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5218 MONO_REQ_GC_UNSAFE_MODE;
5220 MonoObject *o;
5222 mono_error_init (error);
5224 /* check for is_com_object for COM Interop */
5225 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5227 gpointer pa [1];
5228 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5230 if (im == NULL) {
5231 MonoClass *klass = mono_class_get_activation_services_class ();
5233 if (!klass->inited)
5234 mono_class_init (klass);
5236 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5237 if (!im) {
5238 mono_error_set_not_supported (error, "Linked away.");
5239 return NULL;
5241 vtable->domain->create_proxy_for_type_method = im;
5244 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5245 if (!mono_error_ok (error))
5246 return NULL;
5248 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5249 if (!mono_error_ok (error))
5250 return NULL;
5252 if (o != NULL)
5253 return o;
5256 return mono_object_new_alloc_specific_checked (vtable, error);
5259 MonoObject *
5260 ves_icall_object_new_specific (MonoVTable *vtable)
5262 MonoError error;
5263 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5264 mono_error_set_pending_exception (&error);
5266 return o;
5270 * mono_object_new_alloc_specific:
5271 * @vtable: virtual table for the object.
5273 * This function allocates a new `MonoObject` with the type derived
5274 * from the @vtable information. If the class of this object has a
5275 * finalizer, then the object will be tracked for finalization.
5277 * This method might raise an exception on errors. Use the
5278 * `mono_object_new_fast_checked` method if you want to manually raise
5279 * the exception.
5281 * Returns: the allocated object.
5283 MonoObject *
5284 mono_object_new_alloc_specific (MonoVTable *vtable)
5286 MonoError error;
5287 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5288 mono_error_cleanup (&error);
5290 return o;
5294 * mono_object_new_alloc_specific_checked:
5295 * @vtable: virtual table for the object.
5296 * @error: holds the error return value.
5298 * This function allocates a new `MonoObject` with the type derived
5299 * from the @vtable information. If the class of this object has a
5300 * finalizer, then the object will be tracked for finalization.
5302 * If there is not enough memory, the @error parameter will be set
5303 * and will contain a user-visible message with the amount of bytes
5304 * that were requested.
5306 * Returns: the allocated object, or NULL if there is not enough memory
5309 MonoObject *
5310 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5312 MONO_REQ_GC_UNSAFE_MODE;
5314 MonoObject *o;
5316 mono_error_init (error);
5318 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5320 if (G_UNLIKELY (!o))
5321 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5322 else if (G_UNLIKELY (vtable->klass->has_finalize))
5323 mono_object_register_finalizer (o);
5325 return o;
5329 * mono_object_new_fast:
5330 * @vtable: virtual table for the object.
5332 * This function allocates a new `MonoObject` with the type derived
5333 * from the @vtable information. The returned object is not tracked
5334 * for finalization. If your object implements a finalizer, you should
5335 * use `mono_object_new_alloc_specific` instead.
5337 * This method might raise an exception on errors. Use the
5338 * `mono_object_new_fast_checked` method if you want to manually raise
5339 * the exception.
5341 * Returns: the allocated object.
5343 MonoObject*
5344 mono_object_new_fast (MonoVTable *vtable)
5346 MonoError error;
5347 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5348 mono_error_cleanup (&error);
5350 return o;
5354 * mono_object_new_fast_checked:
5355 * @vtable: virtual table for the object.
5356 * @error: holds the error return value.
5358 * This function allocates a new `MonoObject` with the type derived
5359 * from the @vtable information. The returned object is not tracked
5360 * for finalization. If your object implements a finalizer, you should
5361 * use `mono_object_new_alloc_specific_checked` instead.
5363 * If there is not enough memory, the @error parameter will be set
5364 * and will contain a user-visible message with the amount of bytes
5365 * that were requested.
5367 * Returns: the allocated object, or NULL if there is not enough memory
5370 MonoObject*
5371 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5373 MONO_REQ_GC_UNSAFE_MODE;
5375 MonoObject *o;
5377 mono_error_init (error);
5379 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5381 if (G_UNLIKELY (!o))
5382 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5384 return o;
5387 MonoObject *
5388 ves_icall_object_new_fast (MonoVTable *vtable)
5390 MonoError error;
5391 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5392 mono_error_set_pending_exception (&error);
5394 return o;
5397 MonoObject*
5398 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5400 MONO_REQ_GC_UNSAFE_MODE;
5402 MonoObject *o;
5404 mono_error_init (error);
5406 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5408 if (G_UNLIKELY (!o))
5409 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5410 else if (G_UNLIKELY (vtable->klass->has_finalize))
5411 mono_object_register_finalizer (o);
5413 return o;
5417 * mono_class_get_allocation_ftn:
5418 * @vtable: vtable
5419 * @for_box: the object will be used for boxing
5420 * @pass_size_in_words:
5422 * Return the allocation function appropriate for the given class.
5425 void*
5426 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5428 MONO_REQ_GC_NEUTRAL_MODE;
5430 *pass_size_in_words = FALSE;
5432 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5433 return ves_icall_object_new_specific;
5435 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5437 return ves_icall_object_new_fast;
5440 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5441 * of the overhead of parameter passing.
5444 *pass_size_in_words = TRUE;
5445 #ifdef GC_REDIRECT_TO_LOCAL
5446 return GC_local_gcj_fast_malloc;
5447 #else
5448 return GC_gcj_fast_malloc;
5449 #endif
5453 return ves_icall_object_new_specific;
5457 * mono_object_new_from_token:
5458 * @image: Context where the type_token is hosted
5459 * @token: a token of the type that we want to create
5461 * Returns: A newly created object whose definition is
5462 * looked up using @token in the @image image
5464 MonoObject *
5465 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5467 MONO_REQ_GC_UNSAFE_MODE;
5469 MonoError error;
5470 MonoObject *result;
5471 MonoClass *klass;
5473 klass = mono_class_get_checked (image, token, &error);
5474 mono_error_assert_ok (&error);
5476 result = mono_object_new_checked (domain, klass, &error);
5478 mono_error_cleanup (&error);
5479 return result;
5485 * mono_object_clone:
5486 * @obj: the object to clone
5488 * Returns: A newly created object who is a shallow copy of @obj
5490 MonoObject *
5491 mono_object_clone (MonoObject *obj)
5493 MonoError error;
5494 MonoObject *o = mono_object_clone_checked (obj, &error);
5495 mono_error_cleanup (&error);
5497 return o;
5500 MonoObject *
5501 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5503 MONO_REQ_GC_UNSAFE_MODE;
5505 MonoObject *o;
5506 int size;
5508 mono_error_init (error);
5510 size = obj->vtable->klass->instance_size;
5512 if (obj->vtable->klass->rank)
5513 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5515 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5517 if (G_UNLIKELY (!o)) {
5518 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5519 return NULL;
5522 /* If the object doesn't contain references this will do a simple memmove. */
5523 mono_gc_wbarrier_object_copy (o, obj);
5525 if (obj->vtable->klass->has_finalize)
5526 mono_object_register_finalizer (o);
5527 return o;
5531 * mono_array_full_copy:
5532 * @src: source array to copy
5533 * @dest: destination array
5535 * Copies the content of one array to another with exactly the same type and size.
5537 void
5538 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5540 MONO_REQ_GC_UNSAFE_MODE;
5542 uintptr_t size;
5543 MonoClass *klass = src->obj.vtable->klass;
5545 g_assert (klass == dest->obj.vtable->klass);
5547 size = mono_array_length (src);
5548 g_assert (size == mono_array_length (dest));
5549 size *= mono_array_element_size (klass);
5550 #ifdef HAVE_SGEN_GC
5551 if (klass->element_class->valuetype) {
5552 if (klass->element_class->has_references)
5553 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5554 else
5555 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5556 } else {
5557 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5559 #else
5560 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5561 #endif
5565 * mono_array_clone_in_domain:
5566 * @domain: the domain in which the array will be cloned into
5567 * @array: the array to clone
5568 * @error: set on error
5570 * This routine returns a copy of the array that is hosted on the
5571 * specified MonoDomain. On failure returns NULL and sets @error.
5573 MonoArray*
5574 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5576 MONO_REQ_GC_UNSAFE_MODE;
5578 MonoArray *o;
5579 uintptr_t size, i;
5580 uintptr_t *sizes;
5581 MonoClass *klass = array->obj.vtable->klass;
5583 mono_error_init (error);
5585 if (array->bounds == NULL) {
5586 size = mono_array_length (array);
5587 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5588 return_val_if_nok (error, NULL);
5590 size *= mono_array_element_size (klass);
5591 #ifdef HAVE_SGEN_GC
5592 if (klass->element_class->valuetype) {
5593 if (klass->element_class->has_references)
5594 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5595 else
5596 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5597 } else {
5598 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5600 #else
5601 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5602 #endif
5603 return o;
5606 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5607 size = mono_array_element_size (klass);
5608 for (i = 0; i < klass->rank; ++i) {
5609 sizes [i] = array->bounds [i].length;
5610 size *= array->bounds [i].length;
5611 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5613 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5614 return_val_if_nok (error, NULL);
5615 #ifdef HAVE_SGEN_GC
5616 if (klass->element_class->valuetype) {
5617 if (klass->element_class->has_references)
5618 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5619 else
5620 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5621 } else {
5622 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5624 #else
5625 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5626 #endif
5628 return o;
5632 * mono_array_clone:
5633 * @array: the array to clone
5635 * Returns: A newly created array who is a shallow copy of @array
5637 MonoArray*
5638 mono_array_clone (MonoArray *array)
5640 MONO_REQ_GC_UNSAFE_MODE;
5642 MonoError error;
5643 MonoArray *result = mono_array_clone_checked (array, &error);
5644 mono_error_cleanup (&error);
5645 return result;
5649 * mono_array_clone_checked:
5650 * @array: the array to clone
5651 * @error: set on error
5653 * Returns: A newly created array who is a shallow copy of @array. On
5654 * failure returns NULL and sets @error.
5656 MonoArray*
5657 mono_array_clone_checked (MonoArray *array, MonoError *error)
5660 MONO_REQ_GC_UNSAFE_MODE;
5661 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5664 /* helper macros to check for overflow when calculating the size of arrays */
5665 #ifdef MONO_BIG_ARRAYS
5666 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5667 #define MYGUINT_MAX MYGUINT64_MAX
5668 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5669 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5670 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5671 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5672 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5673 #else
5674 #define MYGUINT32_MAX 4294967295U
5675 #define MYGUINT_MAX MYGUINT32_MAX
5676 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5677 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5678 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5679 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5680 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5681 #endif
5683 gboolean
5684 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5686 MONO_REQ_GC_NEUTRAL_MODE;
5688 uintptr_t byte_len;
5690 byte_len = mono_array_element_size (klass);
5691 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5692 return FALSE;
5693 byte_len *= len;
5694 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5695 return FALSE;
5696 byte_len += MONO_SIZEOF_MONO_ARRAY;
5698 *res = byte_len;
5700 return TRUE;
5704 * mono_array_new_full:
5705 * @domain: domain where the object is created
5706 * @array_class: array class
5707 * @lengths: lengths for each dimension in the array
5708 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5710 * This routine creates a new array objects with the given dimensions,
5711 * lower bounds and type.
5713 MonoArray*
5714 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5716 MonoError error;
5717 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5718 mono_error_cleanup (&error);
5720 return array;
5723 MonoArray*
5724 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5726 MONO_REQ_GC_UNSAFE_MODE;
5728 uintptr_t byte_len = 0, len, bounds_size;
5729 MonoObject *o;
5730 MonoArray *array;
5731 MonoArrayBounds *bounds;
5732 MonoVTable *vtable;
5733 int i;
5735 mono_error_init (error);
5737 if (!array_class->inited)
5738 mono_class_init (array_class);
5740 len = 1;
5742 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5743 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5744 len = lengths [0];
5745 if (len > MONO_ARRAY_MAX_INDEX) {
5746 mono_error_set_generic_error (error, "System", "OverflowException", "");
5747 return NULL;
5749 bounds_size = 0;
5750 } else {
5751 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5753 for (i = 0; i < array_class->rank; ++i) {
5754 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5755 mono_error_set_generic_error (error, "System", "OverflowException", "");
5756 return NULL;
5758 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5759 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5760 return NULL;
5762 len *= lengths [i];
5766 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5767 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5768 return NULL;
5771 if (bounds_size) {
5772 /* align */
5773 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5774 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5775 return NULL;
5777 byte_len = (byte_len + 3) & ~3;
5778 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5779 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5780 return NULL;
5782 byte_len += bounds_size;
5785 * Following three lines almost taken from mono_object_new ():
5786 * they need to be kept in sync.
5788 vtable = mono_class_vtable_full (domain, array_class, error);
5789 return_val_if_nok (error, NULL);
5791 if (bounds_size)
5792 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5793 else
5794 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5796 if (G_UNLIKELY (!o)) {
5797 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5798 return NULL;
5801 array = (MonoArray*)o;
5803 bounds = array->bounds;
5805 if (bounds_size) {
5806 for (i = 0; i < array_class->rank; ++i) {
5807 bounds [i].length = lengths [i];
5808 if (lower_bounds)
5809 bounds [i].lower_bound = lower_bounds [i];
5813 return array;
5817 * mono_array_new:
5818 * @domain: domain where the object is created
5819 * @eclass: element class
5820 * @n: number of array elements
5822 * This routine creates a new szarray with @n elements of type @eclass.
5824 MonoArray *
5825 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5827 MONO_REQ_GC_UNSAFE_MODE;
5829 MonoError error;
5830 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5831 mono_error_cleanup (&error);
5832 return result;
5836 * mono_array_new_checked:
5837 * @domain: domain where the object is created
5838 * @eclass: element class
5839 * @n: number of array elements
5840 * @error: set on error
5842 * This routine creates a new szarray with @n elements of type @eclass.
5843 * On failure returns NULL and sets @error.
5845 MonoArray *
5846 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5848 MonoClass *ac;
5850 mono_error_init (error);
5852 ac = mono_array_class_get (eclass, 1);
5853 g_assert (ac);
5855 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5856 return_val_if_nok (error, NULL);
5858 return mono_array_new_specific_checked (vtable, n, error);
5861 MonoArray*
5862 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5864 MonoError error;
5865 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5866 mono_error_set_pending_exception (&error);
5868 return arr;
5872 * mono_array_new_specific:
5873 * @vtable: a vtable in the appropriate domain for an initialized class
5874 * @n: number of array elements
5876 * This routine is a fast alternative to mono_array_new() for code which
5877 * can be sure about the domain it operates in.
5879 MonoArray *
5880 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5882 MonoError error;
5883 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5884 mono_error_cleanup (&error);
5886 return arr;
5889 MonoArray*
5890 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5892 MONO_REQ_GC_UNSAFE_MODE;
5894 MonoObject *o;
5895 uintptr_t byte_len;
5897 mono_error_init (error);
5899 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5900 mono_error_set_generic_error (error, "System", "OverflowException", "");
5901 return NULL;
5904 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5905 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5906 return NULL;
5908 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5910 if (G_UNLIKELY (!o)) {
5911 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5912 return NULL;
5915 return (MonoArray*)o;
5918 MonoArray*
5919 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5921 MonoError error;
5922 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5923 mono_error_set_pending_exception (&error);
5925 return arr;
5929 * mono_string_new_utf16:
5930 * @text: a pointer to an utf16 string
5931 * @len: the length of the string
5933 * Returns: A newly created string object which contains @text.
5935 MonoString *
5936 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5938 MONO_REQ_GC_UNSAFE_MODE;
5940 MonoError error;
5941 MonoString *res = NULL;
5942 res = mono_string_new_utf16_checked (domain, text, len, &error);
5943 mono_error_cleanup (&error);
5945 return res;
5949 * mono_string_new_utf16_checked:
5950 * @text: a pointer to an utf16 string
5951 * @len: the length of the string
5952 * @error: written on error.
5954 * Returns: A newly created string object which contains @text.
5955 * On error, returns NULL and sets @error.
5957 MonoString *
5958 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5960 MONO_REQ_GC_UNSAFE_MODE;
5962 MonoString *s;
5964 mono_error_init (error);
5966 s = mono_string_new_size_checked (domain, len, error);
5967 if (s != NULL)
5968 memcpy (mono_string_chars (s), text, len * 2);
5970 return s;
5974 * mono_string_new_utf32:
5975 * @text: a pointer to an utf32 string
5976 * @len: the length of the string
5977 * @error: set on failure.
5979 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5981 static MonoString *
5982 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5984 MONO_REQ_GC_UNSAFE_MODE;
5986 MonoString *s;
5987 mono_unichar2 *utf16_output = NULL;
5988 gint32 utf16_len = 0;
5989 GError *gerror = NULL;
5990 glong items_written;
5992 mono_error_init (error);
5993 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5995 if (gerror)
5996 g_error_free (gerror);
5998 while (utf16_output [utf16_len]) utf16_len++;
6000 s = mono_string_new_size_checked (domain, utf16_len, error);
6001 return_val_if_nok (error, NULL);
6003 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6005 g_free (utf16_output);
6007 return s;
6011 * mono_string_new_utf32:
6012 * @text: a pointer to an utf32 string
6013 * @len: the length of the string
6015 * Returns: A newly created string object which contains @text.
6017 MonoString *
6018 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6020 MonoError error;
6021 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6022 mono_error_cleanup (&error);
6023 return result;
6027 * mono_string_new_size:
6028 * @text: a pointer to an utf16 string
6029 * @len: the length of the string
6031 * Returns: A newly created string object of @len
6033 MonoString *
6034 mono_string_new_size (MonoDomain *domain, gint32 len)
6036 MonoError error;
6037 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6038 mono_error_cleanup (&error);
6040 return str;
6043 MonoString *
6044 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6046 MONO_REQ_GC_UNSAFE_MODE;
6048 MonoString *s;
6049 MonoVTable *vtable;
6050 size_t size;
6052 mono_error_init (error);
6054 /* check for overflow */
6055 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6056 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6057 return NULL;
6060 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6061 g_assert (size > 0);
6063 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6064 g_assert (vtable);
6066 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6068 if (G_UNLIKELY (!s)) {
6069 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6070 return NULL;
6073 return s;
6077 * mono_string_new_len:
6078 * @text: a pointer to an utf8 string
6079 * @length: number of bytes in @text to consider
6081 * Returns: A newly created string object which contains @text.
6083 MonoString*
6084 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6086 MONO_REQ_GC_UNSAFE_MODE;
6088 MonoError error;
6089 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6090 mono_error_cleanup (&error);
6091 return result;
6095 * mono_string_new_len_checked:
6096 * @text: a pointer to an utf8 string
6097 * @length: number of bytes in @text to consider
6098 * @error: set on error
6100 * Returns: A newly created string object which contains @text. On
6101 * failure returns NULL and sets @error.
6103 MonoString*
6104 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6106 MONO_REQ_GC_UNSAFE_MODE;
6108 mono_error_init (error);
6110 GError *eg_error = NULL;
6111 MonoString *o = NULL;
6112 guint16 *ut = NULL;
6113 glong items_written;
6115 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6117 if (!eg_error)
6118 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6119 else
6120 g_error_free (eg_error);
6122 g_free (ut);
6124 return o;
6128 * mono_string_new:
6129 * @text: a pointer to an utf8 string
6131 * Returns: A newly created string object which contains @text.
6133 * This function asserts if it cannot allocate a new string.
6135 * @deprecated Use mono_string_new_checked in new code.
6137 MonoString*
6138 mono_string_new (MonoDomain *domain, const char *text)
6140 MonoError error;
6141 MonoString *res = NULL;
6142 res = mono_string_new_checked (domain, text, &error);
6143 mono_error_assert_ok (&error);
6144 return res;
6148 * mono_string_new_checked:
6149 * @text: a pointer to an utf8 string
6150 * @merror: set on error
6152 * Returns: A newly created string object which contains @text.
6153 * On error returns NULL and sets @merror.
6155 MonoString*
6156 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6158 MONO_REQ_GC_UNSAFE_MODE;
6160 GError *eg_error = NULL;
6161 MonoString *o = NULL;
6162 guint16 *ut;
6163 glong items_written;
6164 int l;
6166 mono_error_init (error);
6168 l = strlen (text);
6170 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6172 if (!eg_error)
6173 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6174 else
6175 g_error_free (eg_error);
6177 g_free (ut);
6179 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6180 #if 0
6181 gunichar2 *str;
6182 const gchar *end;
6183 int len;
6184 MonoString *o = NULL;
6186 if (!g_utf8_validate (text, -1, &end)) {
6187 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6188 goto leave;
6191 len = g_utf8_strlen (text, -1);
6192 o = mono_string_new_size_checked (domain, len, error);
6193 if (!o)
6194 goto leave;
6195 str = mono_string_chars (o);
6197 while (text < end) {
6198 *str++ = g_utf8_get_char (text);
6199 text = g_utf8_next_char (text);
6202 leave:
6203 #endif
6204 return o;
6208 * mono_string_new_wrapper:
6209 * @text: pointer to utf8 characters.
6211 * Helper function to create a string object from @text in the current domain.
6213 MonoString*
6214 mono_string_new_wrapper (const char *text)
6216 MONO_REQ_GC_UNSAFE_MODE;
6218 MonoDomain *domain = mono_domain_get ();
6220 if (text)
6221 return mono_string_new (domain, text);
6223 return NULL;
6227 * mono_value_box:
6228 * @class: the class of the value
6229 * @value: a pointer to the unboxed data
6231 * Returns: A newly created object which contains @value.
6233 MonoObject *
6234 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6236 MonoError error;
6237 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6238 mono_error_cleanup (&error);
6239 return result;
6243 * mono_value_box_checked:
6244 * @domain: the domain of the new object
6245 * @class: the class of the value
6246 * @value: a pointer to the unboxed data
6247 * @error: set on error
6249 * Returns: A newly created object which contains @value. On failure
6250 * returns NULL and sets @error.
6252 MonoObject *
6253 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6255 MONO_REQ_GC_UNSAFE_MODE;
6256 MonoObject *res;
6257 int size;
6258 MonoVTable *vtable;
6260 mono_error_init (error);
6262 g_assert (klass->valuetype);
6263 if (mono_class_is_nullable (klass))
6264 return mono_nullable_box ((guint8 *)value, klass, error);
6266 vtable = mono_class_vtable (domain, klass);
6267 if (!vtable)
6268 return NULL;
6269 size = mono_class_instance_size (klass);
6270 res = mono_object_new_alloc_specific_checked (vtable, error);
6271 return_val_if_nok (error, NULL);
6273 size = size - sizeof (MonoObject);
6275 #ifdef HAVE_SGEN_GC
6276 g_assert (size == mono_class_value_size (klass, NULL));
6277 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6278 #else
6279 #if NO_UNALIGNED_ACCESS
6280 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6281 #else
6282 switch (size) {
6283 case 1:
6284 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6285 break;
6286 case 2:
6287 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6288 break;
6289 case 4:
6290 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6291 break;
6292 case 8:
6293 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6294 break;
6295 default:
6296 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6298 #endif
6299 #endif
6300 if (klass->has_finalize) {
6301 mono_object_register_finalizer (res);
6302 return_val_if_nok (error, NULL);
6304 return res;
6308 * mono_value_copy:
6309 * @dest: destination pointer
6310 * @src: source pointer
6311 * @klass: a valuetype class
6313 * Copy a valuetype from @src to @dest. This function must be used
6314 * when @klass contains references fields.
6316 void
6317 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6319 MONO_REQ_GC_UNSAFE_MODE;
6321 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6325 * mono_value_copy_array:
6326 * @dest: destination array
6327 * @dest_idx: index in the @dest array
6328 * @src: source pointer
6329 * @count: number of items
6331 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6332 * This function must be used when @klass contains references fields.
6333 * Overlap is handled.
6335 void
6336 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6338 MONO_REQ_GC_UNSAFE_MODE;
6340 int size = mono_array_element_size (dest->obj.vtable->klass);
6341 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6342 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6343 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6347 * mono_object_get_domain:
6348 * @obj: object to query
6350 * Returns: the MonoDomain where the object is hosted
6352 MonoDomain*
6353 mono_object_get_domain (MonoObject *obj)
6355 MONO_REQ_GC_UNSAFE_MODE;
6357 return mono_object_domain (obj);
6361 * mono_object_get_class:
6362 * @obj: object to query
6364 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6366 * Returns: the MonoClass of the object.
6368 MonoClass*
6369 mono_object_get_class (MonoObject *obj)
6371 MONO_REQ_GC_UNSAFE_MODE;
6373 return mono_object_class (obj);
6376 * mono_object_get_size:
6377 * @o: object to query
6379 * Returns: the size, in bytes, of @o
6381 guint
6382 mono_object_get_size (MonoObject* o)
6384 MONO_REQ_GC_UNSAFE_MODE;
6386 MonoClass* klass = mono_object_class (o);
6387 if (klass == mono_defaults.string_class) {
6388 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6389 } else if (o->vtable->rank) {
6390 MonoArray *array = (MonoArray*)o;
6391 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6392 if (array->bounds) {
6393 size += 3;
6394 size &= ~3;
6395 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6397 return size;
6398 } else {
6399 return mono_class_instance_size (klass);
6404 * mono_object_unbox:
6405 * @obj: object to unbox
6407 * Returns: a pointer to the start of the valuetype boxed in this
6408 * object.
6410 * This method will assert if the object passed is not a valuetype.
6412 gpointer
6413 mono_object_unbox (MonoObject *obj)
6415 MONO_REQ_GC_UNSAFE_MODE;
6417 /* add assert for valuetypes? */
6418 g_assert (obj->vtable->klass->valuetype);
6419 return ((char*)obj) + sizeof (MonoObject);
6423 * mono_object_isinst:
6424 * @obj: an object
6425 * @klass: a pointer to a class
6427 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6429 MonoObject *
6430 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6432 MONO_REQ_GC_UNSAFE_MODE;
6434 MonoError error;
6435 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6436 mono_error_cleanup (&error);
6437 return result;
6442 * mono_object_isinst_checked:
6443 * @obj: an object
6444 * @klass: a pointer to a class
6445 * @error: set on error
6447 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6448 * On failure returns NULL and sets @error.
6450 MonoObject *
6451 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6453 MONO_REQ_GC_UNSAFE_MODE;
6455 mono_error_init (error);
6457 MonoObject *result = NULL;
6459 if (!klass->inited)
6460 mono_class_init (klass);
6462 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6463 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6464 return result;
6467 if (!obj)
6468 return NULL;
6470 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6473 MonoObject *
6474 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6476 MONO_REQ_GC_UNSAFE_MODE;
6478 MonoError error;
6479 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6480 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6481 return result;
6484 MonoObject *
6485 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6487 MONO_REQ_GC_UNSAFE_MODE;
6489 MonoVTable *vt;
6491 mono_error_init (error);
6493 if (!obj)
6494 return NULL;
6496 vt = obj->vtable;
6498 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6499 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6500 return obj;
6503 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6504 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6505 return obj;
6506 } else {
6507 MonoClass *oklass = vt->klass;
6508 if (mono_class_is_transparent_proxy (oklass))
6509 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6511 mono_class_setup_supertypes (klass);
6512 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6513 return obj;
6515 #ifndef DISABLE_REMOTING
6516 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6518 MonoDomain *domain = mono_domain_get ();
6519 MonoObject *res;
6520 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6521 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6522 MonoMethod *im = NULL;
6523 gpointer pa [2];
6525 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6526 if (!im) {
6527 mono_error_set_not_supported (error, "Linked away.");
6528 return NULL;
6530 im = mono_object_get_virtual_method (rp, im);
6531 g_assert (im);
6533 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6534 return_val_if_nok (error, NULL);
6535 pa [1] = obj;
6537 res = mono_runtime_invoke_checked (im, rp, pa, error);
6538 return_val_if_nok (error, NULL);
6540 if (*(MonoBoolean *) mono_object_unbox(res)) {
6541 /* Update the vtable of the remote type, so it can safely cast to this new type */
6542 mono_upgrade_remote_class (domain, obj, klass, error);
6543 return_val_if_nok (error, NULL);
6544 return obj;
6547 #endif /* DISABLE_REMOTING */
6548 return NULL;
6552 * mono_object_castclass_mbyref:
6553 * @obj: an object
6554 * @klass: a pointer to a class
6556 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6558 MonoObject *
6559 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6561 MONO_REQ_GC_UNSAFE_MODE;
6562 MonoError error;
6564 if (!obj) return NULL;
6565 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6566 mono_error_cleanup (&error);
6567 return NULL;
6570 typedef struct {
6571 MonoDomain *orig_domain;
6572 MonoString *ins;
6573 MonoString *res;
6574 } LDStrInfo;
6576 static void
6577 str_lookup (MonoDomain *domain, gpointer user_data)
6579 MONO_REQ_GC_UNSAFE_MODE;
6581 LDStrInfo *info = (LDStrInfo *)user_data;
6582 if (info->res || domain == info->orig_domain)
6583 return;
6584 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6587 static MonoString*
6588 mono_string_get_pinned (MonoString *str, MonoError *error)
6590 MONO_REQ_GC_UNSAFE_MODE;
6592 mono_error_init (error);
6594 /* We only need to make a pinned version of a string if this is a moving GC */
6595 if (!mono_gc_is_moving ())
6596 return str;
6597 int size;
6598 MonoString *news;
6599 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6600 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6601 if (news) {
6602 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6603 news->length = mono_string_length (str);
6604 } else {
6605 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6607 return news;
6610 static MonoString*
6611 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6613 MONO_REQ_GC_UNSAFE_MODE;
6615 MonoGHashTable *ldstr_table;
6616 MonoString *s, *res;
6617 MonoDomain *domain;
6619 mono_error_init (error);
6621 domain = ((MonoObject *)str)->vtable->domain;
6622 ldstr_table = domain->ldstr_table;
6623 ldstr_lock ();
6624 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6625 if (res) {
6626 ldstr_unlock ();
6627 return res;
6629 if (insert) {
6630 /* Allocate outside the lock */
6631 ldstr_unlock ();
6632 s = mono_string_get_pinned (str, error);
6633 return_val_if_nok (error, NULL);
6634 if (s) {
6635 ldstr_lock ();
6636 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6637 if (res) {
6638 ldstr_unlock ();
6639 return res;
6641 mono_g_hash_table_insert (ldstr_table, s, s);
6642 ldstr_unlock ();
6644 return s;
6645 } else {
6646 LDStrInfo ldstr_info;
6647 ldstr_info.orig_domain = domain;
6648 ldstr_info.ins = str;
6649 ldstr_info.res = NULL;
6651 mono_domain_foreach (str_lookup, &ldstr_info);
6652 if (ldstr_info.res) {
6654 * the string was already interned in some other domain:
6655 * intern it in the current one as well.
6657 mono_g_hash_table_insert (ldstr_table, str, str);
6658 ldstr_unlock ();
6659 return str;
6662 ldstr_unlock ();
6663 return NULL;
6667 * mono_string_is_interned:
6668 * @o: String to probe
6670 * Returns whether the string has been interned.
6672 MonoString*
6673 mono_string_is_interned (MonoString *o)
6675 MonoError error;
6676 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6677 /* This function does not fail. */
6678 mono_error_assert_ok (&error);
6679 return result;
6683 * mono_string_intern:
6684 * @o: String to intern
6686 * Interns the string passed.
6687 * Returns: The interned string.
6689 MonoString*
6690 mono_string_intern (MonoString *str)
6692 MonoError error;
6693 MonoString *result = mono_string_intern_checked (str, &error);
6694 mono_error_assert_ok (&error);
6695 return result;
6699 * mono_string_intern_checked:
6700 * @o: String to intern
6701 * @error: set on error.
6703 * Interns the string passed.
6704 * Returns: The interned string. On failure returns NULL and sets @error
6706 MonoString*
6707 mono_string_intern_checked (MonoString *str, MonoError *error)
6709 MONO_REQ_GC_UNSAFE_MODE;
6711 mono_error_init (error);
6713 return mono_string_is_interned_lookup (str, TRUE, error);
6717 * mono_ldstr:
6718 * @domain: the domain where the string will be used.
6719 * @image: a metadata context
6720 * @idx: index into the user string table.
6722 * Implementation for the ldstr opcode.
6723 * Returns: a loaded string from the @image/@idx combination.
6725 MonoString*
6726 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6728 MonoError error;
6729 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6730 mono_error_cleanup (&error);
6731 return result;
6735 * mono_ldstr_checked:
6736 * @domain: the domain where the string will be used.
6737 * @image: a metadata context
6738 * @idx: index into the user string table.
6739 * @error: set on error.
6741 * Implementation for the ldstr opcode.
6742 * Returns: a loaded string from the @image/@idx combination.
6743 * On failure returns NULL and sets @error.
6745 MonoString*
6746 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6748 MONO_REQ_GC_UNSAFE_MODE;
6749 mono_error_init (error);
6751 if (image->dynamic) {
6752 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6753 return str;
6754 } else {
6755 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6756 return NULL; /*FIXME we should probably be raising an exception here*/
6757 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6758 return str;
6763 * mono_ldstr_metadata_sig
6764 * @domain: the domain for the string
6765 * @sig: the signature of a metadata string
6766 * @error: set on error
6768 * Returns: a MonoString for a string stored in the metadata. On
6769 * failure returns NULL and sets @error.
6771 static MonoString*
6772 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6774 MONO_REQ_GC_UNSAFE_MODE;
6776 mono_error_init (error);
6777 const char *str = sig;
6778 MonoString *o, *interned;
6779 size_t len2;
6781 len2 = mono_metadata_decode_blob_size (str, &str);
6782 len2 >>= 1;
6784 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6785 return_val_if_nok (error, NULL);
6786 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6788 int i;
6789 guint16 *p2 = (guint16*)mono_string_chars (o);
6790 for (i = 0; i < len2; ++i) {
6791 *p2 = GUINT16_FROM_LE (*p2);
6792 ++p2;
6795 #endif
6796 ldstr_lock ();
6797 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6798 ldstr_unlock ();
6799 if (interned)
6800 return interned; /* o will get garbage collected */
6802 o = mono_string_get_pinned (o, error);
6803 if (o) {
6804 ldstr_lock ();
6805 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6806 if (!interned) {
6807 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6808 interned = o;
6810 ldstr_unlock ();
6813 return interned;
6817 * mono_ldstr_utf8:
6819 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6820 * of an object.
6822 char*
6823 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6825 const char *str;
6826 size_t len2;
6827 long written = 0;
6828 char *as;
6829 GError *gerror = NULL;
6831 mono_error_init (error);
6833 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6834 return NULL; /*FIXME we should probably be raising an exception here*/
6835 str = mono_metadata_user_string (image, idx);
6837 len2 = mono_metadata_decode_blob_size (str, &str);
6838 len2 >>= 1;
6840 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6841 if (gerror) {
6842 mono_error_set_argument (error, "string", "%s", gerror->message);
6843 g_error_free (gerror);
6844 return NULL;
6846 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6847 if (len2 > written) {
6848 /* allocate the total length and copy the part of the string that has been converted */
6849 char *as2 = (char *)g_malloc0 (len2);
6850 memcpy (as2, as, written);
6851 g_free (as);
6852 as = as2;
6855 return as;
6859 * mono_string_to_utf8:
6860 * @s: a System.String
6862 * Returns the UTF8 representation for @s.
6863 * The resulting buffer needs to be freed with mono_free().
6865 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6867 char *
6868 mono_string_to_utf8 (MonoString *s)
6870 MONO_REQ_GC_UNSAFE_MODE;
6872 MonoError error;
6873 char *result = mono_string_to_utf8_checked (s, &error);
6875 if (!is_ok (&error)) {
6876 mono_error_cleanup (&error);
6877 return NULL;
6879 return result;
6883 * mono_string_to_utf8_checked:
6884 * @s: a System.String
6885 * @error: a MonoError.
6887 * Converts a MonoString to its UTF8 representation. May fail; check
6888 * @error to determine whether the conversion was successful.
6889 * The resulting buffer should be freed with mono_free().
6891 char *
6892 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6894 MONO_REQ_GC_UNSAFE_MODE;
6896 long written = 0;
6897 char *as;
6898 GError *gerror = NULL;
6900 mono_error_init (error);
6902 if (s == NULL)
6903 return NULL;
6905 if (!s->length)
6906 return g_strdup ("");
6908 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6909 if (gerror) {
6910 mono_error_set_argument (error, "string", "%s", gerror->message);
6911 g_error_free (gerror);
6912 return NULL;
6914 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6915 if (s->length > written) {
6916 /* allocate the total length and copy the part of the string that has been converted */
6917 char *as2 = (char *)g_malloc0 (s->length);
6918 memcpy (as2, as, written);
6919 g_free (as);
6920 as = as2;
6923 return as;
6927 * mono_string_to_utf8_ignore:
6928 * @s: a MonoString
6930 * Converts a MonoString to its UTF8 representation. Will ignore
6931 * invalid surrogate pairs.
6932 * The resulting buffer should be freed with mono_free().
6935 char *
6936 mono_string_to_utf8_ignore (MonoString *s)
6938 MONO_REQ_GC_UNSAFE_MODE;
6940 long written = 0;
6941 char *as;
6943 if (s == NULL)
6944 return NULL;
6946 if (!s->length)
6947 return g_strdup ("");
6949 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6951 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6952 if (s->length > written) {
6953 /* allocate the total length and copy the part of the string that has been converted */
6954 char *as2 = (char *)g_malloc0 (s->length);
6955 memcpy (as2, as, written);
6956 g_free (as);
6957 as = as2;
6960 return as;
6964 * mono_string_to_utf8_image_ignore:
6965 * @s: a System.String
6967 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6969 char *
6970 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6972 MONO_REQ_GC_UNSAFE_MODE;
6974 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6978 * mono_string_to_utf8_mp_ignore:
6979 * @s: a System.String
6981 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6983 char *
6984 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6986 MONO_REQ_GC_UNSAFE_MODE;
6988 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6993 * mono_string_to_utf16:
6994 * @s: a MonoString
6996 * Return an null-terminated array of the utf-16 chars
6997 * contained in @s. The result must be freed with g_free().
6998 * This is a temporary helper until our string implementation
6999 * is reworked to always include the null terminating char.
7001 mono_unichar2*
7002 mono_string_to_utf16 (MonoString *s)
7004 MONO_REQ_GC_UNSAFE_MODE;
7006 char *as;
7008 if (s == NULL)
7009 return NULL;
7011 as = (char *)g_malloc ((s->length * 2) + 2);
7012 as [(s->length * 2)] = '\0';
7013 as [(s->length * 2) + 1] = '\0';
7015 if (!s->length) {
7016 return (gunichar2 *)(as);
7019 memcpy (as, mono_string_chars(s), s->length * 2);
7020 return (gunichar2 *)(as);
7024 * mono_string_to_utf32:
7025 * @s: a MonoString
7027 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7028 * contained in @s. The result must be freed with g_free().
7030 mono_unichar4*
7031 mono_string_to_utf32 (MonoString *s)
7033 MONO_REQ_GC_UNSAFE_MODE;
7035 mono_unichar4 *utf32_output = NULL;
7036 GError *error = NULL;
7037 glong items_written;
7039 if (s == NULL)
7040 return NULL;
7042 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7044 if (error)
7045 g_error_free (error);
7047 return utf32_output;
7051 * mono_string_from_utf16:
7052 * @data: the UTF16 string (LPWSTR) to convert
7054 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7056 * Returns: a MonoString.
7058 MonoString *
7059 mono_string_from_utf16 (gunichar2 *data)
7061 MonoError error;
7062 MonoString *result = mono_string_from_utf16_checked (data, &error);
7063 mono_error_cleanup (&error);
7064 return result;
7068 * mono_string_from_utf16_checked:
7069 * @data: the UTF16 string (LPWSTR) to convert
7070 * @error: set on error
7072 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7074 * Returns: a MonoString. On failure sets @error and returns NULL.
7076 MonoString *
7077 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7080 MONO_REQ_GC_UNSAFE_MODE;
7082 mono_error_init (error);
7083 MonoDomain *domain = mono_domain_get ();
7084 int len = 0;
7086 if (!data)
7087 return NULL;
7089 while (data [len]) len++;
7091 return mono_string_new_utf16_checked (domain, data, len, error);
7095 * mono_string_from_utf32:
7096 * @data: the UTF32 string (LPWSTR) to convert
7098 * Converts a UTF32 (UCS-4)to a MonoString.
7100 * Returns: a MonoString.
7102 MonoString *
7103 mono_string_from_utf32 (mono_unichar4 *data)
7105 MonoError error;
7106 MonoString *result = mono_string_from_utf32_checked (data, &error);
7107 mono_error_cleanup (&error);
7108 return result;
7112 * mono_string_from_utf32_checked:
7113 * @data: the UTF32 string (LPWSTR) to convert
7114 * @error: set on error
7116 * Converts a UTF32 (UCS-4)to a MonoString.
7118 * Returns: a MonoString. On failure returns NULL and sets @error.
7120 MonoString *
7121 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7123 MONO_REQ_GC_UNSAFE_MODE;
7125 mono_error_init (error);
7126 MonoString* result = NULL;
7127 mono_unichar2 *utf16_output = NULL;
7128 GError *gerror = NULL;
7129 glong items_written;
7130 int len = 0;
7132 if (!data)
7133 return NULL;
7135 while (data [len]) len++;
7137 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7139 if (gerror)
7140 g_error_free (gerror);
7142 result = mono_string_from_utf16_checked (utf16_output, error);
7143 g_free (utf16_output);
7144 return result;
7147 static char *
7148 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7150 MONO_REQ_GC_UNSAFE_MODE;
7152 char *r;
7153 char *mp_s;
7154 int len;
7156 if (ignore_error) {
7157 r = mono_string_to_utf8_ignore (s);
7158 } else {
7159 r = mono_string_to_utf8_checked (s, error);
7160 if (!mono_error_ok (error))
7161 return NULL;
7164 if (!mp && !image)
7165 return r;
7167 len = strlen (r) + 1;
7168 if (mp)
7169 mp_s = (char *)mono_mempool_alloc (mp, len);
7170 else
7171 mp_s = (char *)mono_image_alloc (image, len);
7173 memcpy (mp_s, r, len);
7175 g_free (r);
7177 return mp_s;
7181 * mono_string_to_utf8_image:
7182 * @s: a System.String
7184 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7186 char *
7187 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7189 MONO_REQ_GC_UNSAFE_MODE;
7191 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7195 * mono_string_to_utf8_mp:
7196 * @s: a System.String
7198 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7200 char *
7201 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7203 MONO_REQ_GC_UNSAFE_MODE;
7205 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7209 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7211 void
7212 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7214 eh_callbacks = *cbs;
7217 MonoRuntimeExceptionHandlingCallbacks *
7218 mono_get_eh_callbacks (void)
7220 return &eh_callbacks;
7224 * mono_raise_exception:
7225 * @ex: exception object
7227 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7229 void
7230 mono_raise_exception (MonoException *ex)
7232 MONO_REQ_GC_UNSAFE_MODE;
7235 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7236 * that will cause gcc to omit the function epilog, causing problems when
7237 * the JIT tries to walk the stack, since the return address on the stack
7238 * will point into the next function in the executable, not this one.
7240 eh_callbacks.mono_raise_exception (ex);
7243 void
7244 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7246 MONO_REQ_GC_UNSAFE_MODE;
7248 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7252 * mono_wait_handle_new:
7253 * @domain: Domain where the object will be created
7254 * @handle: Handle for the wait handle
7255 * @error: set on error.
7257 * Returns: A new MonoWaitHandle created in the given domain for the
7258 * given handle. On failure returns NULL and sets @rror.
7260 MonoWaitHandle *
7261 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7263 MONO_REQ_GC_UNSAFE_MODE;
7265 MonoWaitHandle *res;
7266 gpointer params [1];
7267 static MonoMethod *handle_set;
7269 mono_error_init (error);
7270 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7271 return_val_if_nok (error, NULL);
7273 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7274 if (!handle_set)
7275 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7277 params [0] = &handle;
7279 mono_runtime_invoke_checked (handle_set, res, params, error);
7280 return res;
7283 HANDLE
7284 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7286 MONO_REQ_GC_UNSAFE_MODE;
7288 static MonoClassField *f_safe_handle = NULL;
7289 MonoSafeHandle *sh;
7291 if (!f_safe_handle) {
7292 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7293 g_assert (f_safe_handle);
7296 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7297 return sh->handle;
7301 static MonoObject*
7302 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7304 MONO_REQ_GC_UNSAFE_MODE;
7306 RuntimeInvokeFunction runtime_invoke;
7308 mono_error_init (error);
7310 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7311 MonoMethod *method = mono_get_context_capture_method ();
7312 MonoMethod *wrapper;
7313 if (!method)
7314 return NULL;
7315 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7316 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7317 return_val_if_nok (error, NULL);
7318 domain->capture_context_method = mono_compile_method_checked (method, error);
7319 return_val_if_nok (error, NULL);
7322 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7324 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7327 * mono_async_result_new:
7328 * @domain:domain where the object will be created.
7329 * @handle: wait handle.
7330 * @state: state to pass to AsyncResult
7331 * @data: C closure data.
7332 * @error: set on error.
7334 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7335 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7336 * On failure returns NULL and sets @error.
7339 MonoAsyncResult *
7340 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7342 MONO_REQ_GC_UNSAFE_MODE;
7344 mono_error_init (error);
7345 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7346 return_val_if_nok (error, NULL);
7347 MonoObject *context = mono_runtime_capture_context (domain, error);
7348 return_val_if_nok (error, NULL);
7349 /* we must capture the execution context from the original thread */
7350 if (context) {
7351 MONO_OBJECT_SETREF (res, execution_context, context);
7352 /* note: result may be null if the flow is suppressed */
7355 res->data = (void **)data;
7356 MONO_OBJECT_SETREF (res, object_data, object_data);
7357 MONO_OBJECT_SETREF (res, async_state, state);
7358 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7359 return_val_if_nok (error, NULL);
7360 if (handle != NULL)
7361 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7363 res->sync_completed = FALSE;
7364 res->completed = FALSE;
7366 return res;
7369 MonoObject *
7370 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7372 MONO_REQ_GC_UNSAFE_MODE;
7374 MonoError error;
7375 MonoAsyncCall *ac;
7376 MonoObject *res;
7378 g_assert (ares);
7379 g_assert (ares->async_delegate);
7381 ac = (MonoAsyncCall*) ares->object_data;
7382 if (!ac) {
7383 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7384 if (mono_error_set_pending_exception (&error))
7385 return NULL;
7386 } else {
7387 gpointer wait_event = NULL;
7389 ac->msg->exc = NULL;
7390 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7391 if (mono_error_set_pending_exception (&error))
7392 return NULL;
7393 MONO_OBJECT_SETREF (ac, res, res);
7395 mono_monitor_enter ((MonoObject*) ares);
7396 ares->completed = 1;
7397 if (ares->handle)
7398 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7399 mono_monitor_exit ((MonoObject*) ares);
7401 if (wait_event != NULL)
7402 SetEvent (wait_event);
7404 if (ac->cb_method) {
7405 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7406 if (mono_error_set_pending_exception (&error))
7407 return NULL;
7411 return res;
7414 gboolean
7415 mono_message_init (MonoDomain *domain,
7416 MonoMethodMessage *this_obj,
7417 MonoReflectionMethod *method,
7418 MonoArray *out_args,
7419 MonoError *error)
7421 MONO_REQ_GC_UNSAFE_MODE;
7423 static MonoClass *object_array_klass;
7424 static MonoClass *byte_array_klass;
7425 static MonoClass *string_array_klass;
7426 mono_error_init (error);
7427 MonoMethodSignature *sig = mono_method_signature (method->method);
7428 MonoString *name;
7429 MonoArray *arr;
7430 int i, j;
7431 char **names;
7432 guint8 arg_type;
7434 if (!object_array_klass) {
7435 MonoClass *klass;
7437 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7438 g_assert (klass);
7439 byte_array_klass = klass;
7441 klass = mono_array_class_get (mono_defaults.string_class, 1);
7442 g_assert (klass);
7443 string_array_klass = klass;
7445 klass = mono_array_class_get (mono_defaults.object_class, 1);
7446 g_assert (klass);
7448 mono_atomic_store_release (&object_array_klass, klass);
7451 MONO_OBJECT_SETREF (this_obj, method, method);
7453 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, error);
7454 return_val_if_nok (error, FALSE);
7456 MONO_OBJECT_SETREF (this_obj, args, arr);
7458 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, error);
7459 return_val_if_nok (error, FALSE);
7461 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7463 this_obj->async_result = NULL;
7464 this_obj->call_type = CallType_Sync;
7466 names = g_new (char *, sig->param_count);
7467 mono_method_get_param_names (method->method, (const char **) names);
7469 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, error);
7470 if (!is_ok (error))
7471 goto fail;
7473 MONO_OBJECT_SETREF (this_obj, names, arr);
7475 for (i = 0; i < sig->param_count; i++) {
7476 name = mono_string_new_checked (domain, names [i], error);
7477 if (!is_ok (error))
7478 goto fail;
7479 mono_array_setref (this_obj->names, i, name);
7482 g_free (names);
7483 for (i = 0, j = 0; i < sig->param_count; i++) {
7484 if (sig->params [i]->byref) {
7485 if (out_args) {
7486 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7487 mono_array_setref (this_obj->args, i, arg);
7488 j++;
7490 arg_type = 2;
7491 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7492 arg_type |= 1;
7493 } else {
7494 arg_type = 1;
7495 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7496 arg_type |= 4;
7498 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7501 return TRUE;
7502 fail:
7503 g_free (names);
7504 return FALSE;
7507 #ifndef DISABLE_REMOTING
7509 * mono_remoting_invoke:
7510 * @real_proxy: pointer to a RealProxy object
7511 * @msg: The MonoMethodMessage to execute
7512 * @exc: used to store exceptions
7513 * @out_args: used to store output arguments
7515 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7516 * IMessage interface and it is not trivial to extract results from there. So
7517 * we call an helper method PrivateInvoke instead of calling
7518 * RealProxy::Invoke() directly.
7520 * Returns: the result object.
7522 MonoObject *
7523 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7525 MONO_REQ_GC_UNSAFE_MODE;
7527 MonoObject *o;
7528 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7529 gpointer pa [4];
7531 g_assert (exc);
7533 mono_error_init (error);
7535 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7537 if (!im) {
7538 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7539 if (!im) {
7540 mono_error_set_not_supported (error, "Linked away.");
7541 return NULL;
7543 real_proxy->vtable->domain->private_invoke_method = im;
7546 pa [0] = real_proxy;
7547 pa [1] = msg;
7548 pa [2] = exc;
7549 pa [3] = out_args;
7551 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7552 return_val_if_nok (error, NULL);
7554 return o;
7556 #endif
7558 MonoObject *
7559 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7560 MonoObject **exc, MonoArray **out_args, MonoError *error)
7562 MONO_REQ_GC_UNSAFE_MODE;
7564 static MonoClass *object_array_klass;
7565 mono_error_init (error);
7567 MonoDomain *domain;
7568 MonoMethod *method;
7569 MonoMethodSignature *sig;
7570 MonoArray *arr;
7571 int i, j, outarg_count = 0;
7573 #ifndef DISABLE_REMOTING
7574 if (target && mono_object_is_transparent_proxy (target)) {
7575 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7576 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7577 target = tp->rp->unwrapped_server;
7578 } else {
7579 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7582 #endif
7584 domain = mono_domain_get ();
7585 method = msg->method->method;
7586 sig = mono_method_signature (method);
7588 for (i = 0; i < sig->param_count; i++) {
7589 if (sig->params [i]->byref)
7590 outarg_count++;
7593 if (!object_array_klass) {
7594 MonoClass *klass;
7596 klass = mono_array_class_get (mono_defaults.object_class, 1);
7597 g_assert (klass);
7599 mono_memory_barrier ();
7600 object_array_klass = klass;
7603 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7604 return_val_if_nok (error, NULL);
7606 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7607 *exc = NULL;
7609 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7610 return_val_if_nok (error, NULL);
7612 for (i = 0, j = 0; i < sig->param_count; i++) {
7613 if (sig->params [i]->byref) {
7614 MonoObject* arg;
7615 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7616 mono_array_setref (*out_args, j, arg);
7617 j++;
7621 return ret;
7625 * prepare_to_string_method:
7626 * @obj: The object
7627 * @target: Set to @obj or unboxed value if a valuetype
7629 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7631 static MonoMethod *
7632 prepare_to_string_method (MonoObject *obj, void **target)
7634 MONO_REQ_GC_UNSAFE_MODE;
7636 static MonoMethod *to_string = NULL;
7637 MonoMethod *method;
7638 g_assert (target);
7639 g_assert (obj);
7641 *target = obj;
7643 if (!to_string)
7644 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7646 method = mono_object_get_virtual_method (obj, to_string);
7648 // Unbox value type if needed
7649 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7650 *target = mono_object_unbox (obj);
7652 return method;
7656 * mono_object_to_string:
7657 * @obj: The object
7658 * @exc: Any exception thrown by ToString (). May be NULL.
7660 * Returns: the result of calling ToString () on an object.
7662 MonoString *
7663 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7665 MonoError error;
7666 MonoString *s = NULL;
7667 void *target;
7668 MonoMethod *method = prepare_to_string_method (obj, &target);
7669 if (exc) {
7670 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7671 if (*exc == NULL && !mono_error_ok (&error))
7672 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7673 else
7674 mono_error_cleanup (&error);
7675 } else {
7676 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7677 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7680 return s;
7684 * mono_object_to_string_checked:
7685 * @obj: The object
7686 * @error: Set on error.
7688 * Returns: the result of calling ToString () on an object. If the
7689 * method cannot be invoked or if it raises an exception, sets @error
7690 * and returns NULL.
7692 MonoString *
7693 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7695 mono_error_init (error);
7696 void *target;
7697 MonoMethod *method = prepare_to_string_method (obj, &target);
7698 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7702 * mono_object_try_to_string:
7703 * @obj: The object
7704 * @exc: Any exception thrown by ToString (). Must not be NULL.
7705 * @error: Set if method cannot be invoked.
7707 * Returns: the result of calling ToString () on an object. If the
7708 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7709 * and returns NULL.
7711 MonoString *
7712 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7714 g_assert (exc);
7715 mono_error_init (error);
7716 void *target;
7717 MonoMethod *method = prepare_to_string_method (obj, &target);
7718 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7724 * mono_print_unhandled_exception:
7725 * @exc: The exception
7727 * Prints the unhandled exception.
7729 void
7730 mono_print_unhandled_exception (MonoObject *exc)
7732 MONO_REQ_GC_UNSAFE_MODE;
7734 MonoString * str;
7735 char *message = (char*)"";
7736 gboolean free_message = FALSE;
7737 MonoError error;
7739 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7740 message = g_strdup ("OutOfMemoryException");
7741 free_message = TRUE;
7742 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7743 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7744 free_message = TRUE;
7745 } else {
7747 if (((MonoException*)exc)->native_trace_ips) {
7748 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7749 free_message = TRUE;
7750 } else {
7751 MonoObject *other_exc = NULL;
7752 str = mono_object_try_to_string (exc, &other_exc, &error);
7753 if (other_exc == NULL && !is_ok (&error))
7754 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7755 else
7756 mono_error_cleanup (&error);
7757 if (other_exc) {
7758 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7759 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7761 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7762 original_backtrace, nested_backtrace);
7764 g_free (original_backtrace);
7765 g_free (nested_backtrace);
7766 free_message = TRUE;
7767 } else if (str) {
7768 message = mono_string_to_utf8_checked (str, &error);
7769 if (!mono_error_ok (&error)) {
7770 mono_error_cleanup (&error);
7771 message = (char *) "";
7772 } else {
7773 free_message = TRUE;
7780 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7781 * exc->vtable->klass->name, message);
7783 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7785 if (free_message)
7786 g_free (message);
7790 * mono_delegate_ctor_with_method:
7791 * @this: pointer to an uninitialized delegate object
7792 * @target: target object
7793 * @addr: pointer to native code
7794 * @method: method
7795 * @error: set on error.
7797 * Initialize a delegate and sets a specific method, not the one
7798 * associated with addr. This is useful when sharing generic code.
7799 * In that case addr will most probably not be associated with the
7800 * correct instantiation of the method.
7801 * On failure returns FALSE and sets @error.
7803 gboolean
7804 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7806 MONO_REQ_GC_UNSAFE_MODE;
7808 mono_error_init (error);
7809 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7811 g_assert (this_obj);
7812 g_assert (addr);
7814 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7816 if (method)
7817 delegate->method = method;
7819 mono_stats.delegate_creations++;
7821 #ifndef DISABLE_REMOTING
7822 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7823 g_assert (method);
7824 method = mono_marshal_get_remoting_invoke (method);
7825 delegate->method_ptr = mono_compile_method_checked (method, error);
7826 return_val_if_nok (error, FALSE);
7827 MONO_OBJECT_SETREF (delegate, target, target);
7828 } else
7829 #endif
7831 delegate->method_ptr = addr;
7832 MONO_OBJECT_SETREF (delegate, target, target);
7835 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7836 if (callbacks.init_delegate)
7837 callbacks.init_delegate (delegate);
7838 return TRUE;
7842 * mono_delegate_ctor:
7843 * @this: pointer to an uninitialized delegate object
7844 * @target: target object
7845 * @addr: pointer to native code
7846 * @error: set on error.
7848 * This is used to initialize a delegate.
7849 * On failure returns FALSE and sets @error.
7851 gboolean
7852 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7854 MONO_REQ_GC_UNSAFE_MODE;
7856 mono_error_init (error);
7857 MonoDomain *domain = mono_domain_get ();
7858 MonoJitInfo *ji;
7859 MonoMethod *method = NULL;
7861 g_assert (addr);
7863 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7864 /* Shared code */
7865 if (!ji && domain != mono_get_root_domain ())
7866 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7867 if (ji) {
7868 method = mono_jit_info_get_method (ji);
7869 g_assert (!method->klass->generic_container);
7872 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7876 * mono_method_call_message_new:
7877 * @method: method to encapsulate
7878 * @params: parameters to the method
7879 * @invoke: optional, delegate invoke.
7880 * @cb: async callback delegate.
7881 * @state: state passed to the async callback.
7882 * @error: set on error.
7884 * Translates arguments pointers into a MonoMethodMessage.
7885 * On failure returns NULL and sets @error.
7887 MonoMethodMessage *
7888 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7889 MonoDelegate **cb, MonoObject **state, MonoError *error)
7891 MONO_REQ_GC_UNSAFE_MODE;
7893 mono_error_init (error);
7895 MonoDomain *domain = mono_domain_get ();
7896 MonoMethodSignature *sig = mono_method_signature (method);
7897 MonoMethodMessage *msg;
7898 int i, count;
7900 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7901 return_val_if_nok (error, NULL);
7903 if (invoke) {
7904 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7905 return_val_if_nok (error, NULL);
7906 mono_message_init (domain, msg, rm, NULL, error);
7907 return_val_if_nok (error, NULL);
7908 count = sig->param_count - 2;
7909 } else {
7910 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7911 return_val_if_nok (error, NULL);
7912 mono_message_init (domain, msg, rm, NULL, error);
7913 return_val_if_nok (error, NULL);
7914 count = sig->param_count;
7917 for (i = 0; i < count; i++) {
7918 gpointer vpos;
7919 MonoClass *klass;
7920 MonoObject *arg;
7922 if (sig->params [i]->byref)
7923 vpos = *((gpointer *)params [i]);
7924 else
7925 vpos = params [i];
7927 klass = mono_class_from_mono_type (sig->params [i]);
7929 if (klass->valuetype) {
7930 arg = mono_value_box_checked (domain, klass, vpos, error);
7931 return_val_if_nok (error, NULL);
7932 } else
7933 arg = *((MonoObject **)vpos);
7935 mono_array_setref (msg->args, i, arg);
7938 if (cb != NULL && state != NULL) {
7939 *cb = *((MonoDelegate **)params [i]);
7940 i++;
7941 *state = *((MonoObject **)params [i]);
7944 return msg;
7948 * mono_method_return_message_restore:
7950 * Restore results from message based processing back to arguments pointers
7952 void
7953 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7955 MONO_REQ_GC_UNSAFE_MODE;
7957 mono_error_init (error);
7959 MonoMethodSignature *sig = mono_method_signature (method);
7960 int i, j, type, size, out_len;
7962 if (out_args == NULL)
7963 return;
7964 out_len = mono_array_length (out_args);
7965 if (out_len == 0)
7966 return;
7968 for (i = 0, j = 0; i < sig->param_count; i++) {
7969 MonoType *pt = sig->params [i];
7971 if (pt->byref) {
7972 char *arg;
7973 if (j >= out_len) {
7974 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7975 return;
7978 arg = (char *)mono_array_get (out_args, gpointer, j);
7979 type = pt->type;
7981 g_assert (type != MONO_TYPE_VOID);
7983 if (MONO_TYPE_IS_REFERENCE (pt)) {
7984 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7985 } else {
7986 if (arg) {
7987 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7988 size = mono_class_value_size (klass, NULL);
7989 if (klass->has_references)
7990 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7991 else
7992 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7993 } else {
7994 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7995 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7999 j++;
8004 #ifndef DISABLE_REMOTING
8007 * mono_load_remote_field:
8008 * @this: pointer to an object
8009 * @klass: klass of the object containing @field
8010 * @field: the field to load
8011 * @res: a storage to store the result
8013 * This method is called by the runtime on attempts to load fields of
8014 * transparent proxy objects. @this points to such TP, @klass is the class of
8015 * the object containing @field. @res is a storage location which can be
8016 * used to store the result.
8018 * Returns: an address pointing to the value of field.
8020 gpointer
8021 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8023 MonoError error;
8024 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8025 mono_error_cleanup (&error);
8026 return result;
8030 * mono_load_remote_field_checked:
8031 * @this: pointer to an object
8032 * @klass: klass of the object containing @field
8033 * @field: the field to load
8034 * @res: a storage to store the result
8035 * @error: set on error
8037 * This method is called by the runtime on attempts to load fields of
8038 * transparent proxy objects. @this points to such TP, @klass is the class of
8039 * the object containing @field. @res is a storage location which can be
8040 * used to store the result.
8042 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8044 gpointer
8045 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8047 MONO_REQ_GC_UNSAFE_MODE;
8049 static MonoMethod *getter = NULL;
8051 mono_error_init (error);
8053 MonoDomain *domain = mono_domain_get ();
8054 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8055 MonoClass *field_class;
8056 MonoMethodMessage *msg;
8057 MonoArray *out_args;
8058 MonoObject *exc;
8059 char* full_name;
8061 g_assert (mono_object_is_transparent_proxy (this_obj));
8062 g_assert (res != NULL);
8064 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8065 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8066 return res;
8069 if (!getter) {
8070 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8071 if (!getter) {
8072 mono_error_set_not_supported (error, "Linked away.");
8073 return NULL;
8077 field_class = mono_class_from_mono_type (field->type);
8079 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8080 return_val_if_nok (error, NULL);
8081 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8082 return_val_if_nok (error, NULL);
8083 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8084 return_val_if_nok (error, NULL);
8085 mono_message_init (domain, msg, rm, out_args, error);
8086 return_val_if_nok (error, NULL);
8088 full_name = mono_type_get_full_name (klass);
8089 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8090 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8091 g_free (full_name);
8093 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8094 return_val_if_nok (error, NULL);
8096 if (exc) {
8097 mono_error_set_exception_instance (error, (MonoException *)exc);
8098 return NULL;
8101 if (mono_array_length (out_args) == 0)
8102 return NULL;
8104 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8106 if (field_class->valuetype) {
8107 return ((char *)*res) + sizeof (MonoObject);
8108 } else
8109 return res;
8113 * mono_load_remote_field_new:
8114 * @this:
8115 * @klass:
8116 * @field:
8118 * Missing documentation.
8120 MonoObject *
8121 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8123 MonoError error;
8125 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8126 mono_error_cleanup (&error);
8127 return result;
8131 * mono_load_remote_field_new_icall:
8132 * @this: pointer to an object
8133 * @klass: klass of the object containing @field
8134 * @field: the field to load
8136 * This method is called by the runtime on attempts to load fields of
8137 * transparent proxy objects. @this points to such TP, @klass is the class of
8138 * the object containing @field.
8140 * Returns: a freshly allocated object containing the value of the
8141 * field. On failure returns NULL and throws an exception.
8143 MonoObject *
8144 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8146 MonoError error;
8147 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8148 mono_error_set_pending_exception (&error);
8149 return result;
8153 * mono_load_remote_field_new_checked:
8154 * @this: pointer to an object
8155 * @klass: klass of the object containing @field
8156 * @field: the field to load
8157 * @error: set on error.
8159 * This method is called by the runtime on attempts to load fields of
8160 * transparent proxy objects. @this points to such TP, @klass is the class of
8161 * the object containing @field.
8163 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8165 MonoObject *
8166 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8168 MONO_REQ_GC_UNSAFE_MODE;
8170 mono_error_init (error);
8172 static MonoMethod *getter = NULL;
8173 MonoDomain *domain = mono_domain_get ();
8174 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8175 MonoClass *field_class;
8176 MonoMethodMessage *msg;
8177 MonoArray *out_args;
8178 MonoObject *exc, *res;
8179 char* full_name;
8181 g_assert (mono_object_is_transparent_proxy (this_obj));
8183 field_class = mono_class_from_mono_type (field->type);
8185 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8186 gpointer val;
8187 if (field_class->valuetype) {
8188 res = mono_object_new_checked (domain, field_class, error);
8189 return_val_if_nok (error, NULL);
8190 val = ((gchar *) res) + sizeof (MonoObject);
8191 } else {
8192 val = &res;
8194 mono_field_get_value (tp->rp->unwrapped_server, field, val);
8195 return res;
8198 if (!getter) {
8199 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8200 if (!getter) {
8201 mono_error_set_not_supported (error, "Linked away.");
8202 return NULL;
8206 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8207 return_val_if_nok (error, NULL);
8208 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8209 return_val_if_nok (error, NULL);
8211 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8212 return_val_if_nok (error, NULL);
8213 mono_message_init (domain, msg, rm, out_args, error);
8214 return_val_if_nok (error, NULL);
8216 full_name = mono_type_get_full_name (klass);
8217 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8218 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8219 g_free (full_name);
8221 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8222 return_val_if_nok (error, NULL);
8224 if (exc) {
8225 mono_error_set_exception_instance (error, (MonoException *)exc);
8226 return NULL;
8229 if (mono_array_length (out_args) == 0)
8230 res = NULL;
8231 else
8232 res = mono_array_get (out_args, MonoObject *, 0);
8234 return res;
8238 * mono_store_remote_field:
8239 * @this_obj: pointer to an object
8240 * @klass: klass of the object containing @field
8241 * @field: the field to load
8242 * @val: the value/object to store
8244 * This method is called by the runtime on attempts to store fields of
8245 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8246 * the object containing @field. @val is the new value to store in @field.
8248 void
8249 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8251 MonoError error;
8252 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8253 mono_error_cleanup (&error);
8257 * mono_store_remote_field_checked:
8258 * @this_obj: pointer to an object
8259 * @klass: klass of the object containing @field
8260 * @field: the field to load
8261 * @val: the value/object to store
8262 * @error: set on error
8264 * This method is called by the runtime on attempts to store fields of
8265 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8266 * the object containing @field. @val is the new value to store in @field.
8268 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8270 gboolean
8271 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8274 MONO_REQ_GC_UNSAFE_MODE;
8276 static MonoMethod *setter = NULL;
8278 MonoDomain *domain = mono_domain_get ();
8279 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8280 MonoClass *field_class;
8281 MonoMethodMessage *msg;
8282 MonoArray *out_args;
8283 MonoObject *exc;
8284 MonoObject *arg;
8285 char* full_name;
8287 mono_error_init (error);
8289 g_assert (mono_object_is_transparent_proxy (this_obj));
8291 field_class = mono_class_from_mono_type (field->type);
8293 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8294 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
8295 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
8296 return TRUE;
8299 if (!setter) {
8300 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8301 if (!setter) {
8302 mono_error_set_not_supported (error, "Linked away.");
8303 return FALSE;
8307 if (field_class->valuetype) {
8308 arg = mono_value_box_checked (domain, field_class, val, error);
8309 return_val_if_nok (error, FALSE);
8310 } else
8311 arg = *((MonoObject **)val);
8314 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8315 return_val_if_nok (error, FALSE);
8316 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8317 return_val_if_nok (error, FALSE);
8318 mono_message_init (domain, msg, rm, NULL, error);
8319 return_val_if_nok (error, FALSE);
8321 full_name = mono_type_get_full_name (klass);
8322 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8323 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8324 mono_array_setref (msg->args, 2, arg);
8325 g_free (full_name);
8327 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8328 return_val_if_nok (error, FALSE);
8330 if (exc) {
8331 mono_error_set_exception_instance (error, (MonoException *)exc);
8332 return FALSE;
8334 return TRUE;
8338 * mono_store_remote_field_new:
8339 * @this_obj:
8340 * @klass:
8341 * @field:
8342 * @arg:
8344 * Missing documentation
8346 void
8347 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8349 MonoError error;
8350 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8351 mono_error_cleanup (&error);
8355 * mono_store_remote_field_new_icall:
8356 * @this_obj:
8357 * @klass:
8358 * @field:
8359 * @arg:
8361 * Missing documentation
8363 void
8364 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8366 MonoError error;
8367 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8368 mono_error_set_pending_exception (&error);
8372 * mono_store_remote_field_new_checked:
8373 * @this_obj:
8374 * @klass:
8375 * @field:
8376 * @arg:
8377 * @error:
8379 * Missing documentation
8381 gboolean
8382 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8384 MONO_REQ_GC_UNSAFE_MODE;
8386 static MonoMethod *setter = NULL;
8387 MonoDomain *domain = mono_domain_get ();
8388 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8389 MonoClass *field_class;
8390 MonoMethodMessage *msg;
8391 MonoArray *out_args;
8392 MonoObject *exc;
8393 char* full_name;
8395 mono_error_init (error);
8397 g_assert (mono_object_is_transparent_proxy (this_obj));
8399 field_class = mono_class_from_mono_type (field->type);
8401 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8402 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8403 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8404 return TRUE;
8407 if (!setter) {
8408 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8409 if (!setter) {
8410 mono_error_set_not_supported (error, "Linked away.");
8411 return FALSE;
8415 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8416 return_val_if_nok (error, FALSE);
8417 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8418 return_val_if_nok (error, FALSE);
8419 mono_message_init (domain, msg, rm, NULL, error);
8420 return_val_if_nok (error, FALSE);
8422 full_name = mono_type_get_full_name (klass);
8423 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8424 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8425 mono_array_setref (msg->args, 2, arg);
8426 g_free (full_name);
8428 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8429 return_val_if_nok (error, FALSE);
8431 if (exc) {
8432 mono_error_set_exception_instance (error, (MonoException *)exc);
8433 return FALSE;
8435 return TRUE;
8437 #endif
8440 * mono_create_ftnptr:
8442 * Given a function address, create a function descriptor for it.
8443 * This is only needed on some platforms.
8445 gpointer
8446 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8448 return callbacks.create_ftnptr (domain, addr);
8452 * mono_get_addr_from_ftnptr:
8454 * Given a pointer to a function descriptor, return the function address.
8455 * This is only needed on some platforms.
8457 gpointer
8458 mono_get_addr_from_ftnptr (gpointer descr)
8460 return callbacks.get_addr_from_ftnptr (descr);
8464 * mono_string_chars:
8465 * @s: a MonoString
8467 * Returns a pointer to the UCS16 characters stored in the MonoString
8469 gunichar2 *
8470 mono_string_chars (MonoString *s)
8472 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8474 return s->chars;
8478 * mono_string_length:
8479 * @s: MonoString
8481 * Returns the lenght in characters of the string
8484 mono_string_length (MonoString *s)
8486 MONO_REQ_GC_UNSAFE_MODE;
8488 return s->length;
8492 * mono_array_length:
8493 * @array: a MonoArray*
8495 * Returns the total number of elements in the array. This works for
8496 * both vectors and multidimensional arrays.
8498 uintptr_t
8499 mono_array_length (MonoArray *array)
8501 MONO_REQ_GC_UNSAFE_MODE;
8503 return array->max_length;
8507 * mono_array_addr_with_size:
8508 * @array: a MonoArray*
8509 * @size: size of the array elements
8510 * @idx: index into the array
8512 * Use this function to obtain the address for the @idx item on the
8513 * @array containing elements of size @size.
8515 * This method performs no bounds checking or type checking.
8517 * Returns the address of the @idx element in the array.
8519 char*
8520 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8522 MONO_REQ_GC_UNSAFE_MODE;
8524 return ((char*)(array)->vector) + size * idx;
8528 MonoArray *
8529 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8531 MonoDomain *domain = mono_domain_get ();
8532 MonoArray *res;
8533 int len, i;
8535 mono_error_init (error);
8536 if (!list)
8537 return NULL;
8539 len = g_list_length (list);
8540 res = mono_array_new_checked (domain, eclass, len, error);
8541 return_val_if_nok (error, NULL);
8543 for (i = 0; list; list = list->next, i++)
8544 mono_array_set (res, gpointer, i, list->data);
8546 return res;
8549 #if NEVER_DEFINED
8551 * The following section is purely to declare prototypes and
8552 * document the API, as these C files are processed by our
8553 * tool
8557 * mono_array_set:
8558 * @array: array to alter
8559 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8560 * @index: index into the array
8561 * @value: value to set
8563 * Value Type version: This sets the @index's element of the @array
8564 * with elements of size sizeof(type) to the provided @value.
8566 * This macro does not attempt to perform type checking or bounds checking.
8568 * Use this to set value types in a `MonoArray`.
8570 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8575 * mono_array_setref:
8576 * @array: array to alter
8577 * @index: index into the array
8578 * @value: value to set
8580 * Reference Type version: This sets the @index's element of the
8581 * @array with elements of size sizeof(type) to the provided @value.
8583 * This macro does not attempt to perform type checking or bounds checking.
8585 * Use this to reference types in a `MonoArray`.
8587 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8592 * mono_array_get:
8593 * @array: array on which to operate on
8594 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8595 * @index: index into the array
8597 * Use this macro to retrieve the @index element of an @array and
8598 * extract the value assuming that the elements of the array match
8599 * the provided type value.
8601 * This method can be used with both arrays holding value types and
8602 * reference types. For reference types, the @type parameter should
8603 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8605 * This macro does not attempt to perform type checking or bounds checking.
8607 * Returns: The element at the @index position in the @array.
8609 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8612 #endif