[linker] We need to mark nested types even if the declaring type isn't marked.
[mono-project.git] / mono / metadata / object.c
blob3ab92326b1b388bfdf002a7bc1074694047887c4
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/metadata/w32event.h>
45 #include <mono/utils/strenc.h>
46 #include <mono/utils/mono-counters.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-memory-model.h>
49 #include <mono/utils/checked-build.h>
50 #include <mono/utils/mono-threads.h>
51 #include <mono/utils/mono-threads-coop.h>
52 #include "cominterop.h"
54 static void
55 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 static MonoString*
58 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 static void
61 free_main_args (void);
63 static char *
64 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 /* Class lazy loading functions */
67 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
68 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
69 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
70 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
71 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
74 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
75 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
76 static mono_mutex_t ldstr_section;
78 /**
79 * mono_runtime_object_init:
80 * @this_obj: the object to initialize
82 * This function calls the zero-argument constructor (which must
83 * exist) for the given object.
85 void
86 mono_runtime_object_init (MonoObject *this_obj)
88 MonoError error;
89 mono_runtime_object_init_checked (this_obj, &error);
90 mono_error_assert_ok (&error);
93 /**
94 * mono_runtime_object_init_checked:
95 * @this_obj: the object to initialize
96 * @error: set on error.
98 * This function calls the zero-argument constructor (which must
99 * exist) for the given object and returns TRUE on success, or FALSE
100 * on error and sets @error.
102 gboolean
103 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
105 MONO_REQ_GC_UNSAFE_MODE;
107 MonoMethod *method = NULL;
108 MonoClass *klass = this_obj->vtable->klass;
110 mono_error_init (error);
111 method = mono_class_get_method_from_name (klass, ".ctor", 0);
112 if (!method)
113 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
115 if (method->klass->valuetype)
116 this_obj = (MonoObject *)mono_object_unbox (this_obj);
118 mono_runtime_invoke_checked (method, this_obj, NULL, error);
119 return is_ok (error);
122 /* The pseudo algorithm for type initialization from the spec
123 Note it doesn't say anything about domains - only threads.
125 2. If the type is initialized you are done.
126 2.1. If the type is not yet initialized, try to take an
127 initialization lock.
128 2.2. If successful, record this thread as responsible for
129 initializing the type and proceed to step 2.3.
130 2.2.1. If not, see whether this thread or any thread
131 waiting for this thread to complete already holds the lock.
132 2.2.2. If so, return since blocking would create a deadlock. This thread
133 will now see an incompletely initialized state for the type,
134 but no deadlock will arise.
135 2.2.3 If not, block until the type is initialized then return.
136 2.3 Initialize the parent type and then all interfaces implemented
137 by this type.
138 2.4 Execute the type initialization code for this type.
139 2.5 Mark the type as initialized, release the initialization lock,
140 awaken any threads waiting for this type to be initialized,
141 and return.
145 typedef struct
147 MonoNativeThreadId initializing_tid;
148 guint32 waiting_count;
149 gboolean done;
150 MonoCoopMutex initialization_section;
151 } TypeInitializationLock;
153 /* for locking access to type_initialization_hash and blocked_thread_hash */
154 static MonoCoopMutex type_initialization_section;
156 static inline void
157 mono_type_initialization_lock (void)
159 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
160 mono_coop_mutex_lock (&type_initialization_section);
163 static inline void
164 mono_type_initialization_unlock (void)
166 mono_coop_mutex_unlock (&type_initialization_section);
169 static void
170 mono_type_init_lock (TypeInitializationLock *lock)
172 MONO_REQ_GC_NEUTRAL_MODE;
174 mono_coop_mutex_lock (&lock->initialization_section);
177 static void
178 mono_type_init_unlock (TypeInitializationLock *lock)
180 mono_coop_mutex_unlock (&lock->initialization_section);
183 /* from vtable to lock */
184 static GHashTable *type_initialization_hash;
186 /* from thread id to thread id being waited on */
187 static GHashTable *blocked_thread_hash;
189 /* Main thread */
190 static MonoThread *main_thread;
192 /* Functions supplied by the runtime */
193 static MonoRuntimeCallbacks callbacks;
196 * mono_thread_set_main:
197 * @thread: thread to set as the main thread
199 * This function can be used to instruct the runtime to treat @thread
200 * as the main thread, ie, the thread that would normally execute the Main()
201 * method. This basically means that at the end of @thread, the runtime will
202 * wait for the existing foreground threads to quit and other such details.
204 void
205 mono_thread_set_main (MonoThread *thread)
207 MONO_REQ_GC_UNSAFE_MODE;
209 static gboolean registered = FALSE;
211 if (!registered) {
212 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
213 registered = TRUE;
216 main_thread = thread;
219 MonoThread*
220 mono_thread_get_main (void)
222 MONO_REQ_GC_UNSAFE_MODE;
224 return main_thread;
227 void
228 mono_type_initialization_init (void)
230 mono_coop_mutex_init_recursive (&type_initialization_section);
231 type_initialization_hash = g_hash_table_new (NULL, NULL);
232 blocked_thread_hash = g_hash_table_new (NULL, NULL);
233 mono_os_mutex_init_recursive (&ldstr_section);
236 void
237 mono_type_initialization_cleanup (void)
239 #if 0
240 /* This is causing race conditions with
241 * mono_release_type_locks
243 mono_coop_mutex_destroy (&type_initialization_section);
244 g_hash_table_destroy (type_initialization_hash);
245 type_initialization_hash = NULL;
246 #endif
247 mono_os_mutex_destroy (&ldstr_section);
248 g_hash_table_destroy (blocked_thread_hash);
249 blocked_thread_hash = NULL;
251 free_main_args ();
255 * get_type_init_exception_for_vtable:
257 * Return the stored type initialization exception for VTABLE.
259 static MonoException*
260 get_type_init_exception_for_vtable (MonoVTable *vtable)
262 MONO_REQ_GC_UNSAFE_MODE;
264 MonoError error;
265 MonoDomain *domain = vtable->domain;
266 MonoClass *klass = vtable->klass;
267 MonoException *ex;
268 gchar *full_name;
270 if (!vtable->init_failed)
271 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
274 * If the initializing thread was rudely aborted, the exception is not stored
275 * in the hash.
277 ex = NULL;
278 mono_domain_lock (domain);
279 if (domain->type_init_exception_hash)
280 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
281 mono_domain_unlock (domain);
283 if (!ex) {
284 if (klass->name_space && *klass->name_space)
285 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
286 else
287 full_name = g_strdup (klass->name);
288 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
289 g_free (full_name);
290 return_val_if_nok (&error, NULL);
293 return ex;
297 * mono_runtime_class_init:
298 * @vtable: vtable that needs to be initialized
300 * This routine calls the class constructor for @vtable.
302 void
303 mono_runtime_class_init (MonoVTable *vtable)
305 MONO_REQ_GC_UNSAFE_MODE;
306 MonoError error;
308 mono_runtime_class_init_full (vtable, &error);
309 mono_error_assert_ok (&error);
313 * mono_runtime_class_init_full:
314 * @vtable that neeeds to be initialized
315 * @error set on error
317 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
320 gboolean
321 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
323 MONO_REQ_GC_UNSAFE_MODE;
325 MonoMethod *method = NULL;
326 MonoClass *klass;
327 gchar *full_name;
328 MonoDomain *domain = vtable->domain;
329 TypeInitializationLock *lock;
330 MonoNativeThreadId tid;
331 int do_initialization = 0;
332 MonoDomain *last_domain = NULL;
333 MonoException * pending_tae = NULL;
335 mono_error_init (error);
337 if (vtable->initialized)
338 return TRUE;
340 klass = vtable->klass;
342 if (!klass->image->checked_module_cctor) {
343 mono_image_check_for_module_cctor (klass->image);
344 if (klass->image->has_module_cctor) {
345 MonoClass *module_klass;
346 MonoVTable *module_vtable;
348 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
349 if (!module_klass) {
350 return FALSE;
353 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
354 if (!module_vtable)
355 return FALSE;
356 if (!mono_runtime_class_init_full (module_vtable, error))
357 return FALSE;
360 method = mono_class_get_cctor (klass);
361 if (!method) {
362 vtable->initialized = 1;
363 return TRUE;
366 tid = mono_native_thread_id_get ();
368 mono_type_initialization_lock ();
369 /* double check... */
370 if (vtable->initialized) {
371 mono_type_initialization_unlock ();
372 return TRUE;
374 if (vtable->init_failed) {
375 mono_type_initialization_unlock ();
377 /* The type initialization already failed once, rethrow the same exception */
378 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
379 return FALSE;
381 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
382 if (lock == NULL) {
383 /* This thread will get to do the initialization */
384 if (mono_domain_get () != domain) {
385 /* Transfer into the target domain */
386 last_domain = mono_domain_get ();
387 if (!mono_domain_set (domain, FALSE)) {
388 vtable->initialized = 1;
389 mono_type_initialization_unlock ();
390 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
391 return FALSE;
394 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
395 mono_coop_mutex_init_recursive (&lock->initialization_section);
396 lock->initializing_tid = tid;
397 lock->waiting_count = 1;
398 lock->done = FALSE;
399 /* grab the vtable lock while this thread still owns type_initialization_section */
400 /* This is why type_initialization_lock needs to enter blocking mode */
401 mono_type_init_lock (lock);
402 g_hash_table_insert (type_initialization_hash, vtable, lock);
403 do_initialization = 1;
404 } else {
405 gpointer blocked;
406 TypeInitializationLock *pending_lock;
408 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
409 mono_type_initialization_unlock ();
410 return TRUE;
412 /* see if the thread doing the initialization is already blocked on this thread */
413 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
414 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
415 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
416 if (!pending_lock->done) {
417 mono_type_initialization_unlock ();
418 return TRUE;
419 } else {
420 /* the thread doing the initialization is blocked on this thread,
421 but on a lock that has already been freed. It just hasn't got
422 time to awake */
423 break;
426 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
428 ++lock->waiting_count;
429 /* record the fact that we are waiting on the initializing thread */
430 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
432 mono_type_initialization_unlock ();
434 if (do_initialization) {
435 MonoException *exc = NULL;
437 mono_threads_begin_abort_protected_block ();
438 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
439 mono_threads_end_abort_protected_block ();
441 //exception extracted, error will be set to the right value later
442 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
443 exc = mono_error_convert_to_exception (error);
444 else
445 mono_error_cleanup (error);
447 mono_error_init (error);
449 /* If the initialization failed, mark the class as unusable. */
450 /* Avoid infinite loops */
451 if (!(!exc ||
452 (klass->image == mono_defaults.corlib &&
453 !strcmp (klass->name_space, "System") &&
454 !strcmp (klass->name, "TypeInitializationException")))) {
455 vtable->init_failed = 1;
457 if (klass->name_space && *klass->name_space)
458 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
459 else
460 full_name = g_strdup (klass->name);
462 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
463 g_free (full_name);
465 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
468 * Store the exception object so it could be thrown on subsequent
469 * accesses.
471 mono_domain_lock (domain);
472 if (!domain->type_init_exception_hash)
473 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");
474 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
475 mono_domain_unlock (domain);
478 if (last_domain)
479 mono_domain_set (last_domain, TRUE);
480 lock->done = TRUE;
481 mono_type_init_unlock (lock);
482 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
483 pending_tae = exc;
484 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
485 if (!pending_tae)
486 pending_tae = mono_thread_try_resume_interruption ();
487 } else {
488 /* this just blocks until the initializing thread is done */
489 mono_type_init_lock (lock);
490 mono_type_init_unlock (lock);
493 mono_type_initialization_lock ();
494 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
495 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
496 --lock->waiting_count;
497 if (lock->waiting_count == 0) {
498 mono_coop_mutex_destroy (&lock->initialization_section);
499 g_hash_table_remove (type_initialization_hash, vtable);
500 g_free (lock);
502 mono_memory_barrier ();
503 if (!vtable->init_failed)
504 vtable->initialized = 1;
505 mono_type_initialization_unlock ();
507 //TAE wins over TIE
508 if (pending_tae)
509 mono_error_set_exception_instance (error, pending_tae);
510 else if (vtable->init_failed) {
511 /* Either we were the initializing thread or we waited for the initialization */
512 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
513 return FALSE;
515 return TRUE;
518 static
519 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
521 MONO_REQ_GC_NEUTRAL_MODE;
523 MonoVTable *vtable = (MonoVTable*)key;
525 TypeInitializationLock *lock = (TypeInitializationLock*) value;
526 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
527 lock->done = TRUE;
529 * Have to set this since it cannot be set by the normal code in
530 * mono_runtime_class_init (). In this case, the exception object is not stored,
531 * and get_type_init_exception_for_class () needs to be aware of this.
533 vtable->init_failed = 1;
534 mono_type_init_unlock (lock);
535 --lock->waiting_count;
536 if (lock->waiting_count == 0) {
537 mono_coop_mutex_destroy (&lock->initialization_section);
538 g_free (lock);
539 return TRUE;
542 return FALSE;
545 void
546 mono_release_type_locks (MonoInternalThread *thread)
548 MONO_REQ_GC_UNSAFE_MODE;
550 mono_type_initialization_lock ();
551 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
552 mono_type_initialization_unlock ();
555 #ifndef DISABLE_REMOTING
557 static gpointer
558 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
560 g_error ("remoting not installed");
561 return NULL;
564 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
565 #endif
567 static gpointer
568 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
570 g_assert_not_reached ();
571 return NULL;
574 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
575 static MonoImtTrampolineBuilder imt_trampoline_builder;
576 static gboolean always_build_imt_trampolines;
578 #if (MONO_IMT_SIZE > 32)
579 #error "MONO_IMT_SIZE cannot be larger than 32"
580 #endif
582 void
583 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
585 memcpy (&callbacks, cbs, sizeof (*cbs));
588 MonoRuntimeCallbacks*
589 mono_get_runtime_callbacks (void)
591 return &callbacks;
594 #ifndef DISABLE_REMOTING
595 void
596 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
598 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
600 #endif
602 void
603 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
605 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
608 void
609 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
611 imt_trampoline_builder = func;
614 void
615 mono_set_always_build_imt_trampolines (gboolean value)
617 always_build_imt_trampolines = value;
621 * mono_compile_method:
622 * @method: The method to compile.
624 * This JIT-compiles the method, and returns the pointer to the native code
625 * produced.
627 gpointer
628 mono_compile_method (MonoMethod *method)
630 MonoError error;
631 gpointer result = mono_compile_method_checked (method, &error);
632 mono_error_cleanup (&error);
633 return result;
637 * mono_compile_method:
638 * @method: The method to compile.
639 * @error: set on error.
641 * This JIT-compiles the method, and returns the pointer to the native code
642 * produced. On failure returns NULL and sets @error.
644 gpointer
645 mono_compile_method_checked (MonoMethod *method, MonoError *error)
647 gpointer res;
649 MONO_REQ_GC_NEUTRAL_MODE
651 mono_error_init (error);
653 if (!callbacks.compile_method) {
654 g_error ("compile method called on uninitialized runtime");
655 return NULL;
657 res = callbacks.compile_method (method, error);
658 return res;
661 gpointer
662 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
664 gpointer res;
666 MONO_REQ_GC_NEUTRAL_MODE;
668 mono_error_init (error);
669 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
670 return res;
673 gpointer
674 mono_runtime_create_delegate_trampoline (MonoClass *klass)
676 MONO_REQ_GC_NEUTRAL_MODE
678 return arch_create_delegate_trampoline (mono_domain_get (), klass);
681 static MonoFreeMethodFunc default_mono_free_method = NULL;
684 * mono_install_free_method:
685 * @func: pointer to the MonoFreeMethodFunc used to release a method
687 * This is an internal VM routine, it is used for the engines to
688 * register a handler to release the resources associated with a method.
690 * Methods are freed when no more references to the delegate that holds
691 * them are left.
693 void
694 mono_install_free_method (MonoFreeMethodFunc func)
696 default_mono_free_method = func;
700 * mono_runtime_free_method:
701 * @domain; domain where the method is hosted
702 * @method: method to release
704 * This routine is invoked to free the resources associated with
705 * a method that has been JIT compiled. This is used to discard
706 * methods that were used only temporarily (for example, used in marshalling)
709 void
710 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
712 MONO_REQ_GC_NEUTRAL_MODE
714 if (default_mono_free_method != NULL)
715 default_mono_free_method (domain, method);
717 mono_method_clear_object (domain, method);
719 mono_free_method (method);
723 * The vtables in the root appdomain are assumed to be reachable by other
724 * roots, and we don't use typed allocation in the other domains.
727 /* The sync block is no longer a GC pointer */
728 #define GC_HEADER_BITMAP (0)
730 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
732 static gsize*
733 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
735 MONO_REQ_GC_NEUTRAL_MODE;
737 MonoClassField *field;
738 MonoClass *p;
739 guint32 pos;
740 int max_size;
742 if (static_fields)
743 max_size = mono_class_data_size (klass) / sizeof (gpointer);
744 else
745 max_size = klass->instance_size / sizeof (gpointer);
746 if (max_size > size) {
747 g_assert (offset <= 0);
748 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
749 size = max_size;
752 #ifdef HAVE_SGEN_GC
753 /*An Ephemeron cannot be marked by sgen*/
754 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
755 *max_set = 0;
756 memset (bitmap, 0, size / 8);
757 return bitmap;
759 #endif
761 for (p = klass; p != NULL; p = p->parent) {
762 gpointer iter = NULL;
763 while ((field = mono_class_get_fields (p, &iter))) {
764 MonoType *type;
766 if (static_fields) {
767 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
768 continue;
769 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
770 continue;
771 } else {
772 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
773 continue;
775 /* FIXME: should not happen, flag as type load error */
776 if (field->type->byref)
777 break;
779 if (static_fields && field->offset == -1)
780 /* special static */
781 continue;
783 pos = field->offset / sizeof (gpointer);
784 pos += offset;
786 type = mono_type_get_underlying_type (field->type);
787 switch (type->type) {
788 case MONO_TYPE_I:
789 case MONO_TYPE_PTR:
790 case MONO_TYPE_FNPTR:
791 break;
792 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
793 case MONO_TYPE_U:
794 #ifdef HAVE_SGEN_GC
795 break;
796 #else
797 if (klass->image != mono_defaults.corlib)
798 break;
799 #endif
800 case MONO_TYPE_STRING:
801 case MONO_TYPE_SZARRAY:
802 case MONO_TYPE_CLASS:
803 case MONO_TYPE_OBJECT:
804 case MONO_TYPE_ARRAY:
805 g_assert ((field->offset % sizeof(gpointer)) == 0);
807 g_assert (pos < size || pos <= max_size);
808 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
809 *max_set = MAX (*max_set, pos);
810 break;
811 case MONO_TYPE_GENERICINST:
812 if (!mono_type_generic_inst_is_valuetype (type)) {
813 g_assert ((field->offset % sizeof(gpointer)) == 0);
815 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
816 *max_set = MAX (*max_set, pos);
817 break;
818 } else {
819 /* fall through */
821 case MONO_TYPE_VALUETYPE: {
822 MonoClass *fclass = mono_class_from_mono_type (field->type);
823 if (fclass->has_references) {
824 /* remove the object header */
825 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
827 break;
829 case MONO_TYPE_I1:
830 case MONO_TYPE_U1:
831 case MONO_TYPE_I2:
832 case MONO_TYPE_U2:
833 case MONO_TYPE_I4:
834 case MONO_TYPE_U4:
835 case MONO_TYPE_I8:
836 case MONO_TYPE_U8:
837 case MONO_TYPE_R4:
838 case MONO_TYPE_R8:
839 case MONO_TYPE_BOOLEAN:
840 case MONO_TYPE_CHAR:
841 break;
842 default:
843 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
844 break;
847 if (static_fields)
848 break;
850 return bitmap;
854 * mono_class_compute_bitmap:
856 * Mono internal function to compute a bitmap of reference fields in a class.
858 gsize*
859 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
861 MONO_REQ_GC_NEUTRAL_MODE;
863 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
866 #if 0
868 * similar to the above, but sets the bits in the bitmap for any non-ref field
869 * and ignores static fields
871 static gsize*
872 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
874 MonoClassField *field;
875 MonoClass *p;
876 guint32 pos, pos2;
877 int max_size;
879 max_size = class->instance_size / sizeof (gpointer);
880 if (max_size >= size) {
881 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
884 for (p = class; p != NULL; p = p->parent) {
885 gpointer iter = NULL;
886 while ((field = mono_class_get_fields (p, &iter))) {
887 MonoType *type;
889 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
890 continue;
891 /* FIXME: should not happen, flag as type load error */
892 if (field->type->byref)
893 break;
895 pos = field->offset / sizeof (gpointer);
896 pos += offset;
898 type = mono_type_get_underlying_type (field->type);
899 switch (type->type) {
900 #if SIZEOF_VOID_P == 8
901 case MONO_TYPE_I:
902 case MONO_TYPE_U:
903 case MONO_TYPE_PTR:
904 case MONO_TYPE_FNPTR:
905 #endif
906 case MONO_TYPE_I8:
907 case MONO_TYPE_U8:
908 case MONO_TYPE_R8:
909 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
913 /* fall through */
914 #if SIZEOF_VOID_P == 4
915 case MONO_TYPE_I:
916 case MONO_TYPE_U:
917 case MONO_TYPE_PTR:
918 case MONO_TYPE_FNPTR:
919 #endif
920 case MONO_TYPE_I4:
921 case MONO_TYPE_U4:
922 case MONO_TYPE_R4:
923 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
924 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
925 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
927 /* fall through */
928 case MONO_TYPE_CHAR:
929 case MONO_TYPE_I2:
930 case MONO_TYPE_U2:
931 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
932 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
933 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
935 /* fall through */
936 case MONO_TYPE_BOOLEAN:
937 case MONO_TYPE_I1:
938 case MONO_TYPE_U1:
939 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
940 break;
941 case MONO_TYPE_STRING:
942 case MONO_TYPE_SZARRAY:
943 case MONO_TYPE_CLASS:
944 case MONO_TYPE_OBJECT:
945 case MONO_TYPE_ARRAY:
946 break;
947 case MONO_TYPE_GENERICINST:
948 if (!mono_type_generic_inst_is_valuetype (type)) {
949 break;
950 } else {
951 /* fall through */
953 case MONO_TYPE_VALUETYPE: {
954 MonoClass *fclass = mono_class_from_mono_type (field->type);
955 /* remove the object header */
956 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
957 break;
959 default:
960 g_assert_not_reached ();
961 break;
965 return bitmap;
969 * mono_class_insecure_overlapping:
970 * check if a class with explicit layout has references and non-references
971 * fields overlapping.
973 * Returns: TRUE if it is insecure to load the type.
975 gboolean
976 mono_class_insecure_overlapping (MonoClass *klass)
978 int max_set = 0;
979 gsize *bitmap;
980 gsize default_bitmap [4] = {0};
981 gsize *nrbitmap;
982 gsize default_nrbitmap [4] = {0};
983 int i, insecure = FALSE;
984 return FALSE;
986 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
987 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
989 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
990 int idx = i % (sizeof (bitmap [0]) * 8);
991 if (bitmap [idx] & nrbitmap [idx]) {
992 insecure = TRUE;
993 break;
996 if (bitmap != default_bitmap)
997 g_free (bitmap);
998 if (nrbitmap != default_nrbitmap)
999 g_free (nrbitmap);
1000 if (insecure) {
1001 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1002 return FALSE;
1004 return insecure;
1006 #endif
1008 MonoString*
1009 ves_icall_string_alloc (int length)
1011 MonoError error;
1012 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1013 mono_error_set_pending_exception (&error);
1015 return str;
1018 void
1019 mono_class_compute_gc_descriptor (MonoClass *klass)
1021 MONO_REQ_GC_NEUTRAL_MODE;
1023 int max_set = 0;
1024 gsize *bitmap;
1025 gsize default_bitmap [4] = {0};
1026 static gboolean gcj_inited = FALSE;
1028 if (!gcj_inited) {
1029 mono_loader_lock ();
1031 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1032 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1034 gcj_inited = TRUE;
1035 mono_loader_unlock ();
1038 if (!klass->inited)
1039 mono_class_init (klass);
1041 if (klass->gc_descr_inited)
1042 return;
1044 klass->gc_descr_inited = TRUE;
1045 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1047 bitmap = default_bitmap;
1048 if (klass == mono_defaults.string_class) {
1049 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1050 } else if (klass->rank) {
1051 mono_class_compute_gc_descriptor (klass->element_class);
1052 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1053 gsize abm = 1;
1054 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1055 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1056 class->name_space, class->name);*/
1057 } else {
1058 /* remove the object header */
1059 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1060 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));
1061 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1062 class->name_space, class->name);*/
1063 if (bitmap != default_bitmap)
1064 g_free (bitmap);
1066 } else {
1067 /*static int count = 0;
1068 if (count++ > 58)
1069 return;*/
1070 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1071 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1073 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1074 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1076 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1077 if (bitmap != default_bitmap)
1078 g_free (bitmap);
1083 * field_is_special_static:
1084 * @fklass: The MonoClass to look up.
1085 * @field: The MonoClassField describing the field.
1087 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1088 * SPECIAL_STATIC_NONE otherwise.
1090 static gint32
1091 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1093 MONO_REQ_GC_NEUTRAL_MODE;
1095 MonoError error;
1096 MonoCustomAttrInfo *ainfo;
1097 int i;
1098 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1099 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1100 if (!ainfo)
1101 return FALSE;
1102 for (i = 0; i < ainfo->num_attrs; ++i) {
1103 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1104 if (klass->image == mono_defaults.corlib) {
1105 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1106 mono_custom_attrs_free (ainfo);
1107 return SPECIAL_STATIC_THREAD;
1109 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1110 mono_custom_attrs_free (ainfo);
1111 return SPECIAL_STATIC_CONTEXT;
1115 mono_custom_attrs_free (ainfo);
1116 return SPECIAL_STATIC_NONE;
1119 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1120 #define mix(a,b,c) { \
1121 a -= c; a ^= rot(c, 4); c += b; \
1122 b -= a; b ^= rot(a, 6); a += c; \
1123 c -= b; c ^= rot(b, 8); b += a; \
1124 a -= c; a ^= rot(c,16); c += b; \
1125 b -= a; b ^= rot(a,19); a += c; \
1126 c -= b; c ^= rot(b, 4); b += a; \
1128 #define final(a,b,c) { \
1129 c ^= b; c -= rot(b,14); \
1130 a ^= c; a -= rot(c,11); \
1131 b ^= a; b -= rot(a,25); \
1132 c ^= b; c -= rot(b,16); \
1133 a ^= c; a -= rot(c,4); \
1134 b ^= a; b -= rot(a,14); \
1135 c ^= b; c -= rot(b,24); \
1139 * mono_method_get_imt_slot:
1141 * The IMT slot is embedded into AOTed code, so this must return the same value
1142 * for the same method across all executions. This means:
1143 * - pointers shouldn't be used as hash values.
1144 * - mono_metadata_str_hash () should be used for hashing strings.
1146 guint32
1147 mono_method_get_imt_slot (MonoMethod *method)
1149 MONO_REQ_GC_NEUTRAL_MODE;
1151 MonoMethodSignature *sig;
1152 int hashes_count;
1153 guint32 *hashes_start, *hashes;
1154 guint32 a, b, c;
1155 int i;
1157 /* This can be used to stress tests the collision code */
1158 //return 0;
1161 * We do this to simplify generic sharing. It will hurt
1162 * performance in cases where a class implements two different
1163 * instantiations of the same generic interface.
1164 * The code in build_imt_slots () depends on this.
1166 if (method->is_inflated)
1167 method = ((MonoMethodInflated*)method)->declaring;
1169 sig = mono_method_signature (method);
1170 hashes_count = sig->param_count + 4;
1171 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1172 hashes = hashes_start;
1174 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1175 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1176 method->klass->name_space, method->klass->name, method->name);
1179 /* Initialize hashes */
1180 hashes [0] = mono_metadata_str_hash (method->klass->name);
1181 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1182 hashes [2] = mono_metadata_str_hash (method->name);
1183 hashes [3] = mono_metadata_type_hash (sig->ret);
1184 for (i = 0; i < sig->param_count; i++) {
1185 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1188 /* Setup internal state */
1189 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1191 /* Handle most of the hashes */
1192 while (hashes_count > 3) {
1193 a += hashes [0];
1194 b += hashes [1];
1195 c += hashes [2];
1196 mix (a,b,c);
1197 hashes_count -= 3;
1198 hashes += 3;
1201 /* Handle the last 3 hashes (all the case statements fall through) */
1202 switch (hashes_count) {
1203 case 3 : c += hashes [2];
1204 case 2 : b += hashes [1];
1205 case 1 : a += hashes [0];
1206 final (a,b,c);
1207 case 0: /* nothing left to add */
1208 break;
1211 g_free (hashes_start);
1212 /* Report the result */
1213 return c % MONO_IMT_SIZE;
1215 #undef rot
1216 #undef mix
1217 #undef final
1219 #define DEBUG_IMT 0
1221 static void
1222 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1223 MONO_REQ_GC_NEUTRAL_MODE;
1225 guint32 imt_slot = mono_method_get_imt_slot (method);
1226 MonoImtBuilderEntry *entry;
1228 if (slot_num >= 0 && imt_slot != slot_num) {
1229 /* we build just a single imt slot and this is not it */
1230 return;
1233 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1234 entry->key = method;
1235 entry->value.vtable_slot = vtable_slot;
1236 entry->next = imt_builder [imt_slot];
1237 if (imt_builder [imt_slot] != NULL) {
1238 entry->children = imt_builder [imt_slot]->children + 1;
1239 if (entry->children == 1) {
1240 mono_stats.imt_slots_with_collisions++;
1241 *imt_collisions_bitmap |= (1 << imt_slot);
1243 } else {
1244 entry->children = 0;
1245 mono_stats.imt_used_slots++;
1247 imt_builder [imt_slot] = entry;
1248 #if DEBUG_IMT
1250 char *method_name = mono_method_full_name (method, TRUE);
1251 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1252 method, method_name, imt_slot, vtable_slot, entry->children);
1253 g_free (method_name);
1255 #endif
1258 #if DEBUG_IMT
1259 static void
1260 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1261 if (e != NULL) {
1262 MonoMethod *method = e->key;
1263 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1264 message,
1265 num,
1266 method,
1267 method->klass->name_space,
1268 method->klass->name,
1269 method->name);
1270 } else {
1271 printf (" * %s: NULL\n", message);
1274 #endif
1276 static int
1277 compare_imt_builder_entries (const void *p1, const void *p2) {
1278 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1279 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1281 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1284 static int
1285 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1287 MONO_REQ_GC_NEUTRAL_MODE;
1289 int count = end - start;
1290 int chunk_start = out_array->len;
1291 if (count < 4) {
1292 int i;
1293 for (i = start; i < end; ++i) {
1294 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1295 item->key = sorted_array [i]->key;
1296 item->value = sorted_array [i]->value;
1297 item->has_target_code = sorted_array [i]->has_target_code;
1298 item->is_equals = TRUE;
1299 if (i < end - 1)
1300 item->check_target_idx = out_array->len + 1;
1301 else
1302 item->check_target_idx = 0;
1303 g_ptr_array_add (out_array, item);
1305 } else {
1306 int middle = start + count / 2;
1307 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1309 item->key = sorted_array [middle]->key;
1310 item->is_equals = FALSE;
1311 g_ptr_array_add (out_array, item);
1312 imt_emit_ir (sorted_array, start, middle, out_array);
1313 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1315 return chunk_start;
1318 static GPtrArray*
1319 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1320 MONO_REQ_GC_NEUTRAL_MODE;
1322 int number_of_entries = entries->children + 1;
1323 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1324 GPtrArray *result = g_ptr_array_new ();
1325 MonoImtBuilderEntry *current_entry;
1326 int i;
1328 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1329 sorted_array [i] = current_entry;
1331 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1333 /*for (i = 0; i < number_of_entries; i++) {
1334 print_imt_entry (" sorted array:", sorted_array [i], i);
1337 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1339 g_free (sorted_array);
1340 return result;
1343 static gpointer
1344 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1346 MONO_REQ_GC_NEUTRAL_MODE;
1348 if (imt_builder_entry != NULL) {
1349 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1350 /* No collision, return the vtable slot contents */
1351 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1352 } else {
1353 /* Collision, build the trampoline */
1354 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1355 gpointer result;
1356 int i;
1357 result = imt_trampoline_builder (vtable, domain,
1358 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1359 for (i = 0; i < imt_ir->len; ++i)
1360 g_free (g_ptr_array_index (imt_ir, i));
1361 g_ptr_array_free (imt_ir, TRUE);
1362 return result;
1364 } else {
1365 if (fail_tramp)
1366 return fail_tramp;
1367 else
1368 /* Empty slot */
1369 return NULL;
1373 static MonoImtBuilderEntry*
1374 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1377 * LOCKING: requires the loader and domain locks.
1380 static void
1381 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1383 MONO_REQ_GC_NEUTRAL_MODE;
1385 int i;
1386 GSList *list_item;
1387 guint32 imt_collisions_bitmap = 0;
1388 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1389 int method_count = 0;
1390 gboolean record_method_count_for_max_collisions = FALSE;
1391 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1393 #if DEBUG_IMT
1394 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1395 #endif
1396 for (i = 0; i < klass->interface_offsets_count; ++i) {
1397 MonoClass *iface = klass->interfaces_packed [i];
1398 int interface_offset = klass->interface_offsets_packed [i];
1399 int method_slot_in_interface, vt_slot;
1401 if (mono_class_has_variant_generic_params (iface))
1402 has_variant_iface = TRUE;
1404 mono_class_setup_methods (iface);
1405 vt_slot = interface_offset;
1406 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1407 MonoMethod *method;
1409 if (slot_num >= 0 && iface->is_inflated) {
1411 * The imt slot of the method is the same as for its declaring method,
1412 * see the comment in mono_method_get_imt_slot (), so we can
1413 * avoid inflating methods which will be discarded by
1414 * add_imt_builder_entry anyway.
1416 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1417 if (mono_method_get_imt_slot (method) != slot_num) {
1418 vt_slot ++;
1419 continue;
1422 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1423 if (method->is_generic) {
1424 has_generic_virtual = TRUE;
1425 vt_slot ++;
1426 continue;
1429 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1430 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1431 vt_slot ++;
1435 if (extra_interfaces) {
1436 int interface_offset = klass->vtable_size;
1438 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1439 MonoClass* iface = (MonoClass *)list_item->data;
1440 int method_slot_in_interface;
1441 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1442 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1444 if (method->is_generic)
1445 has_generic_virtual = TRUE;
1446 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1448 interface_offset += iface->method.count;
1451 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1452 /* overwrite the imt slot only if we're building all the entries or if
1453 * we're building this specific one
1455 if (slot_num < 0 || i == slot_num) {
1456 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1458 if (entries) {
1459 if (imt_builder [i]) {
1460 MonoImtBuilderEntry *entry;
1462 /* Link entries with imt_builder [i] */
1463 for (entry = entries; entry->next; entry = entry->next) {
1464 #if DEBUG_IMT
1465 MonoMethod *method = (MonoMethod*)entry->key;
1466 char *method_name = mono_method_full_name (method, TRUE);
1467 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1468 g_free (method_name);
1469 #endif
1471 entry->next = imt_builder [i];
1472 entries->children += imt_builder [i]->children + 1;
1474 imt_builder [i] = entries;
1477 if (has_generic_virtual || has_variant_iface) {
1479 * There might be collisions later when the the trampoline is expanded.
1481 imt_collisions_bitmap |= (1 << i);
1484 * The IMT trampoline might be called with an instance of one of the
1485 * generic virtual methods, so has to fallback to the IMT trampoline.
1487 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1488 } else {
1489 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1491 #if DEBUG_IMT
1492 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1493 #endif
1496 if (imt_builder [i] != NULL) {
1497 int methods_in_slot = imt_builder [i]->children + 1;
1498 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1499 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1500 record_method_count_for_max_collisions = TRUE;
1502 method_count += methods_in_slot;
1506 mono_stats.imt_number_of_methods += method_count;
1507 if (record_method_count_for_max_collisions) {
1508 mono_stats.imt_method_count_when_max_collisions = method_count;
1511 for (i = 0; i < MONO_IMT_SIZE; i++) {
1512 MonoImtBuilderEntry* entry = imt_builder [i];
1513 while (entry != NULL) {
1514 MonoImtBuilderEntry* next = entry->next;
1515 g_free (entry);
1516 entry = next;
1519 g_free (imt_builder);
1520 /* we OR the bitmap since we may build just a single imt slot at a time */
1521 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1524 static void
1525 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1526 MONO_REQ_GC_NEUTRAL_MODE;
1528 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1532 * mono_vtable_build_imt_slot:
1533 * @vtable: virtual object table struct
1534 * @imt_slot: slot in the IMT table
1536 * Fill the given @imt_slot in the IMT table of @vtable with
1537 * a trampoline or a trampoline for the case of collisions.
1538 * This is part of the internal mono API.
1540 * LOCKING: Take the domain lock.
1542 void
1543 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1545 MONO_REQ_GC_NEUTRAL_MODE;
1547 gpointer *imt = (gpointer*)vtable;
1548 imt -= MONO_IMT_SIZE;
1549 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1551 /* no support for extra interfaces: the proxy objects will need
1552 * to build the complete IMT
1553 * Update and heck needs to ahppen inside the proper domain lock, as all
1554 * the changes made to a MonoVTable.
1556 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1557 mono_domain_lock (vtable->domain);
1558 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1559 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1560 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1561 mono_domain_unlock (vtable->domain);
1562 mono_loader_unlock ();
1565 #define THUNK_THRESHOLD 10
1568 * mono_method_alloc_generic_virtual_trampoline:
1569 * @domain: a domain
1570 * @size: size in bytes
1572 * Allocs size bytes to be used for the code of a generic virtual
1573 * trampoline. It's either allocated from the domain's code manager or
1574 * reused from a previously invalidated piece.
1576 * LOCKING: The domain lock must be held.
1578 gpointer
1579 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1581 MONO_REQ_GC_NEUTRAL_MODE;
1583 static gboolean inited = FALSE;
1584 static int generic_virtual_trampolines_size = 0;
1586 if (!inited) {
1587 mono_counters_register ("Generic virtual trampoline bytes",
1588 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1589 inited = TRUE;
1591 generic_virtual_trampolines_size += size;
1593 return mono_domain_code_reserve (domain, size);
1596 typedef struct _GenericVirtualCase {
1597 MonoMethod *method;
1598 gpointer code;
1599 int count;
1600 struct _GenericVirtualCase *next;
1601 } GenericVirtualCase;
1604 * get_generic_virtual_entries:
1606 * Return IMT entries for the generic virtual method instances and
1607 * variant interface methods for vtable slot
1608 * VTABLE_SLOT.
1610 static MonoImtBuilderEntry*
1611 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1613 MONO_REQ_GC_NEUTRAL_MODE;
1615 GenericVirtualCase *list;
1616 MonoImtBuilderEntry *entries;
1618 mono_domain_lock (domain);
1619 if (!domain->generic_virtual_cases)
1620 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1622 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1624 entries = NULL;
1625 for (; list; list = list->next) {
1626 MonoImtBuilderEntry *entry;
1628 if (list->count < THUNK_THRESHOLD)
1629 continue;
1631 entry = g_new0 (MonoImtBuilderEntry, 1);
1632 entry->key = list->method;
1633 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1634 entry->has_target_code = 1;
1635 if (entries)
1636 entry->children = entries->children + 1;
1637 entry->next = entries;
1638 entries = entry;
1641 mono_domain_unlock (domain);
1643 /* FIXME: Leaking memory ? */
1644 return entries;
1648 * mono_method_add_generic_virtual_invocation:
1649 * @domain: a domain
1650 * @vtable_slot: pointer to the vtable slot
1651 * @method: the inflated generic virtual method
1652 * @code: the method's code
1654 * Registers a call via unmanaged code to a generic virtual method
1655 * instantiation or variant interface method. If the number of calls reaches a threshold
1656 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1657 * virtual method trampoline.
1659 void
1660 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1661 gpointer *vtable_slot,
1662 MonoMethod *method, gpointer code)
1664 MONO_REQ_GC_NEUTRAL_MODE;
1666 static gboolean inited = FALSE;
1667 static int num_added = 0;
1668 static int num_freed = 0;
1670 GenericVirtualCase *gvc, *list;
1671 MonoImtBuilderEntry *entries;
1672 int i;
1673 GPtrArray *sorted;
1675 mono_domain_lock (domain);
1676 if (!domain->generic_virtual_cases)
1677 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1679 if (!inited) {
1680 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1681 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1682 inited = TRUE;
1685 /* Check whether the case was already added */
1686 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1687 gvc = list;
1688 while (gvc) {
1689 if (gvc->method == method)
1690 break;
1691 gvc = gvc->next;
1694 /* If not found, make a new one */
1695 if (!gvc) {
1696 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1697 gvc->method = method;
1698 gvc->code = code;
1699 gvc->count = 0;
1700 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1702 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1704 num_added++;
1707 if (++gvc->count == THUNK_THRESHOLD) {
1708 gpointer *old_thunk = (void **)*vtable_slot;
1709 gpointer vtable_trampoline = NULL;
1710 gpointer imt_trampoline = NULL;
1712 if ((gpointer)vtable_slot < (gpointer)vtable) {
1713 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1714 int imt_slot = MONO_IMT_SIZE + displacement;
1716 /* Force the rebuild of the trampoline at the next call */
1717 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1718 *vtable_slot = imt_trampoline;
1719 } else {
1720 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1722 entries = get_generic_virtual_entries (domain, vtable_slot);
1724 sorted = imt_sort_slot_entries (entries);
1726 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1727 vtable_trampoline);
1729 while (entries) {
1730 MonoImtBuilderEntry *next = entries->next;
1731 g_free (entries);
1732 entries = next;
1735 for (i = 0; i < sorted->len; ++i)
1736 g_free (g_ptr_array_index (sorted, i));
1737 g_ptr_array_free (sorted, TRUE);
1739 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1740 num_freed ++;
1744 mono_domain_unlock (domain);
1747 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1750 * mono_class_vtable:
1751 * @domain: the application domain
1752 * @class: the class to initialize
1754 * VTables are domain specific because we create domain specific code, and
1755 * they contain the domain specific static class data.
1756 * On failure, NULL is returned, and class->exception_type is set.
1758 MonoVTable *
1759 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1761 MonoError error;
1762 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1763 mono_error_cleanup (&error);
1764 return vtable;
1768 * mono_class_vtable_full:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1771 * @error set on failure.
1773 * VTables are domain specific because we create domain specific code, and
1774 * they contain the domain specific static class data.
1776 MonoVTable *
1777 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1779 MONO_REQ_GC_UNSAFE_MODE;
1781 MonoClassRuntimeInfo *runtime_info;
1783 mono_error_init (error);
1785 g_assert (klass);
1787 if (mono_class_has_failure (klass)) {
1788 mono_error_set_for_class_failure (error, klass);
1789 return NULL;
1792 /* this check can be inlined in jitted code, too */
1793 runtime_info = klass->runtime_info;
1794 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1795 return runtime_info->domain_vtables [domain->domain_id];
1796 return mono_class_create_runtime_vtable (domain, klass, error);
1800 * mono_class_try_get_vtable:
1801 * @domain: the application domain
1802 * @class: the class to initialize
1804 * This function tries to get the associated vtable from @class if
1805 * it was already created.
1807 MonoVTable *
1808 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1810 MONO_REQ_GC_NEUTRAL_MODE;
1812 MonoClassRuntimeInfo *runtime_info;
1814 g_assert (klass);
1816 runtime_info = klass->runtime_info;
1817 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1818 return runtime_info->domain_vtables [domain->domain_id];
1819 return NULL;
1822 static gpointer*
1823 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1825 MONO_REQ_GC_NEUTRAL_MODE;
1827 size_t alloc_offset;
1830 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1831 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1832 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1834 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1835 g_assert ((imt_table_bytes & 7) == 4);
1836 vtable_size += 4;
1837 alloc_offset = 4;
1838 } else {
1839 alloc_offset = 0;
1842 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1845 static MonoVTable *
1846 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1848 MONO_REQ_GC_UNSAFE_MODE;
1850 MonoVTable *vt;
1851 MonoClassRuntimeInfo *runtime_info, *old_info;
1852 MonoClassField *field;
1853 char *t;
1854 int i, vtable_slots;
1855 size_t imt_table_bytes;
1856 int gc_bits;
1857 guint32 vtable_size, class_size;
1858 gpointer iter;
1859 gpointer *interface_offsets;
1861 mono_error_init (error);
1863 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1864 mono_domain_lock (domain);
1865 runtime_info = klass->runtime_info;
1866 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1867 mono_domain_unlock (domain);
1868 mono_loader_unlock ();
1869 return runtime_info->domain_vtables [domain->domain_id];
1871 if (!klass->inited || mono_class_has_failure (klass)) {
1872 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1873 mono_domain_unlock (domain);
1874 mono_loader_unlock ();
1875 mono_error_set_for_class_failure (error, klass);
1876 return NULL;
1880 /* Array types require that their element type be valid*/
1881 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1882 MonoClass *element_class = klass->element_class;
1883 if (!element_class->inited)
1884 mono_class_init (element_class);
1886 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1887 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1888 mono_class_setup_vtable (element_class);
1890 if (mono_class_has_failure (element_class)) {
1891 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1892 if (!mono_class_has_failure (klass))
1893 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1894 mono_domain_unlock (domain);
1895 mono_loader_unlock ();
1896 mono_error_set_for_class_failure (error, klass);
1897 return NULL;
1902 * For some classes, mono_class_init () already computed klass->vtable_size, and
1903 * that is all that is needed because of the vtable trampolines.
1905 if (!klass->vtable_size)
1906 mono_class_setup_vtable (klass);
1908 if (klass->generic_class && !klass->vtable)
1909 mono_class_check_vtable_constraints (klass, NULL);
1911 /* Initialize klass->has_finalize */
1912 mono_class_has_finalizer (klass);
1914 if (mono_class_has_failure (klass)) {
1915 mono_domain_unlock (domain);
1916 mono_loader_unlock ();
1917 mono_error_set_for_class_failure (error, klass);
1918 return NULL;
1921 vtable_slots = klass->vtable_size;
1922 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1923 class_size = mono_class_data_size (klass);
1924 if (class_size)
1925 vtable_slots++;
1927 if (klass->interface_offsets_count) {
1928 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1929 mono_stats.imt_number_of_tables++;
1930 mono_stats.imt_tables_size += imt_table_bytes;
1931 } else {
1932 imt_table_bytes = 0;
1935 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1937 mono_stats.used_class_count++;
1938 mono_stats.class_vtable_size += vtable_size;
1940 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1941 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1942 g_assert (!((gsize)vt & 7));
1944 vt->klass = klass;
1945 vt->rank = klass->rank;
1946 vt->domain = domain;
1948 mono_class_compute_gc_descriptor (klass);
1950 * We can't use typed allocation in the non-root domains, since the
1951 * collector needs the GC descriptor stored in the vtable even after
1952 * the mempool containing the vtable is destroyed when the domain is
1953 * unloaded. An alternative might be to allocate vtables in the GC
1954 * heap, but this does not seem to work (it leads to crashes inside
1955 * libgc). If that approach is tried, two gc descriptors need to be
1956 * allocated for each class: one for the root domain, and one for all
1957 * other domains. The second descriptor should contain a bit for the
1958 * vtable field in MonoObject, since we can no longer assume the
1959 * vtable is reachable by other roots after the appdomain is unloaded.
1961 #ifdef HAVE_BOEHM_GC
1962 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1963 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1964 else
1965 #endif
1966 vt->gc_descr = klass->gc_descr;
1968 gc_bits = mono_gc_get_vtable_bits (klass);
1969 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1971 vt->gc_bits = gc_bits;
1973 if (class_size) {
1974 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1975 if (klass->has_static_refs) {
1976 MonoGCDescriptor statics_gc_descr;
1977 int max_set = 0;
1978 gsize default_bitmap [4] = {0};
1979 gsize *bitmap;
1981 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1982 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1983 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1984 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1985 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1986 if (bitmap != default_bitmap)
1987 g_free (bitmap);
1988 } else {
1989 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1991 vt->has_static_fields = TRUE;
1992 mono_stats.class_static_data_size += class_size;
1995 iter = NULL;
1996 while ((field = mono_class_get_fields (klass, &iter))) {
1997 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1998 continue;
1999 if (mono_field_is_deleted (field))
2000 continue;
2001 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2002 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2003 if (special_static != SPECIAL_STATIC_NONE) {
2004 guint32 size, offset;
2005 gint32 align;
2006 gsize default_bitmap [4] = {0};
2007 gsize *bitmap;
2008 int max_set = 0;
2009 int numbits;
2010 MonoClass *fclass;
2011 if (mono_type_is_reference (field->type)) {
2012 default_bitmap [0] = 1;
2013 numbits = 1;
2014 bitmap = default_bitmap;
2015 } else if (mono_type_is_struct (field->type)) {
2016 fclass = mono_class_from_mono_type (field->type);
2017 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2018 numbits = max_set + 1;
2019 } else {
2020 default_bitmap [0] = 0;
2021 numbits = 0;
2022 bitmap = default_bitmap;
2024 size = mono_type_size (field->type, &align);
2025 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2026 if (!domain->special_static_fields)
2027 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2028 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2029 if (bitmap != default_bitmap)
2030 g_free (bitmap);
2032 * This marks the field as special static to speed up the
2033 * checks in mono_field_static_get/set_value ().
2035 field->offset = -1;
2036 continue;
2039 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2040 MonoClass *fklass = mono_class_from_mono_type (field->type);
2041 const char *data = mono_field_get_data (field);
2043 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2044 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2045 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2046 if (!data)
2047 continue;
2048 if (fklass->valuetype) {
2049 memcpy (t, data, mono_class_value_size (fklass, NULL));
2050 } else {
2051 /* it's a pointer type: add check */
2052 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2053 *t = *(char *)data;
2055 continue;
2059 vt->max_interface_id = klass->max_interface_id;
2060 vt->interface_bitmap = klass->interface_bitmap;
2062 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2063 // class->name, klass->interface_offsets_count);
2065 /* Initialize vtable */
2066 if (callbacks.get_vtable_trampoline) {
2067 // This also covers the AOT case
2068 for (i = 0; i < klass->vtable_size; ++i) {
2069 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2071 } else {
2072 mono_class_setup_vtable (klass);
2074 for (i = 0; i < klass->vtable_size; ++i) {
2075 MonoMethod *cm;
2077 cm = klass->vtable [i];
2078 if (cm) {
2079 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2080 if (!is_ok (error)) {
2081 mono_domain_unlock (domain);
2082 mono_loader_unlock ();
2083 return NULL;
2089 if (imt_table_bytes) {
2090 /* Now that the vtable is full, we can actually fill up the IMT */
2091 for (i = 0; i < MONO_IMT_SIZE; ++i)
2092 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2096 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2097 * re-acquire them and check if another thread has created the vtable in the meantime.
2099 /* Special case System.MonoType to avoid infinite recursion */
2100 if (klass != mono_defaults.runtimetype_class) {
2101 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2102 if (!is_ok (error)) {
2103 mono_domain_unlock (domain);
2104 mono_loader_unlock ();
2105 return NULL;
2108 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2109 /* This is unregistered in
2110 unregister_vtable_reflection_type() in
2111 domain.c. */
2112 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2115 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2117 /* class_vtable_array keeps an array of created vtables
2119 g_ptr_array_add (domain->class_vtable_array, vt);
2120 /* klass->runtime_info is protected by the loader lock, both when
2121 * it it enlarged and when it is stored info.
2125 * Store the vtable in klass->runtime_info.
2126 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2128 mono_memory_barrier ();
2130 old_info = klass->runtime_info;
2131 if (old_info && old_info->max_domain >= domain->domain_id) {
2132 /* someone already created a large enough runtime info */
2133 old_info->domain_vtables [domain->domain_id] = vt;
2134 } else {
2135 int new_size = domain->domain_id;
2136 if (old_info)
2137 new_size = MAX (new_size, old_info->max_domain);
2138 new_size++;
2139 /* make the new size a power of two */
2140 i = 2;
2141 while (new_size > i)
2142 i <<= 1;
2143 new_size = i;
2144 /* this is a bounded memory retention issue: may want to
2145 * handle it differently when we'll have a rcu-like system.
2147 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2148 runtime_info->max_domain = new_size - 1;
2149 /* copy the stuff from the older info */
2150 if (old_info) {
2151 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2153 runtime_info->domain_vtables [domain->domain_id] = vt;
2154 /* keep this last*/
2155 mono_memory_barrier ();
2156 klass->runtime_info = runtime_info;
2159 if (klass == mono_defaults.runtimetype_class) {
2160 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2161 if (!is_ok (error)) {
2162 mono_domain_unlock (domain);
2163 mono_loader_unlock ();
2164 return NULL;
2167 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2168 /* This is unregistered in
2169 unregister_vtable_reflection_type() in
2170 domain.c. */
2171 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2174 mono_domain_unlock (domain);
2175 mono_loader_unlock ();
2177 /* make sure the parent is initialized */
2178 /*FIXME shouldn't this fail the current type?*/
2179 if (klass->parent)
2180 mono_class_vtable_full (domain, klass->parent, error);
2182 return vt;
2185 #ifndef DISABLE_REMOTING
2187 * mono_class_proxy_vtable:
2188 * @domain: the application domain
2189 * @remove_class: the remote class
2190 * @error: set on error
2192 * Creates a vtable for transparent proxies. It is basically
2193 * a copy of the real vtable of the class wrapped in @remote_class,
2194 * but all function pointers invoke the remoting functions, and
2195 * vtable->klass points to the transparent proxy class, and not to @class.
2197 * On failure returns NULL and sets @error
2199 static MonoVTable *
2200 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2202 MONO_REQ_GC_UNSAFE_MODE;
2204 MonoVTable *vt, *pvt;
2205 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2206 MonoClass *k;
2207 GSList *extra_interfaces = NULL;
2208 MonoClass *klass = remote_class->proxy_class;
2209 gpointer *interface_offsets;
2210 uint8_t *bitmap = NULL;
2211 int bsize;
2212 size_t imt_table_bytes;
2214 #ifdef COMPRESSED_INTERFACE_BITMAP
2215 int bcsize;
2216 #endif
2218 mono_error_init (error);
2220 vt = mono_class_vtable (domain, klass);
2221 g_assert (vt); /*FIXME property handle failure*/
2222 max_interface_id = vt->max_interface_id;
2224 /* Calculate vtable space for extra interfaces */
2225 for (j = 0; j < remote_class->interface_count; j++) {
2226 MonoClass* iclass = remote_class->interfaces[j];
2227 GPtrArray *ifaces;
2228 int method_count;
2230 /*FIXME test for interfaces with variant generic arguments*/
2231 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2232 continue; /* interface implemented by the class */
2233 if (g_slist_find (extra_interfaces, iclass))
2234 continue;
2236 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2238 method_count = mono_class_num_methods (iclass);
2240 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2241 if (!is_ok (error))
2242 goto failure;
2243 if (ifaces) {
2244 for (i = 0; i < ifaces->len; ++i) {
2245 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2246 /*FIXME test for interfaces with variant generic arguments*/
2247 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2248 continue; /* interface implemented by the class */
2249 if (g_slist_find (extra_interfaces, ic))
2250 continue;
2251 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2252 method_count += mono_class_num_methods (ic);
2254 g_ptr_array_free (ifaces, TRUE);
2255 ifaces = NULL;
2258 extra_interface_vtsize += method_count * sizeof (gpointer);
2259 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2262 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2263 mono_stats.imt_number_of_tables++;
2264 mono_stats.imt_tables_size += imt_table_bytes;
2266 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2268 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2270 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2271 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2272 g_assert (!((gsize)pvt & 7));
2274 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2276 pvt->klass = mono_defaults.transparent_proxy_class;
2277 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2278 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2280 /* initialize vtable */
2281 mono_class_setup_vtable (klass);
2282 for (i = 0; i < klass->vtable_size; ++i) {
2283 MonoMethod *cm;
2285 if ((cm = klass->vtable [i])) {
2286 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2287 if (!is_ok (error))
2288 goto failure;
2289 } else
2290 pvt->vtable [i] = NULL;
2293 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2294 /* create trampolines for abstract methods */
2295 for (k = klass; k; k = k->parent) {
2296 MonoMethod* m;
2297 gpointer iter = NULL;
2298 while ((m = mono_class_get_methods (k, &iter)))
2299 if (!pvt->vtable [m->slot]) {
2300 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2301 if (!is_ok (error))
2302 goto failure;
2307 pvt->max_interface_id = max_interface_id;
2308 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bitmap = (uint8_t *)g_malloc0 (bsize);
2311 #else
2312 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2313 #endif
2315 for (i = 0; i < klass->interface_offsets_count; ++i) {
2316 int interface_id = klass->interfaces_packed [i]->interface_id;
2317 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2320 if (extra_interfaces) {
2321 int slot = klass->vtable_size;
2322 MonoClass* interf;
2323 gpointer iter;
2324 MonoMethod* cm;
2325 GSList *list_item;
2327 /* Create trampolines for the methods of the interfaces */
2328 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2329 interf = (MonoClass *)list_item->data;
2331 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2333 iter = NULL;
2334 j = 0;
2335 while ((cm = mono_class_get_methods (interf, &iter))) {
2336 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2337 if (!is_ok (error))
2338 goto failure;
2341 slot += mono_class_num_methods (interf);
2345 /* Now that the vtable is full, we can actually fill up the IMT */
2346 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2347 if (extra_interfaces) {
2348 g_slist_free (extra_interfaces);
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2352 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2353 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2354 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2355 g_free (bitmap);
2356 #else
2357 pvt->interface_bitmap = bitmap;
2358 #endif
2359 return pvt;
2360 failure:
2361 if (extra_interfaces)
2362 g_slist_free (extra_interfaces);
2363 #ifdef COMPRESSED_INTERFACE_BITMAP
2364 g_free (bitmap);
2365 #endif
2366 return NULL;
2369 #endif /* DISABLE_REMOTING */
2372 * mono_class_field_is_special_static:
2374 * Returns whether @field is a thread/context static field.
2376 gboolean
2377 mono_class_field_is_special_static (MonoClassField *field)
2379 MONO_REQ_GC_NEUTRAL_MODE
2381 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2382 return FALSE;
2383 if (mono_field_is_deleted (field))
2384 return FALSE;
2385 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2386 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2387 return TRUE;
2389 return FALSE;
2393 * mono_class_field_get_special_static_type:
2394 * @field: The MonoClassField describing the field.
2396 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2397 * SPECIAL_STATIC_NONE otherwise.
2399 guint32
2400 mono_class_field_get_special_static_type (MonoClassField *field)
2402 MONO_REQ_GC_NEUTRAL_MODE
2404 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2405 return SPECIAL_STATIC_NONE;
2406 if (mono_field_is_deleted (field))
2407 return SPECIAL_STATIC_NONE;
2408 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2409 return field_is_special_static (field->parent, field);
2410 return SPECIAL_STATIC_NONE;
2414 * mono_class_has_special_static_fields:
2416 * Returns whenever @klass has any thread/context static fields.
2418 gboolean
2419 mono_class_has_special_static_fields (MonoClass *klass)
2421 MONO_REQ_GC_NEUTRAL_MODE
2423 MonoClassField *field;
2424 gpointer iter;
2426 iter = NULL;
2427 while ((field = mono_class_get_fields (klass, &iter))) {
2428 g_assert (field->parent == klass);
2429 if (mono_class_field_is_special_static (field))
2430 return TRUE;
2433 return FALSE;
2436 #ifndef DISABLE_REMOTING
2438 * create_remote_class_key:
2439 * Creates an array of pointers that can be used as a hash key for a remote class.
2440 * The first element of the array is the number of pointers.
2442 static gpointer*
2443 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2445 MONO_REQ_GC_NEUTRAL_MODE;
2447 gpointer *key;
2448 int i, j;
2450 if (remote_class == NULL) {
2451 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2452 key = (void **)g_malloc (sizeof(gpointer) * 3);
2453 key [0] = GINT_TO_POINTER (2);
2454 key [1] = mono_defaults.marshalbyrefobject_class;
2455 key [2] = extra_class;
2456 } else {
2457 key = (void **)g_malloc (sizeof(gpointer) * 2);
2458 key [0] = GINT_TO_POINTER (1);
2459 key [1] = extra_class;
2461 } else {
2462 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2463 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2464 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2465 key [1] = remote_class->proxy_class;
2467 // Keep the list of interfaces sorted
2468 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2469 if (extra_class && remote_class->interfaces [i] > extra_class) {
2470 key [j++] = extra_class;
2471 extra_class = NULL;
2473 key [j] = remote_class->interfaces [i];
2475 if (extra_class)
2476 key [j] = extra_class;
2477 } else {
2478 // Replace the old class. The interface list is the same
2479 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2480 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2481 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2482 for (i = 0; i < remote_class->interface_count; i++)
2483 key [2 + i] = remote_class->interfaces [i];
2487 return key;
2491 * copy_remote_class_key:
2493 * Make a copy of KEY in the domain and return the copy.
2495 static gpointer*
2496 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2498 MONO_REQ_GC_NEUTRAL_MODE
2500 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2501 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2503 memcpy (mp_key, key, key_size);
2505 return mp_key;
2509 * mono_remote_class:
2510 * @domain: the application domain
2511 * @class_name: name of the remote class
2512 * @error: set on error
2514 * Creates and initializes a MonoRemoteClass object for a remote type.
2516 * On failure returns NULL and sets @error
2518 MonoRemoteClass*
2519 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2521 MONO_REQ_GC_UNSAFE_MODE;
2523 MonoRemoteClass *rc;
2524 gpointer* key, *mp_key;
2525 char *name;
2527 mono_error_init (error);
2529 key = create_remote_class_key (NULL, proxy_class);
2531 mono_domain_lock (domain);
2532 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2534 if (rc) {
2535 g_free (key);
2536 mono_domain_unlock (domain);
2537 return rc;
2540 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2541 if (!is_ok (error)) {
2542 g_free (key);
2543 mono_domain_unlock (domain);
2544 return NULL;
2547 mp_key = copy_remote_class_key (domain, key);
2548 g_free (key);
2549 key = mp_key;
2551 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2552 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2553 rc->interface_count = 1;
2554 rc->interfaces [0] = proxy_class;
2555 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2556 } else {
2557 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2558 rc->interface_count = 0;
2559 rc->proxy_class = proxy_class;
2562 rc->default_vtable = NULL;
2563 rc->xdomain_vtable = NULL;
2564 rc->proxy_class_name = name;
2565 #ifndef DISABLE_PERFCOUNTERS
2566 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2567 #endif
2569 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2571 mono_domain_unlock (domain);
2572 return rc;
2576 * clone_remote_class:
2577 * Creates a copy of the remote_class, adding the provided class or interface
2579 static MonoRemoteClass*
2580 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2582 MONO_REQ_GC_NEUTRAL_MODE;
2584 MonoRemoteClass *rc;
2585 gpointer* key, *mp_key;
2587 key = create_remote_class_key (remote_class, extra_class);
2588 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2589 if (rc != NULL) {
2590 g_free (key);
2591 return rc;
2594 mp_key = copy_remote_class_key (domain, key);
2595 g_free (key);
2596 key = mp_key;
2598 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2599 int i,j;
2600 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2601 rc->proxy_class = remote_class->proxy_class;
2602 rc->interface_count = remote_class->interface_count + 1;
2604 // Keep the list of interfaces sorted, since the hash key of
2605 // the remote class depends on this
2606 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2607 if (remote_class->interfaces [i] > extra_class && i == j)
2608 rc->interfaces [j++] = extra_class;
2609 rc->interfaces [j] = remote_class->interfaces [i];
2611 if (i == j)
2612 rc->interfaces [j] = extra_class;
2613 } else {
2614 // Replace the old class. The interface array is the same
2615 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2616 rc->proxy_class = extra_class;
2617 rc->interface_count = remote_class->interface_count;
2618 if (rc->interface_count > 0)
2619 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2622 rc->default_vtable = NULL;
2623 rc->xdomain_vtable = NULL;
2624 rc->proxy_class_name = remote_class->proxy_class_name;
2626 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2628 return rc;
2631 gpointer
2632 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2634 MONO_REQ_GC_UNSAFE_MODE;
2636 mono_error_init (error);
2638 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2639 mono_domain_lock (domain);
2640 if (rp->target_domain_id != -1) {
2641 if (remote_class->xdomain_vtable == NULL)
2642 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2643 mono_domain_unlock (domain);
2644 mono_loader_unlock ();
2645 return_val_if_nok (error, NULL);
2646 return remote_class->xdomain_vtable;
2648 if (remote_class->default_vtable == NULL) {
2649 MonoType *type;
2650 MonoClass *klass;
2651 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2652 klass = mono_class_from_mono_type (type);
2653 #ifndef DISABLE_COM
2654 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)))
2655 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2656 else
2657 #endif
2658 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2659 /* N.B. both branches of the if modify error */
2660 if (!is_ok (error)) {
2661 mono_domain_unlock (domain);
2662 mono_loader_unlock ();
2663 return NULL;
2667 mono_domain_unlock (domain);
2668 mono_loader_unlock ();
2669 return remote_class->default_vtable;
2673 * mono_upgrade_remote_class:
2674 * @domain: the application domain
2675 * @tproxy: the proxy whose remote class has to be upgraded.
2676 * @klass: class to which the remote class can be casted.
2677 * @error: set on error
2679 * Updates the vtable of the remote class by adding the necessary method slots
2680 * and interface offsets so it can be safely casted to klass. klass can be a
2681 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2683 gboolean
2684 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2686 MONO_REQ_GC_UNSAFE_MODE;
2688 MonoTransparentProxy *tproxy;
2689 MonoRemoteClass *remote_class;
2690 gboolean redo_vtable;
2692 mono_error_init (error);
2693 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2694 mono_domain_lock (domain);
2696 tproxy = (MonoTransparentProxy*) proxy_object;
2697 remote_class = tproxy->remote_class;
2699 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2700 int i;
2701 redo_vtable = TRUE;
2702 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2703 if (remote_class->interfaces [i] == klass)
2704 redo_vtable = FALSE;
2706 else {
2707 redo_vtable = (remote_class->proxy_class != klass);
2710 if (redo_vtable) {
2711 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2712 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2713 if (!is_ok (error))
2714 goto leave;
2717 leave:
2718 mono_domain_unlock (domain);
2719 mono_loader_unlock ();
2720 return is_ok (error);
2722 #endif /* DISABLE_REMOTING */
2726 * mono_object_get_virtual_method:
2727 * @obj: object to operate on.
2728 * @method: method
2730 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2731 * the instance of a callvirt of method.
2733 MonoMethod*
2734 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2736 MONO_REQ_GC_UNSAFE_MODE;
2738 MonoClass *klass;
2739 MonoMethod **vtable;
2740 gboolean is_proxy = FALSE;
2741 MonoMethod *res = NULL;
2743 klass = mono_object_class (obj);
2744 #ifndef DISABLE_REMOTING
2745 if (klass == mono_defaults.transparent_proxy_class) {
2746 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2747 is_proxy = TRUE;
2749 #endif
2751 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2752 return method;
2754 mono_class_setup_vtable (klass);
2755 vtable = klass->vtable;
2757 if (method->slot == -1) {
2758 /* method->slot might not be set for instances of generic methods */
2759 if (method->is_inflated) {
2760 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2761 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2762 } else {
2763 if (!is_proxy)
2764 g_assert_not_reached ();
2768 /* check method->slot is a valid index: perform isinstance? */
2769 if (method->slot != -1) {
2770 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2771 if (!is_proxy) {
2772 gboolean variance_used = FALSE;
2773 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2774 g_assert (iface_offset > 0);
2775 res = vtable [iface_offset + method->slot];
2777 } else {
2778 res = vtable [method->slot];
2782 #ifndef DISABLE_REMOTING
2783 if (is_proxy) {
2784 /* It may be an interface, abstract class method or generic method */
2785 if (!res || mono_method_signature (res)->generic_param_count)
2786 res = method;
2788 /* generic methods demand invoke_with_check */
2789 if (mono_method_signature (res)->generic_param_count)
2790 res = mono_marshal_get_remoting_invoke_with_check (res);
2791 else {
2792 #ifndef DISABLE_COM
2793 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2794 res = mono_cominterop_get_invoke (res);
2795 else
2796 #endif
2797 res = mono_marshal_get_remoting_invoke (res);
2799 } else
2800 #endif
2802 if (method->is_inflated) {
2803 MonoError error;
2804 /* Have to inflate the result */
2805 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2806 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2810 g_assert (res);
2812 return res;
2815 static MonoObject*
2816 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2818 MONO_REQ_GC_UNSAFE_MODE;
2820 MonoObject *result = NULL;
2822 g_assert (callbacks.runtime_invoke);
2824 mono_error_init (error);
2826 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2827 mono_profiler_method_start_invoke (method);
2829 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2831 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2832 mono_profiler_method_end_invoke (method);
2834 if (!mono_error_ok (error))
2835 return NULL;
2837 return result;
2841 * mono_runtime_invoke:
2842 * @method: method to invoke
2843 * @obJ: object instance
2844 * @params: arguments to the method
2845 * @exc: exception information.
2847 * Invokes the method represented by @method on the object @obj.
2849 * obj is the 'this' pointer, it should be NULL for static
2850 * methods, a MonoObject* for object instances and a pointer to
2851 * the value type for value types.
2853 * The params array contains the arguments to the method with the
2854 * same convention: MonoObject* pointers for object instances and
2855 * pointers to the value type otherwise.
2857 * From unmanaged code you'll usually use the
2858 * mono_runtime_invoke() variant.
2860 * Note that this function doesn't handle virtual methods for
2861 * you, it will exec the exact method you pass: we still need to
2862 * expose a function to lookup the derived class implementation
2863 * of a virtual method (there are examples of this in the code,
2864 * though).
2866 * You can pass NULL as the exc argument if you don't want to
2867 * catch exceptions, otherwise, *exc will be set to the exception
2868 * thrown, if any. if an exception is thrown, you can't use the
2869 * MonoObject* result from the function.
2871 * If the method returns a value type, it is boxed in an object
2872 * reference.
2874 MonoObject*
2875 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2877 MonoError error;
2878 MonoObject *res;
2879 if (exc) {
2880 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2881 if (*exc == NULL && !mono_error_ok(&error)) {
2882 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2883 } else
2884 mono_error_cleanup (&error);
2885 } else {
2886 res = mono_runtime_invoke_checked (method, obj, params, &error);
2887 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2889 return res;
2893 * mono_runtime_try_invoke:
2894 * @method: method to invoke
2895 * @obJ: object instance
2896 * @params: arguments to the method
2897 * @exc: exception information.
2898 * @error: set on error
2900 * Invokes the method represented by @method on the object @obj.
2902 * obj is the 'this' pointer, it should be NULL for static
2903 * methods, a MonoObject* for object instances and a pointer to
2904 * the value type for value types.
2906 * The params array contains the arguments to the method with the
2907 * same convention: MonoObject* pointers for object instances and
2908 * pointers to the value type otherwise.
2910 * From unmanaged code you'll usually use the
2911 * mono_runtime_invoke() variant.
2913 * Note that this function doesn't handle virtual methods for
2914 * you, it will exec the exact method you pass: we still need to
2915 * expose a function to lookup the derived class implementation
2916 * of a virtual method (there are examples of this in the code,
2917 * though).
2919 * For this function, you must not pass NULL as the exc argument if
2920 * you don't want to catch exceptions, use
2921 * mono_runtime_invoke_checked(). If an exception is thrown, you
2922 * can't use the MonoObject* result from the function.
2924 * If this method cannot be invoked, @error will be set and @exc and
2925 * the return value must not be used.
2927 * If the method returns a value type, it is boxed in an object
2928 * reference.
2930 MonoObject*
2931 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2933 MONO_REQ_GC_UNSAFE_MODE;
2935 g_assert (exc != NULL);
2937 if (mono_runtime_get_no_exec ())
2938 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2940 return do_runtime_invoke (method, obj, params, exc, error);
2944 * mono_runtime_invoke_checked:
2945 * @method: method to invoke
2946 * @obJ: object instance
2947 * @params: arguments to the method
2948 * @error: set on error
2950 * Invokes the method represented by @method on the object @obj.
2952 * obj is the 'this' pointer, it should be NULL for static
2953 * methods, a MonoObject* for object instances and a pointer to
2954 * the value type for value types.
2956 * The params array contains the arguments to the method with the
2957 * same convention: MonoObject* pointers for object instances and
2958 * pointers to the value type otherwise.
2960 * From unmanaged code you'll usually use the
2961 * mono_runtime_invoke() variant.
2963 * Note that this function doesn't handle virtual methods for
2964 * you, it will exec the exact method you pass: we still need to
2965 * expose a function to lookup the derived class implementation
2966 * of a virtual method (there are examples of this in the code,
2967 * though).
2969 * If an exception is thrown, you can't use the MonoObject* result
2970 * from the function.
2972 * If this method cannot be invoked, @error will be set. If the
2973 * method throws an exception (and we're in coop mode) the exception
2974 * will be set in @error.
2976 * If the method returns a value type, it is boxed in an object
2977 * reference.
2979 MonoObject*
2980 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2982 MONO_REQ_GC_UNSAFE_MODE;
2984 if (mono_runtime_get_no_exec ())
2985 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2987 return do_runtime_invoke (method, obj, params, NULL, error);
2991 * mono_method_get_unmanaged_thunk:
2992 * @method: method to generate a thunk for.
2994 * Returns an unmanaged->managed thunk that can be used to call
2995 * a managed method directly from C.
2997 * The thunk's C signature closely matches the managed signature:
2999 * C#: public bool Equals (object obj);
3000 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3001 * MonoObject*, MonoException**);
3003 * The 1st ("this") parameter must not be used with static methods:
3005 * C#: public static bool ReferenceEquals (object a, object b);
3006 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3007 * MonoException**);
3009 * The last argument must be a non-null pointer of a MonoException* pointer.
3010 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3011 * exception has been thrown in managed code. Otherwise it will point
3012 * to the MonoException* caught by the thunk. In this case, the result of
3013 * the thunk is undefined:
3015 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3016 * MonoException *ex = NULL;
3017 * Equals func = mono_method_get_unmanaged_thunk (method);
3018 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3019 * if (ex) {
3020 * // handle exception
3023 * The calling convention of the thunk matches the platform's default
3024 * convention. This means that under Windows, C declarations must
3025 * contain the __stdcall attribute:
3027 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3028 * MonoObject*, MonoException**);
3030 * LIMITATIONS
3032 * Value type arguments and return values are treated as they were objects:
3034 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3035 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3037 * Arguments must be properly boxed upon trunk's invocation, while return
3038 * values must be unboxed.
3040 gpointer
3041 mono_method_get_unmanaged_thunk (MonoMethod *method)
3043 MONO_REQ_GC_NEUTRAL_MODE;
3044 MONO_REQ_API_ENTRYPOINT;
3046 MonoError error;
3047 gpointer res;
3049 g_assert (!mono_threads_is_coop_enabled ());
3051 MONO_ENTER_GC_UNSAFE;
3052 method = mono_marshal_get_thunk_invoke_wrapper (method);
3053 res = mono_compile_method_checked (method, &error);
3054 mono_error_cleanup (&error);
3055 MONO_EXIT_GC_UNSAFE;
3057 return res;
3060 void
3061 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3063 MONO_REQ_GC_UNSAFE_MODE;
3065 int t;
3066 if (type->byref) {
3067 /* object fields cannot be byref, so we don't need a
3068 wbarrier here */
3069 gpointer *p = (gpointer*)dest;
3070 *p = value;
3071 return;
3073 t = type->type;
3074 handle_enum:
3075 switch (t) {
3076 case MONO_TYPE_BOOLEAN:
3077 case MONO_TYPE_I1:
3078 case MONO_TYPE_U1: {
3079 guint8 *p = (guint8*)dest;
3080 *p = value ? *(guint8*)value : 0;
3081 return;
3083 case MONO_TYPE_I2:
3084 case MONO_TYPE_U2:
3085 case MONO_TYPE_CHAR: {
3086 guint16 *p = (guint16*)dest;
3087 *p = value ? *(guint16*)value : 0;
3088 return;
3090 #if SIZEOF_VOID_P == 4
3091 case MONO_TYPE_I:
3092 case MONO_TYPE_U:
3093 #endif
3094 case MONO_TYPE_I4:
3095 case MONO_TYPE_U4: {
3096 gint32 *p = (gint32*)dest;
3097 *p = value ? *(gint32*)value : 0;
3098 return;
3100 #if SIZEOF_VOID_P == 8
3101 case MONO_TYPE_I:
3102 case MONO_TYPE_U:
3103 #endif
3104 case MONO_TYPE_I8:
3105 case MONO_TYPE_U8: {
3106 gint64 *p = (gint64*)dest;
3107 *p = value ? *(gint64*)value : 0;
3108 return;
3110 case MONO_TYPE_R4: {
3111 float *p = (float*)dest;
3112 *p = value ? *(float*)value : 0;
3113 return;
3115 case MONO_TYPE_R8: {
3116 double *p = (double*)dest;
3117 *p = value ? *(double*)value : 0;
3118 return;
3120 case MONO_TYPE_STRING:
3121 case MONO_TYPE_SZARRAY:
3122 case MONO_TYPE_CLASS:
3123 case MONO_TYPE_OBJECT:
3124 case MONO_TYPE_ARRAY:
3125 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3126 return;
3127 case MONO_TYPE_FNPTR:
3128 case MONO_TYPE_PTR: {
3129 gpointer *p = (gpointer*)dest;
3130 *p = deref_pointer? *(gpointer*)value: value;
3131 return;
3133 case MONO_TYPE_VALUETYPE:
3134 /* note that 't' and 'type->type' can be different */
3135 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3136 t = mono_class_enum_basetype (type->data.klass)->type;
3137 goto handle_enum;
3138 } else {
3139 MonoClass *klass = mono_class_from_mono_type (type);
3140 int size = mono_class_value_size (klass, NULL);
3141 if (value == NULL)
3142 mono_gc_bzero_atomic (dest, size);
3143 else
3144 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3146 return;
3147 case MONO_TYPE_GENERICINST:
3148 t = type->data.generic_class->container_class->byval_arg.type;
3149 goto handle_enum;
3150 default:
3151 g_error ("got type %x", type->type);
3156 * mono_field_set_value:
3157 * @obj: Instance object
3158 * @field: MonoClassField describing the field to set
3159 * @value: The value to be set
3161 * Sets the value of the field described by @field in the object instance @obj
3162 * to the value passed in @value. This method should only be used for instance
3163 * fields. For static fields, use mono_field_static_set_value.
3165 * The value must be on the native format of the field type.
3167 void
3168 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3170 MONO_REQ_GC_UNSAFE_MODE;
3172 void *dest;
3174 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3176 dest = (char*)obj + field->offset;
3177 mono_copy_value (field->type, dest, value, FALSE);
3181 * mono_field_static_set_value:
3182 * @field: MonoClassField describing the field to set
3183 * @value: The value to be set
3185 * Sets the value of the static field described by @field
3186 * to the value passed in @value.
3188 * The value must be on the native format of the field type.
3190 void
3191 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3193 MONO_REQ_GC_UNSAFE_MODE;
3195 void *dest;
3197 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3198 /* you cant set a constant! */
3199 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3201 if (field->offset == -1) {
3202 /* Special static */
3203 gpointer addr;
3205 mono_domain_lock (vt->domain);
3206 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3207 mono_domain_unlock (vt->domain);
3208 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3209 } else {
3210 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3212 mono_copy_value (field->type, dest, value, FALSE);
3216 * mono_vtable_get_static_field_data:
3218 * Internal use function: return a pointer to the memory holding the static fields
3219 * for a class or NULL if there are no static fields.
3220 * This is exported only for use by the debugger.
3222 void *
3223 mono_vtable_get_static_field_data (MonoVTable *vt)
3225 MONO_REQ_GC_NEUTRAL_MODE
3227 if (!vt->has_static_fields)
3228 return NULL;
3229 return vt->vtable [vt->klass->vtable_size];
3232 static guint8*
3233 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3235 MONO_REQ_GC_UNSAFE_MODE;
3237 guint8 *src;
3239 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3240 if (field->offset == -1) {
3241 /* Special static */
3242 gpointer addr;
3244 mono_domain_lock (vt->domain);
3245 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3246 mono_domain_unlock (vt->domain);
3247 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3248 } else {
3249 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3251 } else {
3252 src = (guint8*)obj + field->offset;
3255 return src;
3259 * mono_field_get_value:
3260 * @obj: Object instance
3261 * @field: MonoClassField describing the field to fetch information from
3262 * @value: pointer to the location where the value will be stored
3264 * Use this routine to get the value of the field @field in the object
3265 * passed.
3267 * The pointer provided by value must be of the field type, for reference
3268 * types this is a MonoObject*, for value types its the actual pointer to
3269 * the value type.
3271 * For example:
3272 * int i;
3273 * mono_field_get_value (obj, int_field, &i);
3275 void
3276 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3278 MONO_REQ_GC_UNSAFE_MODE;
3280 void *src;
3282 g_assert (obj);
3284 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3286 src = (char*)obj + field->offset;
3287 mono_copy_value (field->type, value, src, TRUE);
3291 * mono_field_get_value_object:
3292 * @domain: domain where the object will be created (if boxing)
3293 * @field: MonoClassField describing the field to fetch information from
3294 * @obj: The object instance for the field.
3296 * Returns: a new MonoObject with the value from the given field. If the
3297 * field represents a value type, the value is boxed.
3300 MonoObject *
3301 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3303 MonoError error;
3304 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3305 mono_error_assert_ok (&error);
3306 return result;
3310 * mono_field_get_value_object_checked:
3311 * @domain: domain where the object will be created (if boxing)
3312 * @field: MonoClassField describing the field to fetch information from
3313 * @obj: The object instance for the field.
3314 * @error: Set on error.
3316 * Returns: a new MonoObject with the value from the given field. If the
3317 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3320 MonoObject *
3321 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3323 MONO_REQ_GC_UNSAFE_MODE;
3325 mono_error_init (error);
3327 MonoObject *o;
3328 MonoClass *klass;
3329 MonoVTable *vtable = NULL;
3330 gchar *v;
3331 gboolean is_static = FALSE;
3332 gboolean is_ref = FALSE;
3333 gboolean is_literal = FALSE;
3334 gboolean is_ptr = FALSE;
3335 MonoType *type = mono_field_get_type_checked (field, error);
3337 return_val_if_nok (error, NULL);
3339 switch (type->type) {
3340 case MONO_TYPE_STRING:
3341 case MONO_TYPE_OBJECT:
3342 case MONO_TYPE_CLASS:
3343 case MONO_TYPE_ARRAY:
3344 case MONO_TYPE_SZARRAY:
3345 is_ref = TRUE;
3346 break;
3347 case MONO_TYPE_U1:
3348 case MONO_TYPE_I1:
3349 case MONO_TYPE_BOOLEAN:
3350 case MONO_TYPE_U2:
3351 case MONO_TYPE_I2:
3352 case MONO_TYPE_CHAR:
3353 case MONO_TYPE_U:
3354 case MONO_TYPE_I:
3355 case MONO_TYPE_U4:
3356 case MONO_TYPE_I4:
3357 case MONO_TYPE_R4:
3358 case MONO_TYPE_U8:
3359 case MONO_TYPE_I8:
3360 case MONO_TYPE_R8:
3361 case MONO_TYPE_VALUETYPE:
3362 is_ref = type->byref;
3363 break;
3364 case MONO_TYPE_GENERICINST:
3365 is_ref = !mono_type_generic_inst_is_valuetype (type);
3366 break;
3367 case MONO_TYPE_PTR:
3368 is_ptr = TRUE;
3369 break;
3370 default:
3371 g_error ("type 0x%x not handled in "
3372 "mono_field_get_value_object", type->type);
3373 return NULL;
3376 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3377 is_literal = TRUE;
3379 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3380 is_static = TRUE;
3382 if (!is_literal) {
3383 vtable = mono_class_vtable_full (domain, field->parent, error);
3384 return_val_if_nok (error, NULL);
3386 if (!vtable->initialized) {
3387 mono_runtime_class_init_full (vtable, error);
3388 return_val_if_nok (error, NULL);
3391 } else {
3392 g_assert (obj);
3395 if (is_ref) {
3396 if (is_literal) {
3397 get_default_field_value (domain, field, &o, error);
3398 return_val_if_nok (error, NULL);
3399 } else if (is_static) {
3400 mono_field_static_get_value_checked (vtable, field, &o, error);
3401 return_val_if_nok (error, NULL);
3402 } else {
3403 mono_field_get_value (obj, field, &o);
3405 return o;
3408 if (is_ptr) {
3409 static MonoMethod *m;
3410 gpointer args [2];
3411 gpointer *ptr;
3412 gpointer v;
3414 if (!m) {
3415 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3416 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3417 g_assert (m);
3420 v = &ptr;
3421 if (is_literal) {
3422 get_default_field_value (domain, field, v, error);
3423 return_val_if_nok (error, NULL);
3424 } else if (is_static) {
3425 mono_field_static_get_value_checked (vtable, field, v, error);
3426 return_val_if_nok (error, NULL);
3427 } else {
3428 mono_field_get_value (obj, field, v);
3431 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3432 args [0] = ptr ? *ptr : NULL;
3433 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3434 return_val_if_nok (error, NULL);
3436 o = mono_runtime_invoke_checked (m, NULL, args, error);
3437 return_val_if_nok (error, NULL);
3439 return o;
3442 /* boxed value type */
3443 klass = mono_class_from_mono_type (type);
3445 if (mono_class_is_nullable (klass))
3446 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3448 o = mono_object_new_checked (domain, klass, error);
3449 return_val_if_nok (error, NULL);
3450 v = ((gchar *) o) + sizeof (MonoObject);
3452 if (is_literal) {
3453 get_default_field_value (domain, field, v, error);
3454 return_val_if_nok (error, NULL);
3455 } else if (is_static) {
3456 mono_field_static_get_value_checked (vtable, field, v, error);
3457 return_val_if_nok (error, NULL);
3458 } else {
3459 mono_field_get_value (obj, field, v);
3462 return o;
3466 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3468 MONO_REQ_GC_UNSAFE_MODE;
3470 mono_error_init (error);
3471 int retval = 0;
3472 const char *p = blob;
3473 mono_metadata_decode_blob_size (p, &p);
3475 switch (type) {
3476 case MONO_TYPE_BOOLEAN:
3477 case MONO_TYPE_U1:
3478 case MONO_TYPE_I1:
3479 *(guint8 *) value = *p;
3480 break;
3481 case MONO_TYPE_CHAR:
3482 case MONO_TYPE_U2:
3483 case MONO_TYPE_I2:
3484 *(guint16*) value = read16 (p);
3485 break;
3486 case MONO_TYPE_U4:
3487 case MONO_TYPE_I4:
3488 *(guint32*) value = read32 (p);
3489 break;
3490 case MONO_TYPE_U8:
3491 case MONO_TYPE_I8:
3492 *(guint64*) value = read64 (p);
3493 break;
3494 case MONO_TYPE_R4:
3495 readr4 (p, (float*) value);
3496 break;
3497 case MONO_TYPE_R8:
3498 readr8 (p, (double*) value);
3499 break;
3500 case MONO_TYPE_STRING:
3501 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3502 break;
3503 case MONO_TYPE_CLASS:
3504 *(gpointer*) value = NULL;
3505 break;
3506 default:
3507 retval = -1;
3508 g_warning ("type 0x%02x should not be in constant table", type);
3510 return retval;
3513 static void
3514 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3516 MONO_REQ_GC_NEUTRAL_MODE;
3518 MonoTypeEnum def_type;
3519 const char* data;
3521 mono_error_init (error);
3523 data = mono_class_get_field_default_value (field, &def_type);
3524 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3527 void
3528 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3530 MONO_REQ_GC_UNSAFE_MODE;
3532 void *src;
3534 mono_error_init (error);
3536 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3538 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3539 get_default_field_value (vt->domain, field, value, error);
3540 return;
3543 if (field->offset == -1) {
3544 /* Special static */
3545 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3546 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3547 } else {
3548 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3550 mono_copy_value (field->type, value, src, TRUE);
3554 * mono_field_static_get_value:
3555 * @vt: vtable to the object
3556 * @field: MonoClassField describing the field to fetch information from
3557 * @value: where the value is returned
3559 * Use this routine to get the value of the static field @field value.
3561 * The pointer provided by value must be of the field type, for reference
3562 * types this is a MonoObject*, for value types its the actual pointer to
3563 * the value type.
3565 * For example:
3566 * int i;
3567 * mono_field_static_get_value (vt, int_field, &i);
3569 void
3570 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3572 MONO_REQ_GC_NEUTRAL_MODE;
3574 MonoError error;
3575 mono_field_static_get_value_checked (vt, field, value, &error);
3576 mono_error_cleanup (&error);
3580 * mono_field_static_get_value_checked:
3581 * @vt: vtable to the object
3582 * @field: MonoClassField describing the field to fetch information from
3583 * @value: where the value is returned
3584 * @error: set on error
3586 * Use this routine to get the value of the static field @field value.
3588 * The pointer provided by value must be of the field type, for reference
3589 * types this is a MonoObject*, for value types its the actual pointer to
3590 * the value type.
3592 * For example:
3593 * int i;
3594 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3595 * if (!is_ok (error)) { ... }
3597 * On failure sets @error.
3599 void
3600 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3602 MONO_REQ_GC_NEUTRAL_MODE;
3604 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3608 * mono_property_set_value:
3609 * @prop: MonoProperty to set
3610 * @obj: instance object on which to act
3611 * @params: parameters to pass to the propery
3612 * @exc: optional exception
3614 * Invokes the property's set method with the given arguments on the
3615 * object instance obj (or NULL for static properties).
3617 * You can pass NULL as the exc argument if you don't want to
3618 * catch exceptions, otherwise, *exc will be set to the exception
3619 * thrown, if any. if an exception is thrown, you can't use the
3620 * MonoObject* result from the function.
3622 void
3623 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3625 MONO_REQ_GC_UNSAFE_MODE;
3627 MonoError error;
3628 do_runtime_invoke (prop->set, obj, params, exc, &error);
3629 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3630 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3631 } else {
3632 mono_error_cleanup (&error);
3637 * mono_property_set_value_checked:
3638 * @prop: MonoProperty to set
3639 * @obj: instance object on which to act
3640 * @params: parameters to pass to the propery
3641 * @error: set on error
3643 * Invokes the property's set method with the given arguments on the
3644 * object instance obj (or NULL for static properties).
3646 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3647 * If an exception is thrown, it will be caught and returned via @error.
3649 gboolean
3650 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3652 MONO_REQ_GC_UNSAFE_MODE;
3654 MonoObject *exc;
3656 mono_error_init (error);
3657 do_runtime_invoke (prop->set, obj, params, &exc, error);
3658 if (exc != NULL && is_ok (error))
3659 mono_error_set_exception_instance (error, (MonoException*)exc);
3660 return is_ok (error);
3664 * mono_property_get_value:
3665 * @prop: MonoProperty to fetch
3666 * @obj: instance object on which to act
3667 * @params: parameters to pass to the propery
3668 * @exc: optional exception
3670 * Invokes the property's get method with the given arguments on the
3671 * object instance obj (or NULL for static properties).
3673 * You can pass NULL as the exc argument if you don't want to
3674 * catch exceptions, otherwise, *exc will be set to the exception
3675 * thrown, if any. if an exception is thrown, you can't use the
3676 * MonoObject* result from the function.
3678 * Returns: the value from invoking the get method on the property.
3680 MonoObject*
3681 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3683 MONO_REQ_GC_UNSAFE_MODE;
3685 MonoError error;
3686 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3687 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3688 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3689 } else {
3690 mono_error_cleanup (&error); /* FIXME don't raise here */
3693 return val;
3697 * mono_property_get_value_checked:
3698 * @prop: MonoProperty to fetch
3699 * @obj: instance object on which to act
3700 * @params: parameters to pass to the propery
3701 * @error: set on error
3703 * Invokes the property's get method with the given arguments on the
3704 * object instance obj (or NULL for static properties).
3706 * If an exception is thrown, you can't use the
3707 * MonoObject* result from the function. The exception will be propagated via @error.
3709 * Returns: the value from invoking the get method on the property. On
3710 * failure returns NULL and sets @error.
3712 MonoObject*
3713 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3715 MONO_REQ_GC_UNSAFE_MODE;
3717 MonoObject *exc;
3718 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3719 if (exc != NULL && !is_ok (error))
3720 mono_error_set_exception_instance (error, (MonoException*) exc);
3721 if (!is_ok (error))
3722 val = NULL;
3723 return val;
3728 * mono_nullable_init:
3729 * @buf: The nullable structure to initialize.
3730 * @value: the value to initialize from
3731 * @klass: the type for the object
3733 * Initialize the nullable structure pointed to by @buf from @value which
3734 * should be a boxed value type. The size of @buf should be able to hold
3735 * as much data as the @klass->instance_size (which is the number of bytes
3736 * that will be copies).
3738 * Since Nullables have variable structure, we can not define a C
3739 * structure for them.
3741 void
3742 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3744 MONO_REQ_GC_UNSAFE_MODE;
3746 MonoClass *param_class = klass->cast_class;
3748 mono_class_setup_fields_locking (klass);
3749 g_assert (klass->fields_inited);
3751 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3752 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3754 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3755 if (value) {
3756 if (param_class->has_references)
3757 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3758 else
3759 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3760 } else {
3761 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3766 * mono_nullable_box:
3767 * @buf: The buffer representing the data to be boxed
3768 * @klass: the type to box it as.
3769 * @error: set on oerr
3771 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3772 * @buf. On failure returns NULL and sets @error
3774 MonoObject*
3775 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3777 MONO_REQ_GC_UNSAFE_MODE;
3779 mono_error_init (error);
3780 MonoClass *param_class = klass->cast_class;
3782 mono_class_setup_fields_locking (klass);
3783 g_assert (klass->fields_inited);
3785 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3786 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3788 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3789 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3790 return_val_if_nok (error, NULL);
3791 if (param_class->has_references)
3792 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3793 else
3794 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3795 return o;
3797 else
3798 return NULL;
3802 * mono_get_delegate_invoke:
3803 * @klass: The delegate class
3805 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3807 MonoMethod *
3808 mono_get_delegate_invoke (MonoClass *klass)
3810 MONO_REQ_GC_NEUTRAL_MODE;
3812 MonoMethod *im;
3814 /* This is called at runtime, so avoid the slower search in metadata */
3815 mono_class_setup_methods (klass);
3816 if (mono_class_has_failure (klass))
3817 return NULL;
3818 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3819 return im;
3823 * mono_get_delegate_begin_invoke:
3824 * @klass: The delegate class
3826 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3828 MonoMethod *
3829 mono_get_delegate_begin_invoke (MonoClass *klass)
3831 MONO_REQ_GC_NEUTRAL_MODE;
3833 MonoMethod *im;
3835 /* This is called at runtime, so avoid the slower search in metadata */
3836 mono_class_setup_methods (klass);
3837 if (mono_class_has_failure (klass))
3838 return NULL;
3839 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3840 return im;
3844 * mono_get_delegate_end_invoke:
3845 * @klass: The delegate class
3847 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3849 MonoMethod *
3850 mono_get_delegate_end_invoke (MonoClass *klass)
3852 MONO_REQ_GC_NEUTRAL_MODE;
3854 MonoMethod *im;
3856 /* This is called at runtime, so avoid the slower search in metadata */
3857 mono_class_setup_methods (klass);
3858 if (mono_class_has_failure (klass))
3859 return NULL;
3860 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3861 return im;
3865 * mono_runtime_delegate_invoke:
3866 * @delegate: pointer to a delegate object.
3867 * @params: parameters for the delegate.
3868 * @exc: Pointer to the exception result.
3870 * Invokes the delegate method @delegate with the parameters provided.
3872 * You can pass NULL as the exc argument if you don't want to
3873 * catch exceptions, otherwise, *exc will be set to the exception
3874 * thrown, if any. if an exception is thrown, you can't use the
3875 * MonoObject* result from the function.
3877 MonoObject*
3878 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3880 MONO_REQ_GC_UNSAFE_MODE;
3882 MonoError error;
3883 if (exc) {
3884 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3885 if (*exc) {
3886 mono_error_cleanup (&error);
3887 return NULL;
3888 } else {
3889 if (!is_ok (&error))
3890 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3891 return result;
3893 } else {
3894 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3895 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3896 return result;
3901 * mono_runtime_delegate_try_invoke:
3902 * @delegate: pointer to a delegate object.
3903 * @params: parameters for the delegate.
3904 * @exc: Pointer to the exception result.
3905 * @error: set on error
3907 * Invokes the delegate method @delegate with the parameters provided.
3909 * You can pass NULL as the exc argument if you don't want to
3910 * catch exceptions, otherwise, *exc will be set to the exception
3911 * thrown, if any. On failure to execute, @error will be set.
3912 * if an exception is thrown, you can't use the
3913 * MonoObject* result from the function.
3915 MonoObject*
3916 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3918 MONO_REQ_GC_UNSAFE_MODE;
3920 mono_error_init (error);
3921 MonoMethod *im;
3922 MonoClass *klass = delegate->vtable->klass;
3923 MonoObject *o;
3925 im = mono_get_delegate_invoke (klass);
3926 if (!im)
3927 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3929 if (exc) {
3930 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3931 } else {
3932 o = mono_runtime_invoke_checked (im, delegate, params, error);
3935 return o;
3939 * mono_runtime_delegate_invoke_checked:
3940 * @delegate: pointer to a delegate object.
3941 * @params: parameters for the delegate.
3942 * @error: set on error
3944 * Invokes the delegate method @delegate with the parameters provided.
3946 * On failure @error will be set and you can't use the MonoObject*
3947 * result from the function.
3949 MonoObject*
3950 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3952 mono_error_init (error);
3953 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3956 static char **main_args = NULL;
3957 static int num_main_args = 0;
3960 * mono_runtime_get_main_args:
3962 * Returns: a MonoArray with the arguments passed to the main program
3964 MonoArray*
3965 mono_runtime_get_main_args (void)
3967 MONO_REQ_GC_UNSAFE_MODE;
3968 MonoError error;
3969 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3970 mono_error_assert_ok (&error);
3971 return result;
3975 * mono_runtime_get_main_args:
3976 * @error: set on error
3978 * Returns: a MonoArray with the arguments passed to the main
3979 * program. On failure returns NULL and sets @error.
3981 MonoArray*
3982 mono_runtime_get_main_args_checked (MonoError *error)
3984 MonoArray *res;
3985 int i;
3986 MonoDomain *domain = mono_domain_get ();
3988 mono_error_init (error);
3990 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3991 return_val_if_nok (error, NULL);
3993 for (i = 0; i < num_main_args; ++i)
3994 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3996 return res;
3999 static void
4000 free_main_args (void)
4002 MONO_REQ_GC_NEUTRAL_MODE;
4004 int i;
4006 for (i = 0; i < num_main_args; ++i)
4007 g_free (main_args [i]);
4008 g_free (main_args);
4009 num_main_args = 0;
4010 main_args = NULL;
4014 * mono_runtime_set_main_args:
4015 * @argc: number of arguments from the command line
4016 * @argv: array of strings from the command line
4018 * Set the command line arguments from an embedding application that doesn't otherwise call
4019 * mono_runtime_run_main ().
4022 mono_runtime_set_main_args (int argc, char* argv[])
4024 MONO_REQ_GC_NEUTRAL_MODE;
4026 int i;
4028 free_main_args ();
4029 main_args = g_new0 (char*, argc);
4030 num_main_args = argc;
4032 for (i = 0; i < argc; ++i) {
4033 gchar *utf8_arg;
4035 utf8_arg = mono_utf8_from_external (argv[i]);
4036 if (utf8_arg == NULL) {
4037 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4038 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4039 exit (-1);
4042 main_args [i] = utf8_arg;
4045 return 0;
4049 * Prepare an array of arguments in order to execute a standard Main()
4050 * method (argc/argv contains the executable name). This method also
4051 * sets the command line argument value needed by System.Environment.
4054 static MonoArray*
4055 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4057 MONO_REQ_GC_UNSAFE_MODE;
4059 MonoError error;
4060 int i;
4061 MonoArray *args = NULL;
4062 MonoDomain *domain = mono_domain_get ();
4063 gchar *utf8_fullpath;
4064 MonoMethodSignature *sig;
4066 g_assert (method != NULL);
4068 mono_thread_set_main (mono_thread_current ());
4070 main_args = g_new0 (char*, argc);
4071 num_main_args = argc;
4073 if (!g_path_is_absolute (argv [0])) {
4074 gchar *basename = g_path_get_basename (argv [0]);
4075 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4076 basename,
4077 NULL);
4079 utf8_fullpath = mono_utf8_from_external (fullpath);
4080 if(utf8_fullpath == NULL) {
4081 /* Printing the arg text will cause glib to
4082 * whinge about "Invalid UTF-8", but at least
4083 * its relevant, and shows the problem text
4084 * string.
4086 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4087 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4088 exit (-1);
4091 g_free (fullpath);
4092 g_free (basename);
4093 } else {
4094 utf8_fullpath = mono_utf8_from_external (argv[0]);
4095 if(utf8_fullpath == NULL) {
4096 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4097 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4098 exit (-1);
4102 main_args [0] = utf8_fullpath;
4104 for (i = 1; i < argc; ++i) {
4105 gchar *utf8_arg;
4107 utf8_arg=mono_utf8_from_external (argv[i]);
4108 if(utf8_arg==NULL) {
4109 /* Ditto the comment about Invalid UTF-8 here */
4110 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4111 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4112 exit (-1);
4115 main_args [i] = utf8_arg;
4117 argc--;
4118 argv++;
4120 sig = mono_method_signature (method);
4121 if (!sig) {
4122 g_print ("Unable to load Main method.\n");
4123 exit (-1);
4126 if (sig->param_count) {
4127 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4128 mono_error_assert_ok (&error);
4129 for (i = 0; i < argc; ++i) {
4130 /* The encodings should all work, given that
4131 * we've checked all these args for the
4132 * main_args array.
4134 gchar *str = mono_utf8_from_external (argv [i]);
4135 MonoString *arg = mono_string_new (domain, str);
4136 mono_array_setref (args, i, arg);
4137 g_free (str);
4139 } else {
4140 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4141 mono_error_assert_ok (&error);
4144 mono_assembly_set_main (method->klass->image->assembly);
4146 return args;
4150 * mono_runtime_run_main:
4151 * @method: the method to start the application with (usually Main)
4152 * @argc: number of arguments from the command line
4153 * @argv: array of strings from the command line
4154 * @exc: excetption results
4156 * Execute a standard Main() method (argc/argv contains the
4157 * executable name). This method also sets the command line argument value
4158 * needed by System.Environment.
4163 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4164 MonoObject **exc)
4166 MONO_REQ_GC_UNSAFE_MODE;
4168 MonoError error;
4169 MonoArray *args = prepare_run_main (method, argc, argv);
4170 int res;
4171 if (exc) {
4172 res = mono_runtime_try_exec_main (method, args, exc);
4173 } else {
4174 res = mono_runtime_exec_main_checked (method, args, &error);
4175 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4177 return res;
4181 * mono_runtime_run_main_checked:
4182 * @method: the method to start the application with (usually Main)
4183 * @argc: number of arguments from the command line
4184 * @argv: array of strings from the command line
4185 * @error: set on error
4187 * Execute a standard Main() method (argc/argv contains the
4188 * executable name). This method also sets the command line argument value
4189 * needed by System.Environment. On failure sets @error.
4194 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4195 MonoError *error)
4197 mono_error_init (error);
4198 MonoArray *args = prepare_run_main (method, argc, argv);
4199 return mono_runtime_exec_main_checked (method, args, error);
4203 * mono_runtime_try_run_main:
4204 * @method: the method to start the application with (usually Main)
4205 * @argc: number of arguments from the command line
4206 * @argv: array of strings from the command line
4207 * @exc: set if Main throws an exception
4208 * @error: set if Main can't be executed
4210 * Execute a standard Main() method (argc/argv contains the executable
4211 * name). This method also sets the command line argument value needed
4212 * by System.Environment. On failure sets @error if Main can't be
4213 * executed or @exc if it threw and exception.
4218 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4219 MonoObject **exc)
4221 g_assert (exc);
4222 MonoArray *args = prepare_run_main (method, argc, argv);
4223 return mono_runtime_try_exec_main (method, args, exc);
4227 static MonoObject*
4228 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4230 static MonoMethod *serialize_method;
4232 MonoError error;
4233 void *params [1];
4234 MonoObject *array;
4236 if (!serialize_method) {
4237 MonoClass *klass = mono_class_get_remoting_services_class ();
4238 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4241 if (!serialize_method) {
4242 *failure = TRUE;
4243 return NULL;
4246 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4248 params [0] = obj;
4249 *exc = NULL;
4251 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4252 if (*exc == NULL && !mono_error_ok (&error))
4253 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4254 else
4255 mono_error_cleanup (&error);
4257 if (*exc)
4258 *failure = TRUE;
4260 return array;
4263 static MonoObject*
4264 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4266 MONO_REQ_GC_UNSAFE_MODE;
4268 static MonoMethod *deserialize_method;
4270 MonoError error;
4271 void *params [1];
4272 MonoObject *result;
4274 if (!deserialize_method) {
4275 MonoClass *klass = mono_class_get_remoting_services_class ();
4276 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4278 if (!deserialize_method) {
4279 *failure = TRUE;
4280 return NULL;
4283 params [0] = obj;
4284 *exc = NULL;
4286 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4287 if (*exc == NULL && !mono_error_ok (&error))
4288 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4289 else
4290 mono_error_cleanup (&error);
4292 if (*exc)
4293 *failure = TRUE;
4295 return result;
4298 #ifndef DISABLE_REMOTING
4299 static MonoObject*
4300 make_transparent_proxy (MonoObject *obj, MonoError *error)
4302 MONO_REQ_GC_UNSAFE_MODE;
4304 static MonoMethod *get_proxy_method;
4306 MonoDomain *domain = mono_domain_get ();
4307 MonoRealProxy *real_proxy;
4308 MonoReflectionType *reflection_type;
4309 MonoTransparentProxy *transparent_proxy;
4311 mono_error_init (error);
4313 if (!get_proxy_method)
4314 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4316 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4318 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4319 return_val_if_nok (error, NULL);
4320 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4321 return_val_if_nok (error, NULL);
4323 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4324 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4326 MonoObject *exc = NULL;
4328 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4329 if (exc != NULL && is_ok (error))
4330 mono_error_set_exception_instance (error, (MonoException*)exc);
4332 return (MonoObject*) transparent_proxy;
4334 #endif /* DISABLE_REMOTING */
4337 * mono_object_xdomain_representation
4338 * @obj: an object
4339 * @target_domain: a domain
4340 * @error: set on error.
4342 * Creates a representation of obj in the domain target_domain. This
4343 * is either a copy of obj arrived through via serialization and
4344 * deserialization or a proxy, depending on whether the object is
4345 * serializable or marshal by ref. obj must not be in target_domain.
4347 * If the object cannot be represented in target_domain, NULL is
4348 * returned and @error is set appropriately.
4350 MonoObject*
4351 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4353 MONO_REQ_GC_UNSAFE_MODE;
4355 mono_error_init (error);
4356 MonoObject *deserialized = NULL;
4358 #ifndef DISABLE_REMOTING
4359 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4360 deserialized = make_transparent_proxy (obj, error);
4362 else
4363 #endif
4365 gboolean failure = FALSE;
4366 MonoDomain *domain = mono_domain_get ();
4367 MonoObject *serialized;
4368 MonoObject *exc = NULL;
4370 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4371 serialized = serialize_object (obj, &failure, &exc);
4372 mono_domain_set_internal_with_options (target_domain, FALSE);
4373 if (!failure)
4374 deserialized = deserialize_object (serialized, &failure, &exc);
4375 if (domain != target_domain)
4376 mono_domain_set_internal_with_options (domain, FALSE);
4377 if (failure)
4378 mono_error_set_exception_instance (error, (MonoException*)exc);
4381 return deserialized;
4384 /* Used in call_unhandled_exception_delegate */
4385 static MonoObject *
4386 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4388 MONO_REQ_GC_UNSAFE_MODE;
4390 mono_error_init (error);
4391 MonoClass *klass;
4392 gpointer args [2];
4393 MonoMethod *method = NULL;
4394 MonoBoolean is_terminating = TRUE;
4395 MonoObject *obj;
4397 klass = mono_class_get_unhandled_exception_event_args_class ();
4398 mono_class_init (klass);
4400 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4401 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4402 g_assert (method);
4404 args [0] = exc;
4405 args [1] = &is_terminating;
4407 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4408 return_val_if_nok (error, NULL);
4410 mono_runtime_invoke_checked (method, obj, args, error);
4411 return_val_if_nok (error, NULL);
4413 return obj;
4416 /* Used in mono_unhandled_exception */
4417 static void
4418 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4419 MONO_REQ_GC_UNSAFE_MODE;
4421 MonoError error;
4422 MonoObject *e = NULL;
4423 gpointer pa [2];
4424 MonoDomain *current_domain = mono_domain_get ();
4426 if (domain != current_domain)
4427 mono_domain_set_internal_with_options (domain, FALSE);
4429 g_assert (domain == mono_object_domain (domain->domain));
4431 if (mono_object_domain (exc) != domain) {
4433 exc = mono_object_xdomain_representation (exc, domain, &error);
4434 if (!exc) {
4435 if (!is_ok (&error)) {
4436 MonoError inner_error;
4437 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4438 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4439 mono_error_assert_ok (&inner_error);
4440 } else {
4441 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4442 "System.Runtime.Serialization", "SerializationException",
4443 "Could not serialize unhandled exception.");
4447 g_assert (mono_object_domain (exc) == domain);
4449 pa [0] = domain->domain;
4450 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4451 mono_error_assert_ok (&error);
4452 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4453 if (!is_ok (&error)) {
4454 if (e == NULL)
4455 e = (MonoObject*)mono_error_convert_to_exception (&error);
4456 else
4457 mono_error_cleanup (&error);
4460 if (domain != current_domain)
4461 mono_domain_set_internal_with_options (current_domain, FALSE);
4463 if (e) {
4464 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4465 if (!mono_error_ok (&error)) {
4466 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4467 mono_error_cleanup (&error);
4468 } else {
4469 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4470 g_free (msg);
4475 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4478 * mono_runtime_unhandled_exception_policy_set:
4479 * @policy: the new policy
4481 * This is a VM internal routine.
4483 * Sets the runtime policy for handling unhandled exceptions.
4485 void
4486 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4487 runtime_unhandled_exception_policy = policy;
4491 * mono_runtime_unhandled_exception_policy_get:
4493 * This is a VM internal routine.
4495 * Gets the runtime policy for handling unhandled exceptions.
4497 MonoRuntimeUnhandledExceptionPolicy
4498 mono_runtime_unhandled_exception_policy_get (void) {
4499 return runtime_unhandled_exception_policy;
4503 * mono_unhandled_exception:
4504 * @exc: exception thrown
4506 * This is a VM internal routine.
4508 * We call this function when we detect an unhandled exception
4509 * in the default domain.
4511 * It invokes the * UnhandledException event in AppDomain or prints
4512 * a warning to the console
4514 void
4515 mono_unhandled_exception (MonoObject *exc)
4517 MONO_REQ_GC_UNSAFE_MODE;
4519 MonoError error;
4520 MonoClassField *field;
4521 MonoDomain *current_domain, *root_domain;
4522 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4524 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4525 return;
4527 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4528 g_assert (field);
4530 current_domain = mono_domain_get ();
4531 root_domain = mono_get_root_domain ();
4533 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4534 mono_error_assert_ok (&error);
4535 if (current_domain != root_domain) {
4536 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4537 mono_error_assert_ok (&error);
4540 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4541 mono_print_unhandled_exception (exc);
4542 } else {
4543 /* unhandled exception callbacks must not be aborted */
4544 mono_threads_begin_abort_protected_block ();
4545 if (root_appdomain_delegate)
4546 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4547 if (current_appdomain_delegate)
4548 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4549 mono_threads_end_abort_protected_block ();
4552 /* set exitcode only if we will abort the process */
4553 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4554 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4556 mono_environment_exitcode_set (1);
4561 * mono_runtime_exec_managed_code:
4562 * @domain: Application domain
4563 * @main_func: function to invoke from the execution thread
4564 * @main_args: parameter to the main_func
4566 * Launch a new thread to execute a function
4568 * main_func is called back from the thread with main_args as the
4569 * parameter. The callback function is expected to start Main()
4570 * eventually. This function then waits for all managed threads to
4571 * finish.
4572 * It is not necesseray anymore to execute managed code in a subthread,
4573 * so this function should not be used anymore by default: just
4574 * execute the code and then call mono_thread_manage ().
4576 void
4577 mono_runtime_exec_managed_code (MonoDomain *domain,
4578 MonoMainThreadFunc main_func,
4579 gpointer main_args)
4581 MonoError error;
4582 mono_thread_create_checked (domain, main_func, main_args, &error);
4583 mono_error_assert_ok (&error);
4585 mono_thread_manage ();
4588 static void
4589 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4591 MonoInternalThread* thread = mono_thread_internal_current ();
4592 MonoCustomAttrInfo* cinfo;
4593 gboolean has_stathread_attribute;
4595 if (!domain->entry_assembly) {
4596 gchar *str;
4597 MonoAssembly *assembly;
4599 assembly = method->klass->image->assembly;
4600 domain->entry_assembly = assembly;
4601 /* Domains created from another domain already have application_base and configuration_file set */
4602 if (domain->setup->application_base == NULL) {
4603 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4606 if (domain->setup->configuration_file == NULL) {
4607 str = g_strconcat (assembly->image->name, ".config", NULL);
4608 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4609 g_free (str);
4610 mono_domain_set_options_from_config (domain);
4614 MonoError cattr_error;
4615 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4616 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4617 if (cinfo) {
4618 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4619 if (!cinfo->cached)
4620 mono_custom_attrs_free (cinfo);
4621 } else {
4622 has_stathread_attribute = FALSE;
4624 if (has_stathread_attribute) {
4625 thread->apartment_state = ThreadApartmentState_STA;
4626 } else {
4627 thread->apartment_state = ThreadApartmentState_MTA;
4629 mono_thread_init_apartment_state ();
4633 static int
4634 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4636 MONO_REQ_GC_UNSAFE_MODE;
4638 gpointer pa [1];
4639 int rval;
4641 mono_error_init (error);
4642 g_assert (args);
4644 pa [0] = args;
4646 /* FIXME: check signature of method */
4647 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4648 MonoObject *res;
4649 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4650 if (is_ok (error))
4651 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4652 else
4653 rval = -1;
4654 mono_environment_exitcode_set (rval);
4655 } else {
4656 mono_runtime_invoke_checked (method, NULL, pa, error);
4658 if (is_ok (error))
4659 rval = 0;
4660 else {
4661 rval = -1;
4664 return rval;
4667 static int
4668 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4670 MONO_REQ_GC_UNSAFE_MODE;
4672 gpointer pa [1];
4673 int rval;
4675 g_assert (args);
4676 g_assert (exc);
4678 pa [0] = args;
4680 /* FIXME: check signature of method */
4681 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4682 MonoError inner_error;
4683 MonoObject *res;
4684 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4685 if (*exc == NULL && !mono_error_ok (&inner_error))
4686 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4687 else
4688 mono_error_cleanup (&inner_error);
4690 if (*exc == NULL)
4691 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4692 else
4693 rval = -1;
4695 mono_environment_exitcode_set (rval);
4696 } else {
4697 MonoError inner_error;
4698 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4699 if (*exc == NULL && !mono_error_ok (&inner_error))
4700 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4701 else
4702 mono_error_cleanup (&inner_error);
4704 if (*exc == NULL)
4705 rval = 0;
4706 else {
4707 /* If the return type of Main is void, only
4708 * set the exitcode if an exception was thrown
4709 * (we don't want to blow away an
4710 * explicitly-set exit code)
4712 rval = -1;
4713 mono_environment_exitcode_set (rval);
4717 return rval;
4721 * Execute a standard Main() method (args doesn't contain the
4722 * executable name).
4725 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4727 MonoError error;
4728 prepare_thread_to_exec_main (mono_object_domain (args), method);
4729 if (exc) {
4730 int rval = do_try_exec_main (method, args, exc);
4731 return rval;
4732 } else {
4733 int rval = do_exec_main_checked (method, args, &error);
4734 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4735 return rval;
4740 * Execute a standard Main() method (args doesn't contain the
4741 * executable name).
4743 * On failure sets @error
4746 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4748 mono_error_init (error);
4749 prepare_thread_to_exec_main (mono_object_domain (args), method);
4750 return do_exec_main_checked (method, args, error);
4754 * Execute a standard Main() method (args doesn't contain the
4755 * executable name).
4757 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4760 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4762 prepare_thread_to_exec_main (mono_object_domain (args), method);
4763 return do_try_exec_main (method, args, exc);
4768 /** invoke_array_extract_argument:
4769 * @params: array of arguments to the method.
4770 * @i: the index of the argument to extract.
4771 * @t: ith type from the method signature.
4772 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4773 * @error: set on error.
4775 * Given an array of method arguments, return the ith one using the corresponding type
4776 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4778 * On failure sets @error and returns NULL.
4780 static gpointer
4781 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4783 MonoType *t_orig = t;
4784 gpointer result = NULL;
4785 mono_error_init (error);
4786 again:
4787 switch (t->type) {
4788 case MONO_TYPE_U1:
4789 case MONO_TYPE_I1:
4790 case MONO_TYPE_BOOLEAN:
4791 case MONO_TYPE_U2:
4792 case MONO_TYPE_I2:
4793 case MONO_TYPE_CHAR:
4794 case MONO_TYPE_U:
4795 case MONO_TYPE_I:
4796 case MONO_TYPE_U4:
4797 case MONO_TYPE_I4:
4798 case MONO_TYPE_U8:
4799 case MONO_TYPE_I8:
4800 case MONO_TYPE_R4:
4801 case MONO_TYPE_R8:
4802 case MONO_TYPE_VALUETYPE:
4803 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4804 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4805 result = mono_array_get (params, MonoObject*, i);
4806 if (t->byref)
4807 *has_byref_nullables = TRUE;
4808 } else {
4809 /* MS seems to create the objects if a null is passed in */
4810 if (!mono_array_get (params, MonoObject*, i)) {
4811 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4812 return_val_if_nok (error, NULL);
4813 mono_array_setref (params, i, o);
4816 if (t->byref) {
4818 * We can't pass the unboxed vtype byref to the callee, since
4819 * that would mean the callee would be able to modify boxed
4820 * primitive types. So we (and MS) make a copy of the boxed
4821 * object, pass that to the callee, and replace the original
4822 * boxed object in the arg array with the copy.
4824 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4825 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4826 return_val_if_nok (error, NULL);
4827 mono_array_setref (params, i, copy);
4830 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4832 break;
4833 case MONO_TYPE_STRING:
4834 case MONO_TYPE_OBJECT:
4835 case MONO_TYPE_CLASS:
4836 case MONO_TYPE_ARRAY:
4837 case MONO_TYPE_SZARRAY:
4838 if (t->byref)
4839 result = mono_array_addr (params, MonoObject*, i);
4840 // FIXME: I need to check this code path
4841 else
4842 result = mono_array_get (params, MonoObject*, i);
4843 break;
4844 case MONO_TYPE_GENERICINST:
4845 if (t->byref)
4846 t = &t->data.generic_class->container_class->this_arg;
4847 else
4848 t = &t->data.generic_class->container_class->byval_arg;
4849 goto again;
4850 case MONO_TYPE_PTR: {
4851 MonoObject *arg;
4853 /* The argument should be an IntPtr */
4854 arg = mono_array_get (params, MonoObject*, i);
4855 if (arg == NULL) {
4856 result = NULL;
4857 } else {
4858 g_assert (arg->vtable->klass == mono_defaults.int_class);
4859 result = ((MonoIntPtr*)arg)->m_value;
4861 break;
4863 default:
4864 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4866 return result;
4869 * mono_runtime_invoke_array:
4870 * @method: method to invoke
4871 * @obJ: object instance
4872 * @params: arguments to the method
4873 * @exc: exception information.
4875 * Invokes the method represented by @method on the object @obj.
4877 * obj is the 'this' pointer, it should be NULL for static
4878 * methods, a MonoObject* for object instances and a pointer to
4879 * the value type for value types.
4881 * The params array contains the arguments to the method with the
4882 * same convention: MonoObject* pointers for object instances and
4883 * pointers to the value type otherwise. The _invoke_array
4884 * variant takes a C# object[] as the params argument (MonoArray
4885 * *params): in this case the value types are boxed inside the
4886 * respective reference representation.
4888 * From unmanaged code you'll usually use the
4889 * mono_runtime_invoke_checked() variant.
4891 * Note that this function doesn't handle virtual methods for
4892 * you, it will exec the exact method you pass: we still need to
4893 * expose a function to lookup the derived class implementation
4894 * of a virtual method (there are examples of this in the code,
4895 * though).
4897 * You can pass NULL as the exc argument if you don't want to
4898 * catch exceptions, otherwise, *exc will be set to the exception
4899 * thrown, if any. if an exception is thrown, you can't use the
4900 * MonoObject* result from the function.
4902 * If the method returns a value type, it is boxed in an object
4903 * reference.
4905 MonoObject*
4906 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4907 MonoObject **exc)
4909 MonoError error;
4910 if (exc) {
4911 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4912 if (*exc) {
4913 mono_error_cleanup (&error);
4914 return NULL;
4915 } else {
4916 if (!is_ok (&error))
4917 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4918 return result;
4920 } else {
4921 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4922 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4923 return result;
4928 * mono_runtime_invoke_array_checked:
4929 * @method: method to invoke
4930 * @obJ: object instance
4931 * @params: arguments to the method
4932 * @error: set on failure.
4934 * Invokes the method represented by @method on the object @obj.
4936 * obj is the 'this' pointer, it should be NULL for static
4937 * methods, a MonoObject* for object instances and a pointer to
4938 * the value type for value types.
4940 * The params array contains the arguments to the method with the
4941 * same convention: MonoObject* pointers for object instances and
4942 * pointers to the value type otherwise. The _invoke_array
4943 * variant takes a C# object[] as the params argument (MonoArray
4944 * *params): in this case the value types are boxed inside the
4945 * respective reference representation.
4947 * From unmanaged code you'll usually use the
4948 * mono_runtime_invoke_checked() variant.
4950 * Note that this function doesn't handle virtual methods for
4951 * you, it will exec the exact method you pass: we still need to
4952 * expose a function to lookup the derived class implementation
4953 * of a virtual method (there are examples of this in the code,
4954 * though).
4956 * On failure or exception, @error will be set. In that case, you
4957 * can't use the MonoObject* result from the function.
4959 * If the method returns a value type, it is boxed in an object
4960 * reference.
4962 MonoObject*
4963 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4964 MonoError *error)
4966 mono_error_init (error);
4967 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4971 * mono_runtime_try_invoke_array:
4972 * @method: method to invoke
4973 * @obJ: object instance
4974 * @params: arguments to the method
4975 * @exc: exception information.
4976 * @error: set on failure.
4978 * Invokes the method represented by @method on the object @obj.
4980 * obj is the 'this' pointer, it should be NULL for static
4981 * methods, a MonoObject* for object instances and a pointer to
4982 * the value type for value types.
4984 * The params array contains the arguments to the method with the
4985 * same convention: MonoObject* pointers for object instances and
4986 * pointers to the value type otherwise. The _invoke_array
4987 * variant takes a C# object[] as the params argument (MonoArray
4988 * *params): in this case the value types are boxed inside the
4989 * respective reference representation.
4991 * From unmanaged code you'll usually use the
4992 * mono_runtime_invoke_checked() variant.
4994 * Note that this function doesn't handle virtual methods for
4995 * you, it will exec the exact method you pass: we still need to
4996 * expose a function to lookup the derived class implementation
4997 * of a virtual method (there are examples of this in the code,
4998 * though).
5000 * You can pass NULL as the exc argument if you don't want to catch
5001 * exceptions, otherwise, *exc will be set to the exception thrown, if
5002 * any. On other failures, @error will be set. If an exception is
5003 * thrown or there's an error, you can't use the MonoObject* result
5004 * from the function.
5006 * If the method returns a value type, it is boxed in an object
5007 * reference.
5009 MonoObject*
5010 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5011 MonoObject **exc, MonoError *error)
5013 MONO_REQ_GC_UNSAFE_MODE;
5015 mono_error_init (error);
5017 MonoMethodSignature *sig = mono_method_signature (method);
5018 gpointer *pa = NULL;
5019 MonoObject *res;
5020 int i;
5021 gboolean has_byref_nullables = FALSE;
5023 if (NULL != params) {
5024 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5025 for (i = 0; i < mono_array_length (params); i++) {
5026 MonoType *t = sig->params [i];
5027 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5028 return_val_if_nok (error, NULL);
5032 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5033 void *o = obj;
5035 if (mono_class_is_nullable (method->klass)) {
5036 /* Need to create a boxed vtype instead */
5037 g_assert (!obj);
5039 if (!params)
5040 return NULL;
5041 else {
5042 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5046 if (!obj) {
5047 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5048 mono_error_assert_ok (error);
5049 g_assert (obj); /*maybe we should raise a TLE instead?*/
5050 #ifndef DISABLE_REMOTING
5051 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5052 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5054 #endif
5055 if (method->klass->valuetype)
5056 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5057 else
5058 o = obj;
5059 } else if (method->klass->valuetype) {
5060 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5061 return_val_if_nok (error, NULL);
5064 if (exc) {
5065 mono_runtime_try_invoke (method, o, pa, exc, error);
5066 } else {
5067 mono_runtime_invoke_checked (method, o, pa, error);
5070 return (MonoObject *)obj;
5071 } else {
5072 if (mono_class_is_nullable (method->klass)) {
5073 MonoObject *nullable;
5075 /* Convert the unboxed vtype into a Nullable structure */
5076 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5077 return_val_if_nok (error, NULL);
5079 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5080 return_val_if_nok (error, NULL);
5081 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5082 obj = mono_object_unbox (nullable);
5085 /* obj must be already unboxed if needed */
5086 if (exc) {
5087 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5088 } else {
5089 res = mono_runtime_invoke_checked (method, obj, pa, error);
5091 return_val_if_nok (error, NULL);
5093 if (sig->ret->type == MONO_TYPE_PTR) {
5094 MonoClass *pointer_class;
5095 static MonoMethod *box_method;
5096 void *box_args [2];
5097 MonoObject *box_exc;
5100 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5101 * convert it to a Pointer object.
5103 pointer_class = mono_class_get_pointer_class ();
5104 if (!box_method)
5105 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5107 g_assert (res->vtable->klass == mono_defaults.int_class);
5108 box_args [0] = ((MonoIntPtr*)res)->m_value;
5109 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5110 return_val_if_nok (error, NULL);
5112 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5113 g_assert (box_exc == NULL);
5114 mono_error_assert_ok (error);
5117 if (has_byref_nullables) {
5119 * The runtime invoke wrapper already converted byref nullables back,
5120 * and stored them in pa, we just need to copy them back to the
5121 * managed array.
5123 for (i = 0; i < mono_array_length (params); i++) {
5124 MonoType *t = sig->params [i];
5126 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5127 mono_array_setref (params, i, pa [i]);
5131 return res;
5136 * mono_object_new:
5137 * @klass: the class of the object that we want to create
5139 * Returns: a newly created object whose definition is
5140 * looked up using @klass. This will not invoke any constructors,
5141 * so the consumer of this routine has to invoke any constructors on
5142 * its own to initialize the object.
5144 * It returns NULL on failure.
5146 MonoObject *
5147 mono_object_new (MonoDomain *domain, MonoClass *klass)
5149 MONO_REQ_GC_UNSAFE_MODE;
5151 MonoError error;
5153 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5155 mono_error_cleanup (&error);
5156 return result;
5159 MonoObject *
5160 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5162 MONO_REQ_GC_UNSAFE_MODE;
5164 MonoError error;
5166 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5168 mono_error_set_pending_exception (&error);
5169 return result;
5173 * mono_object_new_checked:
5174 * @klass: the class of the object that we want to create
5175 * @error: set on error
5177 * Returns: a newly created object whose definition is
5178 * looked up using @klass. This will not invoke any constructors,
5179 * so the consumer of this routine has to invoke any constructors on
5180 * its own to initialize the object.
5182 * It returns NULL on failure and sets @error.
5184 MonoObject *
5185 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5187 MONO_REQ_GC_UNSAFE_MODE;
5189 MonoVTable *vtable;
5191 vtable = mono_class_vtable (domain, klass);
5192 g_assert (vtable); /* FIXME don't swallow the error */
5194 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5195 return o;
5199 * mono_object_new_pinned:
5201 * Same as mono_object_new, but the returned object will be pinned.
5202 * For SGEN, these objects will only be freed at appdomain unload.
5204 MonoObject *
5205 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5207 MONO_REQ_GC_UNSAFE_MODE;
5209 MonoVTable *vtable;
5211 mono_error_init (error);
5213 vtable = mono_class_vtable (domain, klass);
5214 g_assert (vtable); /* FIXME don't swallow the error */
5216 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5218 if (G_UNLIKELY (!o))
5219 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5220 else if (G_UNLIKELY (vtable->klass->has_finalize))
5221 mono_object_register_finalizer (o);
5223 return o;
5227 * mono_object_new_specific:
5228 * @vtable: the vtable of the object that we want to create
5230 * Returns: A newly created object with class and domain specified
5231 * by @vtable
5233 MonoObject *
5234 mono_object_new_specific (MonoVTable *vtable)
5236 MonoError error;
5237 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5238 mono_error_cleanup (&error);
5240 return o;
5243 MonoObject *
5244 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5246 MONO_REQ_GC_UNSAFE_MODE;
5248 MonoObject *o;
5250 mono_error_init (error);
5252 /* check for is_com_object for COM Interop */
5253 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5255 gpointer pa [1];
5256 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5258 if (im == NULL) {
5259 MonoClass *klass = mono_class_get_activation_services_class ();
5261 if (!klass->inited)
5262 mono_class_init (klass);
5264 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5265 if (!im) {
5266 mono_error_set_not_supported (error, "Linked away.");
5267 return NULL;
5269 vtable->domain->create_proxy_for_type_method = im;
5272 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5273 if (!mono_error_ok (error))
5274 return NULL;
5276 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5277 if (!mono_error_ok (error))
5278 return NULL;
5280 if (o != NULL)
5281 return o;
5284 return mono_object_new_alloc_specific_checked (vtable, error);
5287 MonoObject *
5288 ves_icall_object_new_specific (MonoVTable *vtable)
5290 MonoError error;
5291 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5292 mono_error_set_pending_exception (&error);
5294 return o;
5298 * mono_object_new_alloc_specific:
5299 * @vtable: virtual table for the object.
5301 * This function allocates a new `MonoObject` with the type derived
5302 * from the @vtable information. If the class of this object has a
5303 * finalizer, then the object will be tracked for finalization.
5305 * This method might raise an exception on errors. Use the
5306 * `mono_object_new_fast_checked` method if you want to manually raise
5307 * the exception.
5309 * Returns: the allocated object.
5311 MonoObject *
5312 mono_object_new_alloc_specific (MonoVTable *vtable)
5314 MonoError error;
5315 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5316 mono_error_cleanup (&error);
5318 return o;
5322 * mono_object_new_alloc_specific_checked:
5323 * @vtable: virtual table for the object.
5324 * @error: holds the error return value.
5326 * This function allocates a new `MonoObject` with the type derived
5327 * from the @vtable information. If the class of this object has a
5328 * finalizer, then the object will be tracked for finalization.
5330 * If there is not enough memory, the @error parameter will be set
5331 * and will contain a user-visible message with the amount of bytes
5332 * that were requested.
5334 * Returns: the allocated object, or NULL if there is not enough memory
5337 MonoObject *
5338 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5340 MONO_REQ_GC_UNSAFE_MODE;
5342 MonoObject *o;
5344 mono_error_init (error);
5346 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5348 if (G_UNLIKELY (!o))
5349 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5350 else if (G_UNLIKELY (vtable->klass->has_finalize))
5351 mono_object_register_finalizer (o);
5353 return o;
5357 * mono_object_new_fast:
5358 * @vtable: virtual table for the object.
5360 * This function allocates a new `MonoObject` with the type derived
5361 * from the @vtable information. The returned object is not tracked
5362 * for finalization. If your object implements a finalizer, you should
5363 * use `mono_object_new_alloc_specific` instead.
5365 * This method might raise an exception on errors. Use the
5366 * `mono_object_new_fast_checked` method if you want to manually raise
5367 * the exception.
5369 * Returns: the allocated object.
5371 MonoObject*
5372 mono_object_new_fast (MonoVTable *vtable)
5374 MonoError error;
5375 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5376 mono_error_cleanup (&error);
5378 return o;
5382 * mono_object_new_fast_checked:
5383 * @vtable: virtual table for the object.
5384 * @error: holds the error return value.
5386 * This function allocates a new `MonoObject` with the type derived
5387 * from the @vtable information. The returned object is not tracked
5388 * for finalization. If your object implements a finalizer, you should
5389 * use `mono_object_new_alloc_specific_checked` instead.
5391 * If there is not enough memory, the @error parameter will be set
5392 * and will contain a user-visible message with the amount of bytes
5393 * that were requested.
5395 * Returns: the allocated object, or NULL if there is not enough memory
5398 MonoObject*
5399 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5401 MONO_REQ_GC_UNSAFE_MODE;
5403 MonoObject *o;
5405 mono_error_init (error);
5407 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5409 if (G_UNLIKELY (!o))
5410 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5412 return o;
5415 MonoObject *
5416 ves_icall_object_new_fast (MonoVTable *vtable)
5418 MonoError error;
5419 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5420 mono_error_set_pending_exception (&error);
5422 return o;
5425 MonoObject*
5426 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5428 MONO_REQ_GC_UNSAFE_MODE;
5430 MonoObject *o;
5432 mono_error_init (error);
5434 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5436 if (G_UNLIKELY (!o))
5437 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5438 else if (G_UNLIKELY (vtable->klass->has_finalize))
5439 mono_object_register_finalizer (o);
5441 return o;
5445 * mono_class_get_allocation_ftn:
5446 * @vtable: vtable
5447 * @for_box: the object will be used for boxing
5448 * @pass_size_in_words:
5450 * Return the allocation function appropriate for the given class.
5453 void*
5454 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5456 MONO_REQ_GC_NEUTRAL_MODE;
5458 *pass_size_in_words = FALSE;
5460 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5461 return ves_icall_object_new_specific;
5463 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5465 return ves_icall_object_new_fast;
5468 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5469 * of the overhead of parameter passing.
5472 *pass_size_in_words = TRUE;
5473 #ifdef GC_REDIRECT_TO_LOCAL
5474 return GC_local_gcj_fast_malloc;
5475 #else
5476 return GC_gcj_fast_malloc;
5477 #endif
5481 return ves_icall_object_new_specific;
5485 * mono_object_new_from_token:
5486 * @image: Context where the type_token is hosted
5487 * @token: a token of the type that we want to create
5489 * Returns: A newly created object whose definition is
5490 * looked up using @token in the @image image
5492 MonoObject *
5493 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5495 MONO_REQ_GC_UNSAFE_MODE;
5497 MonoError error;
5498 MonoObject *result;
5499 MonoClass *klass;
5501 klass = mono_class_get_checked (image, token, &error);
5502 mono_error_assert_ok (&error);
5504 result = mono_object_new_checked (domain, klass, &error);
5506 mono_error_cleanup (&error);
5507 return result;
5513 * mono_object_clone:
5514 * @obj: the object to clone
5516 * Returns: A newly created object who is a shallow copy of @obj
5518 MonoObject *
5519 mono_object_clone (MonoObject *obj)
5521 MonoError error;
5522 MonoObject *o = mono_object_clone_checked (obj, &error);
5523 mono_error_cleanup (&error);
5525 return o;
5528 MonoObject *
5529 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5531 MONO_REQ_GC_UNSAFE_MODE;
5533 MonoObject *o;
5534 int size;
5536 mono_error_init (error);
5538 size = obj->vtable->klass->instance_size;
5540 if (obj->vtable->klass->rank)
5541 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5543 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5545 if (G_UNLIKELY (!o)) {
5546 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5547 return NULL;
5550 /* If the object doesn't contain references this will do a simple memmove. */
5551 mono_gc_wbarrier_object_copy (o, obj);
5553 if (obj->vtable->klass->has_finalize)
5554 mono_object_register_finalizer (o);
5555 return o;
5559 * mono_array_full_copy:
5560 * @src: source array to copy
5561 * @dest: destination array
5563 * Copies the content of one array to another with exactly the same type and size.
5565 void
5566 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5568 MONO_REQ_GC_UNSAFE_MODE;
5570 uintptr_t size;
5571 MonoClass *klass = src->obj.vtable->klass;
5573 g_assert (klass == dest->obj.vtable->klass);
5575 size = mono_array_length (src);
5576 g_assert (size == mono_array_length (dest));
5577 size *= mono_array_element_size (klass);
5578 #ifdef HAVE_SGEN_GC
5579 if (klass->element_class->valuetype) {
5580 if (klass->element_class->has_references)
5581 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5582 else
5583 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5584 } else {
5585 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5587 #else
5588 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5589 #endif
5593 * mono_array_clone_in_domain:
5594 * @domain: the domain in which the array will be cloned into
5595 * @array: the array to clone
5596 * @error: set on error
5598 * This routine returns a copy of the array that is hosted on the
5599 * specified MonoDomain. On failure returns NULL and sets @error.
5601 MonoArray*
5602 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5604 MONO_REQ_GC_UNSAFE_MODE;
5606 MonoArray *o;
5607 uintptr_t size, i;
5608 uintptr_t *sizes;
5609 MonoClass *klass = array->obj.vtable->klass;
5611 mono_error_init (error);
5613 if (array->bounds == NULL) {
5614 size = mono_array_length (array);
5615 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5616 return_val_if_nok (error, NULL);
5618 size *= mono_array_element_size (klass);
5619 #ifdef HAVE_SGEN_GC
5620 if (klass->element_class->valuetype) {
5621 if (klass->element_class->has_references)
5622 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5623 else
5624 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5625 } else {
5626 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5628 #else
5629 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5630 #endif
5631 return o;
5634 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5635 size = mono_array_element_size (klass);
5636 for (i = 0; i < klass->rank; ++i) {
5637 sizes [i] = array->bounds [i].length;
5638 size *= array->bounds [i].length;
5639 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5641 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5642 return_val_if_nok (error, NULL);
5643 #ifdef HAVE_SGEN_GC
5644 if (klass->element_class->valuetype) {
5645 if (klass->element_class->has_references)
5646 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5647 else
5648 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5649 } else {
5650 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5652 #else
5653 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5654 #endif
5656 return o;
5660 * mono_array_clone:
5661 * @array: the array to clone
5663 * Returns: A newly created array who is a shallow copy of @array
5665 MonoArray*
5666 mono_array_clone (MonoArray *array)
5668 MONO_REQ_GC_UNSAFE_MODE;
5670 MonoError error;
5671 MonoArray *result = mono_array_clone_checked (array, &error);
5672 mono_error_cleanup (&error);
5673 return result;
5677 * mono_array_clone_checked:
5678 * @array: the array to clone
5679 * @error: set on error
5681 * Returns: A newly created array who is a shallow copy of @array. On
5682 * failure returns NULL and sets @error.
5684 MonoArray*
5685 mono_array_clone_checked (MonoArray *array, MonoError *error)
5688 MONO_REQ_GC_UNSAFE_MODE;
5689 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5692 /* helper macros to check for overflow when calculating the size of arrays */
5693 #ifdef MONO_BIG_ARRAYS
5694 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5695 #define MYGUINT_MAX MYGUINT64_MAX
5696 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5697 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5698 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5699 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5700 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5701 #else
5702 #define MYGUINT32_MAX 4294967295U
5703 #define MYGUINT_MAX MYGUINT32_MAX
5704 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5705 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5706 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5707 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5708 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5709 #endif
5711 gboolean
5712 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5714 MONO_REQ_GC_NEUTRAL_MODE;
5716 uintptr_t byte_len;
5718 byte_len = mono_array_element_size (klass);
5719 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5720 return FALSE;
5721 byte_len *= len;
5722 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5723 return FALSE;
5724 byte_len += MONO_SIZEOF_MONO_ARRAY;
5726 *res = byte_len;
5728 return TRUE;
5732 * mono_array_new_full:
5733 * @domain: domain where the object is created
5734 * @array_class: array class
5735 * @lengths: lengths for each dimension in the array
5736 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5738 * This routine creates a new array objects with the given dimensions,
5739 * lower bounds and type.
5741 MonoArray*
5742 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5744 MonoError error;
5745 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5746 mono_error_cleanup (&error);
5748 return array;
5751 MonoArray*
5752 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5754 MONO_REQ_GC_UNSAFE_MODE;
5756 uintptr_t byte_len = 0, len, bounds_size;
5757 MonoObject *o;
5758 MonoArray *array;
5759 MonoArrayBounds *bounds;
5760 MonoVTable *vtable;
5761 int i;
5763 mono_error_init (error);
5765 if (!array_class->inited)
5766 mono_class_init (array_class);
5768 len = 1;
5770 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5771 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5772 len = lengths [0];
5773 if (len > MONO_ARRAY_MAX_INDEX) {
5774 mono_error_set_generic_error (error, "System", "OverflowException", "");
5775 return NULL;
5777 bounds_size = 0;
5778 } else {
5779 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5781 for (i = 0; i < array_class->rank; ++i) {
5782 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5783 mono_error_set_generic_error (error, "System", "OverflowException", "");
5784 return NULL;
5786 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5787 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5788 return NULL;
5790 len *= lengths [i];
5794 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5795 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5796 return NULL;
5799 if (bounds_size) {
5800 /* align */
5801 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5802 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5803 return NULL;
5805 byte_len = (byte_len + 3) & ~3;
5806 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5807 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5808 return NULL;
5810 byte_len += bounds_size;
5813 * Following three lines almost taken from mono_object_new ():
5814 * they need to be kept in sync.
5816 vtable = mono_class_vtable_full (domain, array_class, error);
5817 return_val_if_nok (error, NULL);
5819 if (bounds_size)
5820 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5821 else
5822 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5824 if (G_UNLIKELY (!o)) {
5825 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5826 return NULL;
5829 array = (MonoArray*)o;
5831 bounds = array->bounds;
5833 if (bounds_size) {
5834 for (i = 0; i < array_class->rank; ++i) {
5835 bounds [i].length = lengths [i];
5836 if (lower_bounds)
5837 bounds [i].lower_bound = lower_bounds [i];
5841 return array;
5845 * mono_array_new:
5846 * @domain: domain where the object is created
5847 * @eclass: element class
5848 * @n: number of array elements
5850 * This routine creates a new szarray with @n elements of type @eclass.
5852 MonoArray *
5853 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5855 MONO_REQ_GC_UNSAFE_MODE;
5857 MonoError error;
5858 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5859 mono_error_cleanup (&error);
5860 return result;
5864 * mono_array_new_checked:
5865 * @domain: domain where the object is created
5866 * @eclass: element class
5867 * @n: number of array elements
5868 * @error: set on error
5870 * This routine creates a new szarray with @n elements of type @eclass.
5871 * On failure returns NULL and sets @error.
5873 MonoArray *
5874 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5876 MonoClass *ac;
5878 mono_error_init (error);
5880 ac = mono_array_class_get (eclass, 1);
5881 g_assert (ac);
5883 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5884 return_val_if_nok (error, NULL);
5886 return mono_array_new_specific_checked (vtable, n, error);
5889 MonoArray*
5890 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5892 MonoError error;
5893 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5894 mono_error_set_pending_exception (&error);
5896 return arr;
5900 * mono_array_new_specific:
5901 * @vtable: a vtable in the appropriate domain for an initialized class
5902 * @n: number of array elements
5904 * This routine is a fast alternative to mono_array_new() for code which
5905 * can be sure about the domain it operates in.
5907 MonoArray *
5908 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5910 MonoError error;
5911 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5912 mono_error_cleanup (&error);
5914 return arr;
5917 MonoArray*
5918 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5920 MONO_REQ_GC_UNSAFE_MODE;
5922 MonoObject *o;
5923 uintptr_t byte_len;
5925 mono_error_init (error);
5927 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5928 mono_error_set_generic_error (error, "System", "OverflowException", "");
5929 return NULL;
5932 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5933 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5934 return NULL;
5936 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5938 if (G_UNLIKELY (!o)) {
5939 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5940 return NULL;
5943 return (MonoArray*)o;
5946 MonoArray*
5947 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5949 MonoError error;
5950 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5951 mono_error_set_pending_exception (&error);
5953 return arr;
5957 * mono_string_new_utf16:
5958 * @text: a pointer to an utf16 string
5959 * @len: the length of the string
5961 * Returns: A newly created string object which contains @text.
5963 MonoString *
5964 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5966 MONO_REQ_GC_UNSAFE_MODE;
5968 MonoError error;
5969 MonoString *res = NULL;
5970 res = mono_string_new_utf16_checked (domain, text, len, &error);
5971 mono_error_cleanup (&error);
5973 return res;
5977 * mono_string_new_utf16_checked:
5978 * @text: a pointer to an utf16 string
5979 * @len: the length of the string
5980 * @error: written on error.
5982 * Returns: A newly created string object which contains @text.
5983 * On error, returns NULL and sets @error.
5985 MonoString *
5986 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5988 MONO_REQ_GC_UNSAFE_MODE;
5990 MonoString *s;
5992 mono_error_init (error);
5994 s = mono_string_new_size_checked (domain, len, error);
5995 if (s != NULL)
5996 memcpy (mono_string_chars (s), text, len * 2);
5998 return s;
6002 * mono_string_new_utf32:
6003 * @text: a pointer to an utf32 string
6004 * @len: the length of the string
6005 * @error: set on failure.
6007 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6009 static MonoString *
6010 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6012 MONO_REQ_GC_UNSAFE_MODE;
6014 MonoString *s;
6015 mono_unichar2 *utf16_output = NULL;
6016 gint32 utf16_len = 0;
6017 GError *gerror = NULL;
6018 glong items_written;
6020 mono_error_init (error);
6021 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6023 if (gerror)
6024 g_error_free (gerror);
6026 while (utf16_output [utf16_len]) utf16_len++;
6028 s = mono_string_new_size_checked (domain, utf16_len, error);
6029 return_val_if_nok (error, NULL);
6031 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6033 g_free (utf16_output);
6035 return s;
6039 * mono_string_new_utf32:
6040 * @text: a pointer to an utf32 string
6041 * @len: the length of the string
6043 * Returns: A newly created string object which contains @text.
6045 MonoString *
6046 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6048 MonoError error;
6049 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6050 mono_error_cleanup (&error);
6051 return result;
6055 * mono_string_new_size:
6056 * @text: a pointer to an utf16 string
6057 * @len: the length of the string
6059 * Returns: A newly created string object of @len
6061 MonoString *
6062 mono_string_new_size (MonoDomain *domain, gint32 len)
6064 MonoError error;
6065 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6066 mono_error_cleanup (&error);
6068 return str;
6071 MonoString *
6072 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6074 MONO_REQ_GC_UNSAFE_MODE;
6076 MonoString *s;
6077 MonoVTable *vtable;
6078 size_t size;
6080 mono_error_init (error);
6082 /* check for overflow */
6083 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6084 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6085 return NULL;
6088 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6089 g_assert (size > 0);
6091 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6092 g_assert (vtable);
6094 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6096 if (G_UNLIKELY (!s)) {
6097 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6098 return NULL;
6101 return s;
6105 * mono_string_new_len:
6106 * @text: a pointer to an utf8 string
6107 * @length: number of bytes in @text to consider
6109 * Returns: A newly created string object which contains @text.
6111 MonoString*
6112 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6114 MONO_REQ_GC_UNSAFE_MODE;
6116 MonoError error;
6117 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6118 mono_error_cleanup (&error);
6119 return result;
6123 * mono_string_new_len_checked:
6124 * @text: a pointer to an utf8 string
6125 * @length: number of bytes in @text to consider
6126 * @error: set on error
6128 * Returns: A newly created string object which contains @text. On
6129 * failure returns NULL and sets @error.
6131 MonoString*
6132 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6134 MONO_REQ_GC_UNSAFE_MODE;
6136 mono_error_init (error);
6138 GError *eg_error = NULL;
6139 MonoString *o = NULL;
6140 guint16 *ut = NULL;
6141 glong items_written;
6143 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6145 if (!eg_error)
6146 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6147 else
6148 g_error_free (eg_error);
6150 g_free (ut);
6152 return o;
6156 * mono_string_new:
6157 * @text: a pointer to an utf8 string
6159 * Returns: A newly created string object which contains @text.
6161 * This function asserts if it cannot allocate a new string.
6163 * @deprecated Use mono_string_new_checked in new code.
6165 MonoString*
6166 mono_string_new (MonoDomain *domain, const char *text)
6168 MonoError error;
6169 MonoString *res = NULL;
6170 res = mono_string_new_checked (domain, text, &error);
6171 mono_error_assert_ok (&error);
6172 return res;
6176 * mono_string_new_checked:
6177 * @text: a pointer to an utf8 string
6178 * @merror: set on error
6180 * Returns: A newly created string object which contains @text.
6181 * On error returns NULL and sets @merror.
6183 MonoString*
6184 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6186 MONO_REQ_GC_UNSAFE_MODE;
6188 GError *eg_error = NULL;
6189 MonoString *o = NULL;
6190 guint16 *ut;
6191 glong items_written;
6192 int l;
6194 mono_error_init (error);
6196 l = strlen (text);
6198 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6200 if (!eg_error)
6201 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6202 else
6203 g_error_free (eg_error);
6205 g_free (ut);
6207 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6208 #if 0
6209 gunichar2 *str;
6210 const gchar *end;
6211 int len;
6212 MonoString *o = NULL;
6214 if (!g_utf8_validate (text, -1, &end)) {
6215 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6216 goto leave;
6219 len = g_utf8_strlen (text, -1);
6220 o = mono_string_new_size_checked (domain, len, error);
6221 if (!o)
6222 goto leave;
6223 str = mono_string_chars (o);
6225 while (text < end) {
6226 *str++ = g_utf8_get_char (text);
6227 text = g_utf8_next_char (text);
6230 leave:
6231 #endif
6232 return o;
6236 * mono_string_new_wrapper:
6237 * @text: pointer to utf8 characters.
6239 * Helper function to create a string object from @text in the current domain.
6241 MonoString*
6242 mono_string_new_wrapper (const char *text)
6244 MONO_REQ_GC_UNSAFE_MODE;
6246 MonoDomain *domain = mono_domain_get ();
6248 if (text)
6249 return mono_string_new (domain, text);
6251 return NULL;
6255 * mono_value_box:
6256 * @class: the class of the value
6257 * @value: a pointer to the unboxed data
6259 * Returns: A newly created object which contains @value.
6261 MonoObject *
6262 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6264 MonoError error;
6265 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6266 mono_error_cleanup (&error);
6267 return result;
6271 * mono_value_box_checked:
6272 * @domain: the domain of the new object
6273 * @class: the class of the value
6274 * @value: a pointer to the unboxed data
6275 * @error: set on error
6277 * Returns: A newly created object which contains @value. On failure
6278 * returns NULL and sets @error.
6280 MonoObject *
6281 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6283 MONO_REQ_GC_UNSAFE_MODE;
6284 MonoObject *res;
6285 int size;
6286 MonoVTable *vtable;
6288 mono_error_init (error);
6290 g_assert (klass->valuetype);
6291 if (mono_class_is_nullable (klass))
6292 return mono_nullable_box ((guint8 *)value, klass, error);
6294 vtable = mono_class_vtable (domain, klass);
6295 if (!vtable)
6296 return NULL;
6297 size = mono_class_instance_size (klass);
6298 res = mono_object_new_alloc_specific_checked (vtable, error);
6299 return_val_if_nok (error, NULL);
6301 size = size - sizeof (MonoObject);
6303 #ifdef HAVE_SGEN_GC
6304 g_assert (size == mono_class_value_size (klass, NULL));
6305 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6306 #else
6307 #if NO_UNALIGNED_ACCESS
6308 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6309 #else
6310 switch (size) {
6311 case 1:
6312 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6313 break;
6314 case 2:
6315 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6316 break;
6317 case 4:
6318 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6319 break;
6320 case 8:
6321 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6322 break;
6323 default:
6324 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6326 #endif
6327 #endif
6328 if (klass->has_finalize) {
6329 mono_object_register_finalizer (res);
6330 return_val_if_nok (error, NULL);
6332 return res;
6336 * mono_value_copy:
6337 * @dest: destination pointer
6338 * @src: source pointer
6339 * @klass: a valuetype class
6341 * Copy a valuetype from @src to @dest. This function must be used
6342 * when @klass contains references fields.
6344 void
6345 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6347 MONO_REQ_GC_UNSAFE_MODE;
6349 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6353 * mono_value_copy_array:
6354 * @dest: destination array
6355 * @dest_idx: index in the @dest array
6356 * @src: source pointer
6357 * @count: number of items
6359 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6360 * This function must be used when @klass contains references fields.
6361 * Overlap is handled.
6363 void
6364 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6366 MONO_REQ_GC_UNSAFE_MODE;
6368 int size = mono_array_element_size (dest->obj.vtable->klass);
6369 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6370 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6371 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6375 * mono_object_get_domain:
6376 * @obj: object to query
6378 * Returns: the MonoDomain where the object is hosted
6380 MonoDomain*
6381 mono_object_get_domain (MonoObject *obj)
6383 MONO_REQ_GC_UNSAFE_MODE;
6385 return mono_object_domain (obj);
6389 * mono_object_get_class:
6390 * @obj: object to query
6392 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6394 * Returns: the MonoClass of the object.
6396 MonoClass*
6397 mono_object_get_class (MonoObject *obj)
6399 MONO_REQ_GC_UNSAFE_MODE;
6401 return mono_object_class (obj);
6404 * mono_object_get_size:
6405 * @o: object to query
6407 * Returns: the size, in bytes, of @o
6409 guint
6410 mono_object_get_size (MonoObject* o)
6412 MONO_REQ_GC_UNSAFE_MODE;
6414 MonoClass* klass = mono_object_class (o);
6415 if (klass == mono_defaults.string_class) {
6416 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6417 } else if (o->vtable->rank) {
6418 MonoArray *array = (MonoArray*)o;
6419 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6420 if (array->bounds) {
6421 size += 3;
6422 size &= ~3;
6423 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6425 return size;
6426 } else {
6427 return mono_class_instance_size (klass);
6432 * mono_object_unbox:
6433 * @obj: object to unbox
6435 * Returns: a pointer to the start of the valuetype boxed in this
6436 * object.
6438 * This method will assert if the object passed is not a valuetype.
6440 gpointer
6441 mono_object_unbox (MonoObject *obj)
6443 MONO_REQ_GC_UNSAFE_MODE;
6445 /* add assert for valuetypes? */
6446 g_assert (obj->vtable->klass->valuetype);
6447 return ((char*)obj) + sizeof (MonoObject);
6451 * mono_object_isinst:
6452 * @obj: an object
6453 * @klass: a pointer to a class
6455 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6457 MonoObject *
6458 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6460 MONO_REQ_GC_UNSAFE_MODE;
6462 MonoError error;
6463 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6464 mono_error_cleanup (&error);
6465 return result;
6470 * mono_object_isinst_checked:
6471 * @obj: an object
6472 * @klass: a pointer to a class
6473 * @error: set on error
6475 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6476 * On failure returns NULL and sets @error.
6478 MonoObject *
6479 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6481 MONO_REQ_GC_UNSAFE_MODE;
6483 mono_error_init (error);
6485 MonoObject *result = NULL;
6487 if (!klass->inited)
6488 mono_class_init (klass);
6490 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6491 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6492 return result;
6495 if (!obj)
6496 return NULL;
6498 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6501 MonoObject *
6502 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6504 MONO_REQ_GC_UNSAFE_MODE;
6506 MonoError error;
6507 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6508 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6509 return result;
6512 MonoObject *
6513 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6515 MONO_REQ_GC_UNSAFE_MODE;
6517 MonoVTable *vt;
6519 mono_error_init (error);
6521 if (!obj)
6522 return NULL;
6524 vt = obj->vtable;
6526 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6527 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6528 return obj;
6531 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6532 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6533 return obj;
6534 } else {
6535 MonoClass *oklass = vt->klass;
6536 if (mono_class_is_transparent_proxy (oklass))
6537 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6539 mono_class_setup_supertypes (klass);
6540 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6541 return obj;
6543 #ifndef DISABLE_REMOTING
6544 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6546 MonoDomain *domain = mono_domain_get ();
6547 MonoObject *res;
6548 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6549 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6550 MonoMethod *im = NULL;
6551 gpointer pa [2];
6553 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6554 if (!im) {
6555 mono_error_set_not_supported (error, "Linked away.");
6556 return NULL;
6558 im = mono_object_get_virtual_method (rp, im);
6559 g_assert (im);
6561 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6562 return_val_if_nok (error, NULL);
6563 pa [1] = obj;
6565 res = mono_runtime_invoke_checked (im, rp, pa, error);
6566 return_val_if_nok (error, NULL);
6568 if (*(MonoBoolean *) mono_object_unbox(res)) {
6569 /* Update the vtable of the remote type, so it can safely cast to this new type */
6570 mono_upgrade_remote_class (domain, obj, klass, error);
6571 return_val_if_nok (error, NULL);
6572 return obj;
6575 #endif /* DISABLE_REMOTING */
6576 return NULL;
6580 * mono_object_castclass_mbyref:
6581 * @obj: an object
6582 * @klass: a pointer to a class
6584 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6586 MonoObject *
6587 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6589 MONO_REQ_GC_UNSAFE_MODE;
6590 MonoError error;
6592 if (!obj) return NULL;
6593 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6594 mono_error_cleanup (&error);
6595 return NULL;
6598 typedef struct {
6599 MonoDomain *orig_domain;
6600 MonoString *ins;
6601 MonoString *res;
6602 } LDStrInfo;
6604 static void
6605 str_lookup (MonoDomain *domain, gpointer user_data)
6607 MONO_REQ_GC_UNSAFE_MODE;
6609 LDStrInfo *info = (LDStrInfo *)user_data;
6610 if (info->res || domain == info->orig_domain)
6611 return;
6612 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6615 static MonoString*
6616 mono_string_get_pinned (MonoString *str, MonoError *error)
6618 MONO_REQ_GC_UNSAFE_MODE;
6620 mono_error_init (error);
6622 /* We only need to make a pinned version of a string if this is a moving GC */
6623 if (!mono_gc_is_moving ())
6624 return str;
6625 int size;
6626 MonoString *news;
6627 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6628 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6629 if (news) {
6630 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6631 news->length = mono_string_length (str);
6632 } else {
6633 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6635 return news;
6638 static MonoString*
6639 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6641 MONO_REQ_GC_UNSAFE_MODE;
6643 MonoGHashTable *ldstr_table;
6644 MonoString *s, *res;
6645 MonoDomain *domain;
6647 mono_error_init (error);
6649 domain = ((MonoObject *)str)->vtable->domain;
6650 ldstr_table = domain->ldstr_table;
6651 ldstr_lock ();
6652 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6653 if (res) {
6654 ldstr_unlock ();
6655 return res;
6657 if (insert) {
6658 /* Allocate outside the lock */
6659 ldstr_unlock ();
6660 s = mono_string_get_pinned (str, error);
6661 return_val_if_nok (error, NULL);
6662 if (s) {
6663 ldstr_lock ();
6664 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6665 if (res) {
6666 ldstr_unlock ();
6667 return res;
6669 mono_g_hash_table_insert (ldstr_table, s, s);
6670 ldstr_unlock ();
6672 return s;
6673 } else {
6674 LDStrInfo ldstr_info;
6675 ldstr_info.orig_domain = domain;
6676 ldstr_info.ins = str;
6677 ldstr_info.res = NULL;
6679 mono_domain_foreach (str_lookup, &ldstr_info);
6680 if (ldstr_info.res) {
6682 * the string was already interned in some other domain:
6683 * intern it in the current one as well.
6685 mono_g_hash_table_insert (ldstr_table, str, str);
6686 ldstr_unlock ();
6687 return str;
6690 ldstr_unlock ();
6691 return NULL;
6695 * mono_string_is_interned:
6696 * @o: String to probe
6698 * Returns whether the string has been interned.
6700 MonoString*
6701 mono_string_is_interned (MonoString *o)
6703 MonoError error;
6704 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6705 /* This function does not fail. */
6706 mono_error_assert_ok (&error);
6707 return result;
6711 * mono_string_intern:
6712 * @o: String to intern
6714 * Interns the string passed.
6715 * Returns: The interned string.
6717 MonoString*
6718 mono_string_intern (MonoString *str)
6720 MonoError error;
6721 MonoString *result = mono_string_intern_checked (str, &error);
6722 mono_error_assert_ok (&error);
6723 return result;
6727 * mono_string_intern_checked:
6728 * @o: String to intern
6729 * @error: set on error.
6731 * Interns the string passed.
6732 * Returns: The interned string. On failure returns NULL and sets @error
6734 MonoString*
6735 mono_string_intern_checked (MonoString *str, MonoError *error)
6737 MONO_REQ_GC_UNSAFE_MODE;
6739 mono_error_init (error);
6741 return mono_string_is_interned_lookup (str, TRUE, error);
6745 * mono_ldstr:
6746 * @domain: the domain where the string will be used.
6747 * @image: a metadata context
6748 * @idx: index into the user string table.
6750 * Implementation for the ldstr opcode.
6751 * Returns: a loaded string from the @image/@idx combination.
6753 MonoString*
6754 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6756 MonoError error;
6757 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6758 mono_error_cleanup (&error);
6759 return result;
6763 * mono_ldstr_checked:
6764 * @domain: the domain where the string will be used.
6765 * @image: a metadata context
6766 * @idx: index into the user string table.
6767 * @error: set on error.
6769 * Implementation for the ldstr opcode.
6770 * Returns: a loaded string from the @image/@idx combination.
6771 * On failure returns NULL and sets @error.
6773 MonoString*
6774 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6776 MONO_REQ_GC_UNSAFE_MODE;
6777 mono_error_init (error);
6779 if (image->dynamic) {
6780 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6781 return str;
6782 } else {
6783 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6784 return NULL; /*FIXME we should probably be raising an exception here*/
6785 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6786 return str;
6791 * mono_ldstr_metadata_sig
6792 * @domain: the domain for the string
6793 * @sig: the signature of a metadata string
6794 * @error: set on error
6796 * Returns: a MonoString for a string stored in the metadata. On
6797 * failure returns NULL and sets @error.
6799 static MonoString*
6800 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6802 MONO_REQ_GC_UNSAFE_MODE;
6804 mono_error_init (error);
6805 const char *str = sig;
6806 MonoString *o, *interned;
6807 size_t len2;
6809 len2 = mono_metadata_decode_blob_size (str, &str);
6810 len2 >>= 1;
6812 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6813 return_val_if_nok (error, NULL);
6814 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6816 int i;
6817 guint16 *p2 = (guint16*)mono_string_chars (o);
6818 for (i = 0; i < len2; ++i) {
6819 *p2 = GUINT16_FROM_LE (*p2);
6820 ++p2;
6823 #endif
6824 ldstr_lock ();
6825 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6826 ldstr_unlock ();
6827 if (interned)
6828 return interned; /* o will get garbage collected */
6830 o = mono_string_get_pinned (o, error);
6831 if (o) {
6832 ldstr_lock ();
6833 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6834 if (!interned) {
6835 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6836 interned = o;
6838 ldstr_unlock ();
6841 return interned;
6845 * mono_ldstr_utf8:
6847 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6848 * of an object.
6850 char*
6851 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6853 const char *str;
6854 size_t len2;
6855 long written = 0;
6856 char *as;
6857 GError *gerror = NULL;
6859 mono_error_init (error);
6861 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6862 return NULL; /*FIXME we should probably be raising an exception here*/
6863 str = mono_metadata_user_string (image, idx);
6865 len2 = mono_metadata_decode_blob_size (str, &str);
6866 len2 >>= 1;
6868 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6869 if (gerror) {
6870 mono_error_set_argument (error, "string", "%s", gerror->message);
6871 g_error_free (gerror);
6872 return NULL;
6874 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6875 if (len2 > written) {
6876 /* allocate the total length and copy the part of the string that has been converted */
6877 char *as2 = (char *)g_malloc0 (len2);
6878 memcpy (as2, as, written);
6879 g_free (as);
6880 as = as2;
6883 return as;
6887 * mono_string_to_utf8:
6888 * @s: a System.String
6890 * Returns the UTF8 representation for @s.
6891 * The resulting buffer needs to be freed with mono_free().
6893 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6895 char *
6896 mono_string_to_utf8 (MonoString *s)
6898 MONO_REQ_GC_UNSAFE_MODE;
6900 MonoError error;
6901 char *result = mono_string_to_utf8_checked (s, &error);
6903 if (!is_ok (&error)) {
6904 mono_error_cleanup (&error);
6905 return NULL;
6907 return result;
6911 * mono_string_to_utf8_checked:
6912 * @s: a System.String
6913 * @error: a MonoError.
6915 * Converts a MonoString to its UTF8 representation. May fail; check
6916 * @error to determine whether the conversion was successful.
6917 * The resulting buffer should be freed with mono_free().
6919 char *
6920 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6922 MONO_REQ_GC_UNSAFE_MODE;
6924 long written = 0;
6925 char *as;
6926 GError *gerror = NULL;
6928 mono_error_init (error);
6930 if (s == NULL)
6931 return NULL;
6933 if (!s->length)
6934 return g_strdup ("");
6936 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6937 if (gerror) {
6938 mono_error_set_argument (error, "string", "%s", gerror->message);
6939 g_error_free (gerror);
6940 return NULL;
6942 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6943 if (s->length > written) {
6944 /* allocate the total length and copy the part of the string that has been converted */
6945 char *as2 = (char *)g_malloc0 (s->length);
6946 memcpy (as2, as, written);
6947 g_free (as);
6948 as = as2;
6951 return as;
6955 * mono_string_to_utf8_ignore:
6956 * @s: a MonoString
6958 * Converts a MonoString to its UTF8 representation. Will ignore
6959 * invalid surrogate pairs.
6960 * The resulting buffer should be freed with mono_free().
6963 char *
6964 mono_string_to_utf8_ignore (MonoString *s)
6966 MONO_REQ_GC_UNSAFE_MODE;
6968 long written = 0;
6969 char *as;
6971 if (s == NULL)
6972 return NULL;
6974 if (!s->length)
6975 return g_strdup ("");
6977 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6979 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6980 if (s->length > written) {
6981 /* allocate the total length and copy the part of the string that has been converted */
6982 char *as2 = (char *)g_malloc0 (s->length);
6983 memcpy (as2, as, written);
6984 g_free (as);
6985 as = as2;
6988 return as;
6992 * mono_string_to_utf8_image_ignore:
6993 * @s: a System.String
6995 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6997 char *
6998 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7000 MONO_REQ_GC_UNSAFE_MODE;
7002 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7006 * mono_string_to_utf8_mp_ignore:
7007 * @s: a System.String
7009 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7011 char *
7012 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7014 MONO_REQ_GC_UNSAFE_MODE;
7016 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7021 * mono_string_to_utf16:
7022 * @s: a MonoString
7024 * Return an null-terminated array of the utf-16 chars
7025 * contained in @s. The result must be freed with g_free().
7026 * This is a temporary helper until our string implementation
7027 * is reworked to always include the null terminating char.
7029 mono_unichar2*
7030 mono_string_to_utf16 (MonoString *s)
7032 MONO_REQ_GC_UNSAFE_MODE;
7034 char *as;
7036 if (s == NULL)
7037 return NULL;
7039 as = (char *)g_malloc ((s->length * 2) + 2);
7040 as [(s->length * 2)] = '\0';
7041 as [(s->length * 2) + 1] = '\0';
7043 if (!s->length) {
7044 return (gunichar2 *)(as);
7047 memcpy (as, mono_string_chars(s), s->length * 2);
7048 return (gunichar2 *)(as);
7052 * mono_string_to_utf32:
7053 * @s: a MonoString
7055 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7056 * contained in @s. The result must be freed with g_free().
7058 mono_unichar4*
7059 mono_string_to_utf32 (MonoString *s)
7061 MONO_REQ_GC_UNSAFE_MODE;
7063 mono_unichar4 *utf32_output = NULL;
7064 GError *error = NULL;
7065 glong items_written;
7067 if (s == NULL)
7068 return NULL;
7070 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7072 if (error)
7073 g_error_free (error);
7075 return utf32_output;
7079 * mono_string_from_utf16:
7080 * @data: the UTF16 string (LPWSTR) to convert
7082 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7084 * Returns: a MonoString.
7086 MonoString *
7087 mono_string_from_utf16 (gunichar2 *data)
7089 MonoError error;
7090 MonoString *result = mono_string_from_utf16_checked (data, &error);
7091 mono_error_cleanup (&error);
7092 return result;
7096 * mono_string_from_utf16_checked:
7097 * @data: the UTF16 string (LPWSTR) to convert
7098 * @error: set on error
7100 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7102 * Returns: a MonoString. On failure sets @error and returns NULL.
7104 MonoString *
7105 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7108 MONO_REQ_GC_UNSAFE_MODE;
7110 mono_error_init (error);
7111 MonoDomain *domain = mono_domain_get ();
7112 int len = 0;
7114 if (!data)
7115 return NULL;
7117 while (data [len]) len++;
7119 return mono_string_new_utf16_checked (domain, data, len, error);
7123 * mono_string_from_utf32:
7124 * @data: the UTF32 string (LPWSTR) to convert
7126 * Converts a UTF32 (UCS-4)to a MonoString.
7128 * Returns: a MonoString.
7130 MonoString *
7131 mono_string_from_utf32 (mono_unichar4 *data)
7133 MonoError error;
7134 MonoString *result = mono_string_from_utf32_checked (data, &error);
7135 mono_error_cleanup (&error);
7136 return result;
7140 * mono_string_from_utf32_checked:
7141 * @data: the UTF32 string (LPWSTR) to convert
7142 * @error: set on error
7144 * Converts a UTF32 (UCS-4)to a MonoString.
7146 * Returns: a MonoString. On failure returns NULL and sets @error.
7148 MonoString *
7149 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7151 MONO_REQ_GC_UNSAFE_MODE;
7153 mono_error_init (error);
7154 MonoString* result = NULL;
7155 mono_unichar2 *utf16_output = NULL;
7156 GError *gerror = NULL;
7157 glong items_written;
7158 int len = 0;
7160 if (!data)
7161 return NULL;
7163 while (data [len]) len++;
7165 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7167 if (gerror)
7168 g_error_free (gerror);
7170 result = mono_string_from_utf16_checked (utf16_output, error);
7171 g_free (utf16_output);
7172 return result;
7175 static char *
7176 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7178 MONO_REQ_GC_UNSAFE_MODE;
7180 char *r;
7181 char *mp_s;
7182 int len;
7184 if (ignore_error) {
7185 r = mono_string_to_utf8_ignore (s);
7186 } else {
7187 r = mono_string_to_utf8_checked (s, error);
7188 if (!mono_error_ok (error))
7189 return NULL;
7192 if (!mp && !image)
7193 return r;
7195 len = strlen (r) + 1;
7196 if (mp)
7197 mp_s = (char *)mono_mempool_alloc (mp, len);
7198 else
7199 mp_s = (char *)mono_image_alloc (image, len);
7201 memcpy (mp_s, r, len);
7203 g_free (r);
7205 return mp_s;
7209 * mono_string_to_utf8_image:
7210 * @s: a System.String
7212 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7214 char *
7215 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7217 MONO_REQ_GC_UNSAFE_MODE;
7219 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7223 * mono_string_to_utf8_mp:
7224 * @s: a System.String
7226 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7228 char *
7229 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7231 MONO_REQ_GC_UNSAFE_MODE;
7233 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7237 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7239 void
7240 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7242 eh_callbacks = *cbs;
7245 MonoRuntimeExceptionHandlingCallbacks *
7246 mono_get_eh_callbacks (void)
7248 return &eh_callbacks;
7252 * mono_raise_exception:
7253 * @ex: exception object
7255 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7257 void
7258 mono_raise_exception (MonoException *ex)
7260 MONO_REQ_GC_UNSAFE_MODE;
7263 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7264 * that will cause gcc to omit the function epilog, causing problems when
7265 * the JIT tries to walk the stack, since the return address on the stack
7266 * will point into the next function in the executable, not this one.
7268 eh_callbacks.mono_raise_exception (ex);
7271 void
7272 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7274 MONO_REQ_GC_UNSAFE_MODE;
7276 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7280 * mono_wait_handle_new:
7281 * @domain: Domain where the object will be created
7282 * @handle: Handle for the wait handle
7283 * @error: set on error.
7285 * Returns: A new MonoWaitHandle created in the given domain for the
7286 * given handle. On failure returns NULL and sets @rror.
7288 MonoWaitHandle *
7289 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7291 MONO_REQ_GC_UNSAFE_MODE;
7293 MonoWaitHandle *res;
7294 gpointer params [1];
7295 static MonoMethod *handle_set;
7297 mono_error_init (error);
7298 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7299 return_val_if_nok (error, NULL);
7301 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7302 if (!handle_set)
7303 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7305 params [0] = &handle;
7307 mono_runtime_invoke_checked (handle_set, res, params, error);
7308 return res;
7311 HANDLE
7312 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7314 MONO_REQ_GC_UNSAFE_MODE;
7316 static MonoClassField *f_safe_handle = NULL;
7317 MonoSafeHandle *sh;
7319 if (!f_safe_handle) {
7320 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7321 g_assert (f_safe_handle);
7324 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7325 return sh->handle;
7329 static MonoObject*
7330 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7332 MONO_REQ_GC_UNSAFE_MODE;
7334 RuntimeInvokeFunction runtime_invoke;
7336 mono_error_init (error);
7338 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7339 MonoMethod *method = mono_get_context_capture_method ();
7340 MonoMethod *wrapper;
7341 if (!method)
7342 return NULL;
7343 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7344 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7345 return_val_if_nok (error, NULL);
7346 domain->capture_context_method = mono_compile_method_checked (method, error);
7347 return_val_if_nok (error, NULL);
7350 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7352 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7355 * mono_async_result_new:
7356 * @domain:domain where the object will be created.
7357 * @handle: wait handle.
7358 * @state: state to pass to AsyncResult
7359 * @data: C closure data.
7360 * @error: set on error.
7362 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7363 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7364 * On failure returns NULL and sets @error.
7367 MonoAsyncResult *
7368 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7370 MONO_REQ_GC_UNSAFE_MODE;
7372 mono_error_init (error);
7373 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7374 return_val_if_nok (error, NULL);
7375 MonoObject *context = mono_runtime_capture_context (domain, error);
7376 return_val_if_nok (error, NULL);
7377 /* we must capture the execution context from the original thread */
7378 if (context) {
7379 MONO_OBJECT_SETREF (res, execution_context, context);
7380 /* note: result may be null if the flow is suppressed */
7383 res->data = (void **)data;
7384 MONO_OBJECT_SETREF (res, object_data, object_data);
7385 MONO_OBJECT_SETREF (res, async_state, state);
7386 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7387 return_val_if_nok (error, NULL);
7388 if (handle != NULL)
7389 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7391 res->sync_completed = FALSE;
7392 res->completed = FALSE;
7394 return res;
7397 MonoObject *
7398 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7400 MONO_REQ_GC_UNSAFE_MODE;
7402 MonoError error;
7403 MonoAsyncCall *ac;
7404 MonoObject *res;
7406 g_assert (ares);
7407 g_assert (ares->async_delegate);
7409 ac = (MonoAsyncCall*) ares->object_data;
7410 if (!ac) {
7411 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7412 if (mono_error_set_pending_exception (&error))
7413 return NULL;
7414 } else {
7415 gpointer wait_event = NULL;
7417 ac->msg->exc = NULL;
7419 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7421 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7422 mono_threads_begin_abort_protected_block ();
7424 if (!ac->msg->exc) {
7425 MonoException *ex = mono_error_convert_to_exception (&error);
7426 ac->msg->exc = (MonoObject *)ex;
7427 } else {
7428 mono_error_cleanup (&error);
7431 MONO_OBJECT_SETREF (ac, res, res);
7433 mono_monitor_enter ((MonoObject*) ares);
7434 ares->completed = 1;
7435 if (ares->handle)
7436 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7437 mono_monitor_exit ((MonoObject*) ares);
7439 if (wait_event != NULL)
7440 mono_w32event_set (wait_event);
7442 mono_error_init (&error); //the else branch would leave it in an undefined state
7443 if (ac->cb_method)
7444 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7446 mono_threads_end_abort_protected_block ();
7448 if (mono_error_set_pending_exception (&error))
7449 return NULL;
7452 return res;
7455 gboolean
7456 mono_message_init (MonoDomain *domain,
7457 MonoMethodMessage *this_obj,
7458 MonoReflectionMethod *method,
7459 MonoArray *out_args,
7460 MonoError *error)
7462 MONO_REQ_GC_UNSAFE_MODE;
7464 static MonoMethod *init_message_method = NULL;
7466 if (!init_message_method) {
7467 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7468 g_assert (init_message_method != NULL);
7471 mono_error_init (error);
7472 /* FIXME set domain instead? */
7473 g_assert (domain == mono_domain_get ());
7475 gpointer args[2];
7477 args[0] = method;
7478 args[1] = out_args;
7480 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7481 return is_ok (error);
7484 #ifndef DISABLE_REMOTING
7486 * mono_remoting_invoke:
7487 * @real_proxy: pointer to a RealProxy object
7488 * @msg: The MonoMethodMessage to execute
7489 * @exc: used to store exceptions
7490 * @out_args: used to store output arguments
7492 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7493 * IMessage interface and it is not trivial to extract results from there. So
7494 * we call an helper method PrivateInvoke instead of calling
7495 * RealProxy::Invoke() directly.
7497 * Returns: the result object.
7499 MonoObject *
7500 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7502 MONO_REQ_GC_UNSAFE_MODE;
7504 MonoObject *o;
7505 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7506 gpointer pa [4];
7508 g_assert (exc);
7510 mono_error_init (error);
7512 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7514 if (!im) {
7515 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7516 if (!im) {
7517 mono_error_set_not_supported (error, "Linked away.");
7518 return NULL;
7520 real_proxy->vtable->domain->private_invoke_method = im;
7523 pa [0] = real_proxy;
7524 pa [1] = msg;
7525 pa [2] = exc;
7526 pa [3] = out_args;
7528 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7529 return_val_if_nok (error, NULL);
7531 return o;
7533 #endif
7535 MonoObject *
7536 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7537 MonoObject **exc, MonoArray **out_args, MonoError *error)
7539 MONO_REQ_GC_UNSAFE_MODE;
7541 static MonoClass *object_array_klass;
7542 mono_error_init (error);
7544 MonoDomain *domain;
7545 MonoMethod *method;
7546 MonoMethodSignature *sig;
7547 MonoArray *arr;
7548 int i, j, outarg_count = 0;
7550 #ifndef DISABLE_REMOTING
7551 if (target && mono_object_is_transparent_proxy (target)) {
7552 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7553 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7554 target = tp->rp->unwrapped_server;
7555 } else {
7556 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7559 #endif
7561 domain = mono_domain_get ();
7562 method = msg->method->method;
7563 sig = mono_method_signature (method);
7565 for (i = 0; i < sig->param_count; i++) {
7566 if (sig->params [i]->byref)
7567 outarg_count++;
7570 if (!object_array_klass) {
7571 MonoClass *klass;
7573 klass = mono_array_class_get (mono_defaults.object_class, 1);
7574 g_assert (klass);
7576 mono_memory_barrier ();
7577 object_array_klass = klass;
7580 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7581 return_val_if_nok (error, NULL);
7583 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7584 *exc = NULL;
7586 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7587 return_val_if_nok (error, NULL);
7589 for (i = 0, j = 0; i < sig->param_count; i++) {
7590 if (sig->params [i]->byref) {
7591 MonoObject* arg;
7592 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7593 mono_array_setref (*out_args, j, arg);
7594 j++;
7598 return ret;
7602 * prepare_to_string_method:
7603 * @obj: The object
7604 * @target: Set to @obj or unboxed value if a valuetype
7606 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7608 static MonoMethod *
7609 prepare_to_string_method (MonoObject *obj, void **target)
7611 MONO_REQ_GC_UNSAFE_MODE;
7613 static MonoMethod *to_string = NULL;
7614 MonoMethod *method;
7615 g_assert (target);
7616 g_assert (obj);
7618 *target = obj;
7620 if (!to_string)
7621 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7623 method = mono_object_get_virtual_method (obj, to_string);
7625 // Unbox value type if needed
7626 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7627 *target = mono_object_unbox (obj);
7629 return method;
7633 * mono_object_to_string:
7634 * @obj: The object
7635 * @exc: Any exception thrown by ToString (). May be NULL.
7637 * Returns: the result of calling ToString () on an object.
7639 MonoString *
7640 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7642 MonoError error;
7643 MonoString *s = NULL;
7644 void *target;
7645 MonoMethod *method = prepare_to_string_method (obj, &target);
7646 if (exc) {
7647 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7648 if (*exc == NULL && !mono_error_ok (&error))
7649 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7650 else
7651 mono_error_cleanup (&error);
7652 } else {
7653 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7654 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7657 return s;
7661 * mono_object_to_string_checked:
7662 * @obj: The object
7663 * @error: Set on error.
7665 * Returns: the result of calling ToString () on an object. If the
7666 * method cannot be invoked or if it raises an exception, sets @error
7667 * and returns NULL.
7669 MonoString *
7670 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7672 mono_error_init (error);
7673 void *target;
7674 MonoMethod *method = prepare_to_string_method (obj, &target);
7675 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7679 * mono_object_try_to_string:
7680 * @obj: The object
7681 * @exc: Any exception thrown by ToString (). Must not be NULL.
7682 * @error: Set if method cannot be invoked.
7684 * Returns: the result of calling ToString () on an object. If the
7685 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7686 * and returns NULL.
7688 MonoString *
7689 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7691 g_assert (exc);
7692 mono_error_init (error);
7693 void *target;
7694 MonoMethod *method = prepare_to_string_method (obj, &target);
7695 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7701 * mono_print_unhandled_exception:
7702 * @exc: The exception
7704 * Prints the unhandled exception.
7706 void
7707 mono_print_unhandled_exception (MonoObject *exc)
7709 MONO_REQ_GC_UNSAFE_MODE;
7711 MonoString * str;
7712 char *message = (char*)"";
7713 gboolean free_message = FALSE;
7714 MonoError error;
7716 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7717 message = g_strdup ("OutOfMemoryException");
7718 free_message = TRUE;
7719 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7720 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7721 free_message = TRUE;
7722 } else {
7724 if (((MonoException*)exc)->native_trace_ips) {
7725 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7726 free_message = TRUE;
7727 } else {
7728 MonoObject *other_exc = NULL;
7729 str = mono_object_try_to_string (exc, &other_exc, &error);
7730 if (other_exc == NULL && !is_ok (&error))
7731 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7732 else
7733 mono_error_cleanup (&error);
7734 if (other_exc) {
7735 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7736 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7738 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7739 original_backtrace, nested_backtrace);
7741 g_free (original_backtrace);
7742 g_free (nested_backtrace);
7743 free_message = TRUE;
7744 } else if (str) {
7745 message = mono_string_to_utf8_checked (str, &error);
7746 if (!mono_error_ok (&error)) {
7747 mono_error_cleanup (&error);
7748 message = (char *) "";
7749 } else {
7750 free_message = TRUE;
7757 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7758 * exc->vtable->klass->name, message);
7760 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7762 if (free_message)
7763 g_free (message);
7767 * mono_delegate_ctor_with_method:
7768 * @this: pointer to an uninitialized delegate object
7769 * @target: target object
7770 * @addr: pointer to native code
7771 * @method: method
7772 * @error: set on error.
7774 * Initialize a delegate and sets a specific method, not the one
7775 * associated with addr. This is useful when sharing generic code.
7776 * In that case addr will most probably not be associated with the
7777 * correct instantiation of the method.
7778 * On failure returns FALSE and sets @error.
7780 gboolean
7781 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7783 MONO_REQ_GC_UNSAFE_MODE;
7785 mono_error_init (error);
7786 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7788 g_assert (this_obj);
7789 g_assert (addr);
7791 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7793 if (method)
7794 delegate->method = method;
7796 mono_stats.delegate_creations++;
7798 #ifndef DISABLE_REMOTING
7799 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7800 g_assert (method);
7801 method = mono_marshal_get_remoting_invoke (method);
7802 delegate->method_ptr = mono_compile_method_checked (method, error);
7803 return_val_if_nok (error, FALSE);
7804 MONO_OBJECT_SETREF (delegate, target, target);
7805 } else
7806 #endif
7808 delegate->method_ptr = addr;
7809 MONO_OBJECT_SETREF (delegate, target, target);
7812 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7813 if (callbacks.init_delegate)
7814 callbacks.init_delegate (delegate);
7815 return TRUE;
7819 * mono_delegate_ctor:
7820 * @this: pointer to an uninitialized delegate object
7821 * @target: target object
7822 * @addr: pointer to native code
7823 * @error: set on error.
7825 * This is used to initialize a delegate.
7826 * On failure returns FALSE and sets @error.
7828 gboolean
7829 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7831 MONO_REQ_GC_UNSAFE_MODE;
7833 mono_error_init (error);
7834 MonoDomain *domain = mono_domain_get ();
7835 MonoJitInfo *ji;
7836 MonoMethod *method = NULL;
7838 g_assert (addr);
7840 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7841 /* Shared code */
7842 if (!ji && domain != mono_get_root_domain ())
7843 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7844 if (ji) {
7845 method = mono_jit_info_get_method (ji);
7846 g_assert (!method->klass->generic_container);
7849 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7853 * mono_method_call_message_new:
7854 * @method: method to encapsulate
7855 * @params: parameters to the method
7856 * @invoke: optional, delegate invoke.
7857 * @cb: async callback delegate.
7858 * @state: state passed to the async callback.
7859 * @error: set on error.
7861 * Translates arguments pointers into a MonoMethodMessage.
7862 * On failure returns NULL and sets @error.
7864 MonoMethodMessage *
7865 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7866 MonoDelegate **cb, MonoObject **state, MonoError *error)
7868 MONO_REQ_GC_UNSAFE_MODE;
7870 mono_error_init (error);
7872 MonoDomain *domain = mono_domain_get ();
7873 MonoMethodSignature *sig = mono_method_signature (method);
7874 MonoMethodMessage *msg;
7875 int i, count;
7877 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7878 return_val_if_nok (error, NULL);
7880 if (invoke) {
7881 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7882 return_val_if_nok (error, NULL);
7883 mono_message_init (domain, msg, rm, NULL, error);
7884 return_val_if_nok (error, NULL);
7885 count = sig->param_count - 2;
7886 } else {
7887 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7888 return_val_if_nok (error, NULL);
7889 mono_message_init (domain, msg, rm, NULL, error);
7890 return_val_if_nok (error, NULL);
7891 count = sig->param_count;
7894 for (i = 0; i < count; i++) {
7895 gpointer vpos;
7896 MonoClass *klass;
7897 MonoObject *arg;
7899 if (sig->params [i]->byref)
7900 vpos = *((gpointer *)params [i]);
7901 else
7902 vpos = params [i];
7904 klass = mono_class_from_mono_type (sig->params [i]);
7906 if (klass->valuetype) {
7907 arg = mono_value_box_checked (domain, klass, vpos, error);
7908 return_val_if_nok (error, NULL);
7909 } else
7910 arg = *((MonoObject **)vpos);
7912 mono_array_setref (msg->args, i, arg);
7915 if (cb != NULL && state != NULL) {
7916 *cb = *((MonoDelegate **)params [i]);
7917 i++;
7918 *state = *((MonoObject **)params [i]);
7921 return msg;
7925 * mono_method_return_message_restore:
7927 * Restore results from message based processing back to arguments pointers
7929 void
7930 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7932 MONO_REQ_GC_UNSAFE_MODE;
7934 mono_error_init (error);
7936 MonoMethodSignature *sig = mono_method_signature (method);
7937 int i, j, type, size, out_len;
7939 if (out_args == NULL)
7940 return;
7941 out_len = mono_array_length (out_args);
7942 if (out_len == 0)
7943 return;
7945 for (i = 0, j = 0; i < sig->param_count; i++) {
7946 MonoType *pt = sig->params [i];
7948 if (pt->byref) {
7949 char *arg;
7950 if (j >= out_len) {
7951 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7952 return;
7955 arg = (char *)mono_array_get (out_args, gpointer, j);
7956 type = pt->type;
7958 g_assert (type != MONO_TYPE_VOID);
7960 if (MONO_TYPE_IS_REFERENCE (pt)) {
7961 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7962 } else {
7963 if (arg) {
7964 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7965 size = mono_class_value_size (klass, NULL);
7966 if (klass->has_references)
7967 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7968 else
7969 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7970 } else {
7971 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7972 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7976 j++;
7981 #ifndef DISABLE_REMOTING
7984 * mono_load_remote_field:
7985 * @this: pointer to an object
7986 * @klass: klass of the object containing @field
7987 * @field: the field to load
7988 * @res: a storage to store the result
7990 * This method is called by the runtime on attempts to load fields of
7991 * transparent proxy objects. @this points to such TP, @klass is the class of
7992 * the object containing @field. @res is a storage location which can be
7993 * used to store the result.
7995 * Returns: an address pointing to the value of field.
7997 gpointer
7998 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8000 MonoError error;
8001 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8002 mono_error_cleanup (&error);
8003 return result;
8007 * mono_load_remote_field_checked:
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
8012 * @error: set on error
8014 * This method is called by the runtime on attempts to load fields of
8015 * transparent proxy objects. @this points to such TP, @klass is the class of
8016 * the object containing @field. @res is a storage location which can be
8017 * used to store the result.
8019 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8021 gpointer
8022 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8024 MONO_REQ_GC_UNSAFE_MODE;
8026 static MonoMethod *getter = NULL;
8028 mono_error_init (error);
8030 MonoDomain *domain = mono_domain_get ();
8031 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8032 MonoClass *field_class;
8033 MonoMethodMessage *msg;
8034 MonoArray *out_args;
8035 MonoObject *exc;
8036 char* full_name;
8038 g_assert (mono_object_is_transparent_proxy (this_obj));
8039 g_assert (res != NULL);
8041 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8042 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8043 return res;
8046 if (!getter) {
8047 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8048 if (!getter) {
8049 mono_error_set_not_supported (error, "Linked away.");
8050 return NULL;
8054 field_class = mono_class_from_mono_type (field->type);
8056 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8057 return_val_if_nok (error, NULL);
8058 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8059 return_val_if_nok (error, NULL);
8060 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8061 return_val_if_nok (error, NULL);
8062 mono_message_init (domain, msg, rm, out_args, error);
8063 return_val_if_nok (error, NULL);
8065 full_name = mono_type_get_full_name (klass);
8066 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8067 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8068 g_free (full_name);
8070 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8071 return_val_if_nok (error, NULL);
8073 if (exc) {
8074 mono_error_set_exception_instance (error, (MonoException *)exc);
8075 return NULL;
8078 if (mono_array_length (out_args) == 0)
8079 return NULL;
8081 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8083 if (field_class->valuetype) {
8084 return ((char *)*res) + sizeof (MonoObject);
8085 } else
8086 return res;
8090 * mono_load_remote_field_new:
8091 * @this:
8092 * @klass:
8093 * @field:
8095 * Missing documentation.
8097 MonoObject *
8098 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8100 MonoError error;
8102 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8103 mono_error_cleanup (&error);
8104 return result;
8108 * mono_load_remote_field_new_checked:
8109 * @this: pointer to an object
8110 * @klass: klass of the object containing @field
8111 * @field: the field to load
8112 * @error: set on error.
8114 * This method is called by the runtime on attempts to load fields of
8115 * transparent proxy objects. @this points to such TP, @klass is the class of
8116 * the object containing @field.
8118 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8120 MonoObject *
8121 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8123 MONO_REQ_GC_UNSAFE_MODE;
8125 mono_error_init (error);
8127 static MonoMethod *tp_load = NULL;
8129 g_assert (mono_object_is_transparent_proxy (this_obj));
8131 if (!tp_load) {
8132 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8133 if (!tp_load) {
8134 mono_error_set_not_supported (error, "Linked away.");
8135 return NULL;
8139 /* MonoType *type = mono_class_get_type (klass); */
8141 gpointer args[2];
8142 args [0] = &klass;
8143 args [1] = &field;
8145 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8149 * mono_store_remote_field:
8150 * @this_obj: pointer to an object
8151 * @klass: klass of the object containing @field
8152 * @field: the field to load
8153 * @val: the value/object to store
8155 * This method is called by the runtime on attempts to store fields of
8156 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8157 * the object containing @field. @val is the new value to store in @field.
8159 void
8160 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8162 MonoError error;
8163 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8164 mono_error_cleanup (&error);
8168 * mono_store_remote_field_checked:
8169 * @this_obj: pointer to an object
8170 * @klass: klass of the object containing @field
8171 * @field: the field to load
8172 * @val: the value/object to store
8173 * @error: set on error
8175 * This method is called by the runtime on attempts to store fields of
8176 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8177 * the object containing @field. @val is the new value to store in @field.
8179 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8181 gboolean
8182 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8185 MONO_REQ_GC_UNSAFE_MODE;
8187 mono_error_init (error);
8189 MonoDomain *domain = mono_domain_get ();
8190 MonoClass *field_class;
8191 MonoObject *arg;
8193 g_assert (mono_object_is_transparent_proxy (this_obj));
8195 field_class = mono_class_from_mono_type (field->type);
8197 if (field_class->valuetype) {
8198 arg = mono_value_box_checked (domain, field_class, val, error);
8199 return_val_if_nok (error, FALSE);
8200 } else {
8201 arg = *((MonoObject**)val);
8204 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8208 * mono_store_remote_field_new:
8209 * @this_obj:
8210 * @klass:
8211 * @field:
8212 * @arg:
8214 * Missing documentation
8216 void
8217 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8219 MonoError error;
8220 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8221 mono_error_cleanup (&error);
8225 * mono_store_remote_field_new_checked:
8226 * @this_obj:
8227 * @klass:
8228 * @field:
8229 * @arg:
8230 * @error:
8232 * Missing documentation
8234 gboolean
8235 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8237 MONO_REQ_GC_UNSAFE_MODE;
8239 static MonoMethod *tp_store = NULL;
8241 mono_error_init (error);
8243 g_assert (mono_object_is_transparent_proxy (this_obj));
8245 if (!tp_store) {
8246 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8247 if (!tp_store) {
8248 mono_error_set_not_supported (error, "Linked away.");
8249 return FALSE;
8253 gpointer args[3];
8254 args [0] = &klass;
8255 args [1] = &field;
8256 args [2] = arg;
8258 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8259 return is_ok (error);
8261 #endif
8264 * mono_create_ftnptr:
8266 * Given a function address, create a function descriptor for it.
8267 * This is only needed on some platforms.
8269 gpointer
8270 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8272 return callbacks.create_ftnptr (domain, addr);
8276 * mono_get_addr_from_ftnptr:
8278 * Given a pointer to a function descriptor, return the function address.
8279 * This is only needed on some platforms.
8281 gpointer
8282 mono_get_addr_from_ftnptr (gpointer descr)
8284 return callbacks.get_addr_from_ftnptr (descr);
8288 * mono_string_chars:
8289 * @s: a MonoString
8291 * Returns a pointer to the UCS16 characters stored in the MonoString
8293 gunichar2 *
8294 mono_string_chars (MonoString *s)
8296 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8298 return s->chars;
8302 * mono_string_length:
8303 * @s: MonoString
8305 * Returns the lenght in characters of the string
8308 mono_string_length (MonoString *s)
8310 MONO_REQ_GC_UNSAFE_MODE;
8312 return s->length;
8316 * mono_array_length:
8317 * @array: a MonoArray*
8319 * Returns the total number of elements in the array. This works for
8320 * both vectors and multidimensional arrays.
8322 uintptr_t
8323 mono_array_length (MonoArray *array)
8325 MONO_REQ_GC_UNSAFE_MODE;
8327 return array->max_length;
8331 * mono_array_addr_with_size:
8332 * @array: a MonoArray*
8333 * @size: size of the array elements
8334 * @idx: index into the array
8336 * Use this function to obtain the address for the @idx item on the
8337 * @array containing elements of size @size.
8339 * This method performs no bounds checking or type checking.
8341 * Returns the address of the @idx element in the array.
8343 char*
8344 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8346 MONO_REQ_GC_UNSAFE_MODE;
8348 return ((char*)(array)->vector) + size * idx;
8352 MonoArray *
8353 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8355 MonoDomain *domain = mono_domain_get ();
8356 MonoArray *res;
8357 int len, i;
8359 mono_error_init (error);
8360 if (!list)
8361 return NULL;
8363 len = g_list_length (list);
8364 res = mono_array_new_checked (domain, eclass, len, error);
8365 return_val_if_nok (error, NULL);
8367 for (i = 0; list; list = list->next, i++)
8368 mono_array_set (res, gpointer, i, list->data);
8370 return res;
8373 #if NEVER_DEFINED
8375 * The following section is purely to declare prototypes and
8376 * document the API, as these C files are processed by our
8377 * tool
8381 * mono_array_set:
8382 * @array: array to alter
8383 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8384 * @index: index into the array
8385 * @value: value to set
8387 * Value Type version: This sets the @index's element of the @array
8388 * with elements of size sizeof(type) to the provided @value.
8390 * This macro does not attempt to perform type checking or bounds checking.
8392 * Use this to set value types in a `MonoArray`.
8394 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8399 * mono_array_setref:
8400 * @array: array to alter
8401 * @index: index into the array
8402 * @value: value to set
8404 * Reference Type version: This sets the @index's element of the
8405 * @array with elements of size sizeof(type) to the provided @value.
8407 * This macro does not attempt to perform type checking or bounds checking.
8409 * Use this to reference types in a `MonoArray`.
8411 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8416 * mono_array_get:
8417 * @array: array on which to operate on
8418 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8419 * @index: index into the array
8421 * Use this macro to retrieve the @index element of an @array and
8422 * extract the value assuming that the elements of the array match
8423 * the provided type value.
8425 * This method can be used with both arrays holding value types and
8426 * reference types. For reference types, the @type parameter should
8427 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8429 * This macro does not attempt to perform type checking or bounds checking.
8431 * Returns: The element at the @index position in the @array.
8433 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8436 #endif