Fix roslyn install with AOT disabled.
[mono-project.git] / mono / metadata / object.c
blob0a6df1231eab5944092ad99a6335625ad51c0ac4
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"
53 #include <mono/io-layer/io-layer.h>
55 static void
56 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
58 static MonoString*
59 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
61 static void
62 free_main_args (void);
64 static char *
65 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
67 /* Class lazy loading functions */
68 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
69 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
70 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
71 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
72 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
75 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
76 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
77 static mono_mutex_t ldstr_section;
80 /**
81 * mono_runtime_object_init:
82 * @this_obj: the object to initialize
84 * This function calls the zero-argument constructor (which must
85 * exist) for the given object.
87 void
88 mono_runtime_object_init (MonoObject *this_obj)
90 MonoError error;
91 mono_runtime_object_init_checked (this_obj, &error);
92 mono_error_assert_ok (&error);
95 /**
96 * mono_runtime_object_init_checked:
97 * @this_obj: the object to initialize
98 * @error: set on error.
100 * This function calls the zero-argument constructor (which must
101 * exist) for the given object and returns TRUE on success, or FALSE
102 * on error and sets @error.
104 gboolean
105 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
107 MONO_REQ_GC_UNSAFE_MODE;
109 MonoMethod *method = NULL;
110 MonoClass *klass = this_obj->vtable->klass;
112 mono_error_init (error);
113 method = mono_class_get_method_from_name (klass, ".ctor", 0);
114 if (!method)
115 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
117 if (method->klass->valuetype)
118 this_obj = (MonoObject *)mono_object_unbox (this_obj);
120 mono_runtime_invoke_checked (method, this_obj, NULL, error);
121 return is_ok (error);
124 /* The pseudo algorithm for type initialization from the spec
125 Note it doesn't say anything about domains - only threads.
127 2. If the type is initialized you are done.
128 2.1. If the type is not yet initialized, try to take an
129 initialization lock.
130 2.2. If successful, record this thread as responsible for
131 initializing the type and proceed to step 2.3.
132 2.2.1. If not, see whether this thread or any thread
133 waiting for this thread to complete already holds the lock.
134 2.2.2. If so, return since blocking would create a deadlock. This thread
135 will now see an incompletely initialized state for the type,
136 but no deadlock will arise.
137 2.2.3 If not, block until the type is initialized then return.
138 2.3 Initialize the parent type and then all interfaces implemented
139 by this type.
140 2.4 Execute the type initialization code for this type.
141 2.5 Mark the type as initialized, release the initialization lock,
142 awaken any threads waiting for this type to be initialized,
143 and return.
147 typedef struct
149 MonoNativeThreadId initializing_tid;
150 guint32 waiting_count;
151 gboolean done;
152 MonoCoopMutex initialization_section;
153 } TypeInitializationLock;
155 /* for locking access to type_initialization_hash and blocked_thread_hash */
156 static MonoCoopMutex type_initialization_section;
158 static inline void
159 mono_type_initialization_lock (void)
161 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
162 mono_coop_mutex_lock (&type_initialization_section);
165 static inline void
166 mono_type_initialization_unlock (void)
168 mono_coop_mutex_unlock (&type_initialization_section);
171 static void
172 mono_type_init_lock (TypeInitializationLock *lock)
174 MONO_REQ_GC_NEUTRAL_MODE;
176 mono_coop_mutex_lock (&lock->initialization_section);
179 static void
180 mono_type_init_unlock (TypeInitializationLock *lock)
182 mono_coop_mutex_unlock (&lock->initialization_section);
185 /* from vtable to lock */
186 static GHashTable *type_initialization_hash;
188 /* from thread id to thread id being waited on */
189 static GHashTable *blocked_thread_hash;
191 /* Main thread */
192 static MonoThread *main_thread;
194 /* Functions supplied by the runtime */
195 static MonoRuntimeCallbacks callbacks;
198 * mono_thread_set_main:
199 * @thread: thread to set as the main thread
201 * This function can be used to instruct the runtime to treat @thread
202 * as the main thread, ie, the thread that would normally execute the Main()
203 * method. This basically means that at the end of @thread, the runtime will
204 * wait for the existing foreground threads to quit and other such details.
206 void
207 mono_thread_set_main (MonoThread *thread)
209 MONO_REQ_GC_UNSAFE_MODE;
211 static gboolean registered = FALSE;
213 if (!registered) {
214 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
215 registered = TRUE;
218 main_thread = thread;
221 MonoThread*
222 mono_thread_get_main (void)
224 MONO_REQ_GC_UNSAFE_MODE;
226 return main_thread;
229 void
230 mono_type_initialization_init (void)
232 mono_coop_mutex_init_recursive (&type_initialization_section);
233 type_initialization_hash = g_hash_table_new (NULL, NULL);
234 blocked_thread_hash = g_hash_table_new (NULL, NULL);
235 mono_os_mutex_init_recursive (&ldstr_section);
238 void
239 mono_type_initialization_cleanup (void)
241 #if 0
242 /* This is causing race conditions with
243 * mono_release_type_locks
245 mono_coop_mutex_destroy (&type_initialization_section);
246 g_hash_table_destroy (type_initialization_hash);
247 type_initialization_hash = NULL;
248 #endif
249 mono_os_mutex_destroy (&ldstr_section);
250 g_hash_table_destroy (blocked_thread_hash);
251 blocked_thread_hash = NULL;
253 free_main_args ();
257 * get_type_init_exception_for_vtable:
259 * Return the stored type initialization exception for VTABLE.
261 static MonoException*
262 get_type_init_exception_for_vtable (MonoVTable *vtable)
264 MONO_REQ_GC_UNSAFE_MODE;
266 MonoError error;
267 MonoDomain *domain = vtable->domain;
268 MonoClass *klass = vtable->klass;
269 MonoException *ex;
270 gchar *full_name;
272 if (!vtable->init_failed)
273 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
276 * If the initializing thread was rudely aborted, the exception is not stored
277 * in the hash.
279 ex = NULL;
280 mono_domain_lock (domain);
281 if (domain->type_init_exception_hash)
282 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
283 mono_domain_unlock (domain);
285 if (!ex) {
286 if (klass->name_space && *klass->name_space)
287 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
288 else
289 full_name = g_strdup (klass->name);
290 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
291 g_free (full_name);
292 return_val_if_nok (&error, NULL);
295 return ex;
299 * mono_runtime_class_init:
300 * @vtable: vtable that needs to be initialized
302 * This routine calls the class constructor for @vtable.
304 void
305 mono_runtime_class_init (MonoVTable *vtable)
307 MONO_REQ_GC_UNSAFE_MODE;
308 MonoError error;
310 mono_runtime_class_init_full (vtable, &error);
311 mono_error_assert_ok (&error);
315 * mono_runtime_class_init_full:
316 * @vtable that neeeds to be initialized
317 * @error set on error
319 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
322 gboolean
323 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
325 MONO_REQ_GC_UNSAFE_MODE;
327 MonoMethod *method = NULL;
328 MonoClass *klass;
329 gchar *full_name;
330 MonoDomain *domain = vtable->domain;
331 TypeInitializationLock *lock;
332 MonoNativeThreadId tid;
333 int do_initialization = 0;
334 MonoDomain *last_domain = NULL;
335 MonoException * pending_tae = NULL;
337 mono_error_init (error);
339 if (vtable->initialized)
340 return TRUE;
342 klass = vtable->klass;
344 if (!klass->image->checked_module_cctor) {
345 mono_image_check_for_module_cctor (klass->image);
346 if (klass->image->has_module_cctor) {
347 MonoClass *module_klass;
348 MonoVTable *module_vtable;
350 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
351 if (!module_klass) {
352 return FALSE;
355 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
356 if (!module_vtable)
357 return FALSE;
358 if (!mono_runtime_class_init_full (module_vtable, error))
359 return FALSE;
362 method = mono_class_get_cctor (klass);
363 if (!method) {
364 vtable->initialized = 1;
365 return TRUE;
368 tid = mono_native_thread_id_get ();
370 mono_type_initialization_lock ();
371 /* double check... */
372 if (vtable->initialized) {
373 mono_type_initialization_unlock ();
374 return TRUE;
376 if (vtable->init_failed) {
377 mono_type_initialization_unlock ();
379 /* The type initialization already failed once, rethrow the same exception */
380 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
381 return FALSE;
383 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
384 if (lock == NULL) {
385 /* This thread will get to do the initialization */
386 if (mono_domain_get () != domain) {
387 /* Transfer into the target domain */
388 last_domain = mono_domain_get ();
389 if (!mono_domain_set (domain, FALSE)) {
390 vtable->initialized = 1;
391 mono_type_initialization_unlock ();
392 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
393 return FALSE;
396 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
397 mono_coop_mutex_init_recursive (&lock->initialization_section);
398 lock->initializing_tid = tid;
399 lock->waiting_count = 1;
400 lock->done = FALSE;
401 /* grab the vtable lock while this thread still owns type_initialization_section */
402 /* This is why type_initialization_lock needs to enter blocking mode */
403 mono_type_init_lock (lock);
404 g_hash_table_insert (type_initialization_hash, vtable, lock);
405 do_initialization = 1;
406 } else {
407 gpointer blocked;
408 TypeInitializationLock *pending_lock;
410 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
411 mono_type_initialization_unlock ();
412 return TRUE;
414 /* see if the thread doing the initialization is already blocked on this thread */
415 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
416 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
417 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
418 if (!pending_lock->done) {
419 mono_type_initialization_unlock ();
420 return TRUE;
421 } else {
422 /* the thread doing the initialization is blocked on this thread,
423 but on a lock that has already been freed. It just hasn't got
424 time to awake */
425 break;
428 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
430 ++lock->waiting_count;
431 /* record the fact that we are waiting on the initializing thread */
432 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
434 mono_type_initialization_unlock ();
436 if (do_initialization) {
437 MonoException *exc = NULL;
439 mono_threads_begin_abort_protected_block ();
440 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
441 mono_threads_end_abort_protected_block ();
443 //exception extracted, error will be set to the right value later
444 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
445 exc = mono_error_convert_to_exception (error);
446 else
447 mono_error_cleanup (error);
449 mono_error_init (error);
451 /* If the initialization failed, mark the class as unusable. */
452 /* Avoid infinite loops */
453 if (!(!exc ||
454 (klass->image == mono_defaults.corlib &&
455 !strcmp (klass->name_space, "System") &&
456 !strcmp (klass->name, "TypeInitializationException")))) {
457 vtable->init_failed = 1;
459 if (klass->name_space && *klass->name_space)
460 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
461 else
462 full_name = g_strdup (klass->name);
464 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
465 g_free (full_name);
467 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
470 * Store the exception object so it could be thrown on subsequent
471 * accesses.
473 mono_domain_lock (domain);
474 if (!domain->type_init_exception_hash)
475 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");
476 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
477 mono_domain_unlock (domain);
480 if (last_domain)
481 mono_domain_set (last_domain, TRUE);
482 lock->done = TRUE;
483 mono_type_init_unlock (lock);
484 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
485 pending_tae = exc;
486 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
487 if (!pending_tae && mono_get_eh_callbacks ()->mono_above_abort_threshold ())
488 pending_tae = mono_thread_try_resume_interruption ();
489 } else {
490 /* this just blocks until the initializing thread is done */
491 mono_type_init_lock (lock);
492 mono_type_init_unlock (lock);
495 mono_type_initialization_lock ();
496 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
497 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
498 --lock->waiting_count;
499 if (lock->waiting_count == 0) {
500 mono_coop_mutex_destroy (&lock->initialization_section);
501 g_hash_table_remove (type_initialization_hash, vtable);
502 g_free (lock);
504 mono_memory_barrier ();
505 if (!vtable->init_failed)
506 vtable->initialized = 1;
507 mono_type_initialization_unlock ();
509 //TAE wins over TIE
510 if (pending_tae)
511 mono_error_set_exception_instance (error, pending_tae);
512 else if (vtable->init_failed) {
513 /* Either we were the initializing thread or we waited for the initialization */
514 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
515 return FALSE;
517 return TRUE;
520 static
521 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
523 MONO_REQ_GC_NEUTRAL_MODE;
525 MonoVTable *vtable = (MonoVTable*)key;
527 TypeInitializationLock *lock = (TypeInitializationLock*) value;
528 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
529 lock->done = TRUE;
531 * Have to set this since it cannot be set by the normal code in
532 * mono_runtime_class_init (). In this case, the exception object is not stored,
533 * and get_type_init_exception_for_class () needs to be aware of this.
535 vtable->init_failed = 1;
536 mono_type_init_unlock (lock);
537 --lock->waiting_count;
538 if (lock->waiting_count == 0) {
539 mono_coop_mutex_destroy (&lock->initialization_section);
540 g_free (lock);
541 return TRUE;
544 return FALSE;
547 void
548 mono_release_type_locks (MonoInternalThread *thread)
550 MONO_REQ_GC_UNSAFE_MODE;
552 mono_type_initialization_lock ();
553 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
554 mono_type_initialization_unlock ();
557 #ifndef DISABLE_REMOTING
559 static gpointer
560 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
562 if (!callbacks.create_remoting_trampoline)
563 g_error ("remoting not installed");
564 return callbacks.create_remoting_trampoline (domain, method, target, error);
567 #endif
569 static MonoImtTrampolineBuilder imt_trampoline_builder;
570 static gboolean always_build_imt_trampolines;
572 #if (MONO_IMT_SIZE > 32)
573 #error "MONO_IMT_SIZE cannot be larger than 32"
574 #endif
576 void
577 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
579 memcpy (&callbacks, cbs, sizeof (*cbs));
582 MonoRuntimeCallbacks*
583 mono_get_runtime_callbacks (void)
585 return &callbacks;
588 void
589 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
591 imt_trampoline_builder = func;
594 void
595 mono_set_always_build_imt_trampolines (gboolean value)
597 always_build_imt_trampolines = value;
601 * mono_compile_method:
602 * @method: The method to compile.
604 * This JIT-compiles the method, and returns the pointer to the native code
605 * produced.
607 gpointer
608 mono_compile_method (MonoMethod *method)
610 MonoError error;
611 gpointer result = mono_compile_method_checked (method, &error);
612 mono_error_cleanup (&error);
613 return result;
617 * mono_compile_method:
618 * @method: The method to compile.
619 * @error: set on error.
621 * This JIT-compiles the method, and returns the pointer to the native code
622 * produced. On failure returns NULL and sets @error.
624 gpointer
625 mono_compile_method_checked (MonoMethod *method, MonoError *error)
627 gpointer res;
629 MONO_REQ_GC_NEUTRAL_MODE
631 mono_error_init (error);
633 g_assert (callbacks.compile_method);
634 res = callbacks.compile_method (method, error);
635 return res;
638 gpointer
639 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
641 gpointer res;
643 MONO_REQ_GC_NEUTRAL_MODE;
645 mono_error_init (error);
646 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
647 return res;
650 gpointer
651 mono_runtime_create_delegate_trampoline (MonoClass *klass)
653 MONO_REQ_GC_NEUTRAL_MODE
655 g_assert (callbacks.create_delegate_trampoline);
656 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
660 * mono_runtime_free_method:
661 * @domain; domain where the method is hosted
662 * @method: method to release
664 * This routine is invoked to free the resources associated with
665 * a method that has been JIT compiled. This is used to discard
666 * methods that were used only temporarily (for example, used in marshalling)
669 void
670 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
672 MONO_REQ_GC_NEUTRAL_MODE
674 if (callbacks.free_method)
675 callbacks.free_method (domain, method);
677 mono_method_clear_object (domain, method);
679 mono_free_method (method);
683 * The vtables in the root appdomain are assumed to be reachable by other
684 * roots, and we don't use typed allocation in the other domains.
687 /* The sync block is no longer a GC pointer */
688 #define GC_HEADER_BITMAP (0)
690 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
692 static gsize*
693 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
695 MONO_REQ_GC_NEUTRAL_MODE;
697 MonoClassField *field;
698 MonoClass *p;
699 guint32 pos;
700 int max_size;
702 if (static_fields)
703 max_size = mono_class_data_size (klass) / sizeof (gpointer);
704 else
705 max_size = klass->instance_size / sizeof (gpointer);
706 if (max_size > size) {
707 g_assert (offset <= 0);
708 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
709 size = max_size;
712 #ifdef HAVE_SGEN_GC
713 /*An Ephemeron cannot be marked by sgen*/
714 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
715 *max_set = 0;
716 memset (bitmap, 0, size / 8);
717 return bitmap;
719 #endif
721 for (p = klass; p != NULL; p = p->parent) {
722 gpointer iter = NULL;
723 while ((field = mono_class_get_fields (p, &iter))) {
724 MonoType *type;
726 if (static_fields) {
727 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
728 continue;
729 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
730 continue;
731 } else {
732 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
733 continue;
735 /* FIXME: should not happen, flag as type load error */
736 if (field->type->byref)
737 break;
739 if (static_fields && field->offset == -1)
740 /* special static */
741 continue;
743 pos = field->offset / sizeof (gpointer);
744 pos += offset;
746 type = mono_type_get_underlying_type (field->type);
747 switch (type->type) {
748 case MONO_TYPE_I:
749 case MONO_TYPE_PTR:
750 case MONO_TYPE_FNPTR:
751 break;
752 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
753 case MONO_TYPE_U:
754 #ifdef HAVE_SGEN_GC
755 break;
756 #else
757 if (klass->image != mono_defaults.corlib)
758 break;
759 #endif
760 case MONO_TYPE_STRING:
761 case MONO_TYPE_SZARRAY:
762 case MONO_TYPE_CLASS:
763 case MONO_TYPE_OBJECT:
764 case MONO_TYPE_ARRAY:
765 g_assert ((field->offset % sizeof(gpointer)) == 0);
767 g_assert (pos < size || pos <= max_size);
768 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
769 *max_set = MAX (*max_set, pos);
770 break;
771 case MONO_TYPE_GENERICINST:
772 if (!mono_type_generic_inst_is_valuetype (type)) {
773 g_assert ((field->offset % sizeof(gpointer)) == 0);
775 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
776 *max_set = MAX (*max_set, pos);
777 break;
778 } else {
779 /* fall through */
781 case MONO_TYPE_VALUETYPE: {
782 MonoClass *fclass = mono_class_from_mono_type (field->type);
783 if (fclass->has_references) {
784 /* remove the object header */
785 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
787 break;
789 case MONO_TYPE_I1:
790 case MONO_TYPE_U1:
791 case MONO_TYPE_I2:
792 case MONO_TYPE_U2:
793 case MONO_TYPE_I4:
794 case MONO_TYPE_U4:
795 case MONO_TYPE_I8:
796 case MONO_TYPE_U8:
797 case MONO_TYPE_R4:
798 case MONO_TYPE_R8:
799 case MONO_TYPE_BOOLEAN:
800 case MONO_TYPE_CHAR:
801 break;
802 default:
803 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
804 break;
807 if (static_fields)
808 break;
810 return bitmap;
814 * mono_class_compute_bitmap:
816 * Mono internal function to compute a bitmap of reference fields in a class.
818 gsize*
819 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
821 MONO_REQ_GC_NEUTRAL_MODE;
823 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
826 #if 0
828 * similar to the above, but sets the bits in the bitmap for any non-ref field
829 * and ignores static fields
831 static gsize*
832 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
834 MonoClassField *field;
835 MonoClass *p;
836 guint32 pos, pos2;
837 int max_size;
839 max_size = class->instance_size / sizeof (gpointer);
840 if (max_size >= size) {
841 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
844 for (p = class; p != NULL; p = p->parent) {
845 gpointer iter = NULL;
846 while ((field = mono_class_get_fields (p, &iter))) {
847 MonoType *type;
849 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
850 continue;
851 /* FIXME: should not happen, flag as type load error */
852 if (field->type->byref)
853 break;
855 pos = field->offset / sizeof (gpointer);
856 pos += offset;
858 type = mono_type_get_underlying_type (field->type);
859 switch (type->type) {
860 #if SIZEOF_VOID_P == 8
861 case MONO_TYPE_I:
862 case MONO_TYPE_U:
863 case MONO_TYPE_PTR:
864 case MONO_TYPE_FNPTR:
865 #endif
866 case MONO_TYPE_I8:
867 case MONO_TYPE_U8:
868 case MONO_TYPE_R8:
869 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
870 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
871 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
873 /* fall through */
874 #if SIZEOF_VOID_P == 4
875 case MONO_TYPE_I:
876 case MONO_TYPE_U:
877 case MONO_TYPE_PTR:
878 case MONO_TYPE_FNPTR:
879 #endif
880 case MONO_TYPE_I4:
881 case MONO_TYPE_U4:
882 case MONO_TYPE_R4:
883 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
884 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
885 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
887 /* fall through */
888 case MONO_TYPE_CHAR:
889 case MONO_TYPE_I2:
890 case MONO_TYPE_U2:
891 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
892 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
893 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
895 /* fall through */
896 case MONO_TYPE_BOOLEAN:
897 case MONO_TYPE_I1:
898 case MONO_TYPE_U1:
899 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
900 break;
901 case MONO_TYPE_STRING:
902 case MONO_TYPE_SZARRAY:
903 case MONO_TYPE_CLASS:
904 case MONO_TYPE_OBJECT:
905 case MONO_TYPE_ARRAY:
906 break;
907 case MONO_TYPE_GENERICINST:
908 if (!mono_type_generic_inst_is_valuetype (type)) {
909 break;
910 } else {
911 /* fall through */
913 case MONO_TYPE_VALUETYPE: {
914 MonoClass *fclass = mono_class_from_mono_type (field->type);
915 /* remove the object header */
916 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
917 break;
919 default:
920 g_assert_not_reached ();
921 break;
925 return bitmap;
929 * mono_class_insecure_overlapping:
930 * check if a class with explicit layout has references and non-references
931 * fields overlapping.
933 * Returns: TRUE if it is insecure to load the type.
935 gboolean
936 mono_class_insecure_overlapping (MonoClass *klass)
938 int max_set = 0;
939 gsize *bitmap;
940 gsize default_bitmap [4] = {0};
941 gsize *nrbitmap;
942 gsize default_nrbitmap [4] = {0};
943 int i, insecure = FALSE;
944 return FALSE;
946 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
947 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
949 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
950 int idx = i % (sizeof (bitmap [0]) * 8);
951 if (bitmap [idx] & nrbitmap [idx]) {
952 insecure = TRUE;
953 break;
956 if (bitmap != default_bitmap)
957 g_free (bitmap);
958 if (nrbitmap != default_nrbitmap)
959 g_free (nrbitmap);
960 if (insecure) {
961 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
962 return FALSE;
964 return insecure;
966 #endif
968 MonoString*
969 ves_icall_string_alloc (int length)
971 MonoError error;
972 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
973 mono_error_set_pending_exception (&error);
975 return str;
978 /* LOCKING: Acquires the loader lock */
979 void
980 mono_class_compute_gc_descriptor (MonoClass *klass)
982 MONO_REQ_GC_NEUTRAL_MODE;
984 int max_set = 0;
985 gsize *bitmap;
986 gsize default_bitmap [4] = {0};
987 static gboolean gcj_inited = FALSE;
988 MonoGCDescriptor gc_descr;
990 if (!gcj_inited) {
991 mono_loader_lock ();
993 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
994 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
996 gcj_inited = TRUE;
997 mono_loader_unlock ();
1000 if (!klass->inited)
1001 mono_class_init (klass);
1003 if (klass->gc_descr_inited)
1004 return;
1006 bitmap = default_bitmap;
1007 if (klass == mono_defaults.string_class) {
1008 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1009 } else if (klass->rank) {
1010 mono_class_compute_gc_descriptor (klass->element_class);
1011 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1012 gsize abm = 1;
1013 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1014 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1015 class->name_space, class->name);*/
1016 } else {
1017 /* remove the object header */
1018 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1019 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));
1020 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1021 class->name_space, class->name);*/
1022 if (bitmap != default_bitmap)
1023 g_free (bitmap);
1025 } else {
1026 /*static int count = 0;
1027 if (count++ > 58)
1028 return;*/
1029 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1030 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1032 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1033 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1035 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1036 if (bitmap != default_bitmap)
1037 g_free (bitmap);
1040 /* Publish the data */
1041 mono_loader_lock ();
1042 klass->gc_descr = gc_descr;
1043 mono_memory_barrier ();
1044 klass->gc_descr_inited = TRUE;
1045 mono_loader_unlock ();
1049 * field_is_special_static:
1050 * @fklass: The MonoClass to look up.
1051 * @field: The MonoClassField describing the field.
1053 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1054 * SPECIAL_STATIC_NONE otherwise.
1056 static gint32
1057 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1059 MONO_REQ_GC_NEUTRAL_MODE;
1061 MonoError error;
1062 MonoCustomAttrInfo *ainfo;
1063 int i;
1064 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1065 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1066 if (!ainfo)
1067 return FALSE;
1068 for (i = 0; i < ainfo->num_attrs; ++i) {
1069 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1070 if (klass->image == mono_defaults.corlib) {
1071 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1072 mono_custom_attrs_free (ainfo);
1073 return SPECIAL_STATIC_THREAD;
1075 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1076 mono_custom_attrs_free (ainfo);
1077 return SPECIAL_STATIC_CONTEXT;
1081 mono_custom_attrs_free (ainfo);
1082 return SPECIAL_STATIC_NONE;
1085 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1086 #define mix(a,b,c) { \
1087 a -= c; a ^= rot(c, 4); c += b; \
1088 b -= a; b ^= rot(a, 6); a += c; \
1089 c -= b; c ^= rot(b, 8); b += a; \
1090 a -= c; a ^= rot(c,16); c += b; \
1091 b -= a; b ^= rot(a,19); a += c; \
1092 c -= b; c ^= rot(b, 4); b += a; \
1094 #define final(a,b,c) { \
1095 c ^= b; c -= rot(b,14); \
1096 a ^= c; a -= rot(c,11); \
1097 b ^= a; b -= rot(a,25); \
1098 c ^= b; c -= rot(b,16); \
1099 a ^= c; a -= rot(c,4); \
1100 b ^= a; b -= rot(a,14); \
1101 c ^= b; c -= rot(b,24); \
1105 * mono_method_get_imt_slot:
1107 * The IMT slot is embedded into AOTed code, so this must return the same value
1108 * for the same method across all executions. This means:
1109 * - pointers shouldn't be used as hash values.
1110 * - mono_metadata_str_hash () should be used for hashing strings.
1112 guint32
1113 mono_method_get_imt_slot (MonoMethod *method)
1115 MONO_REQ_GC_NEUTRAL_MODE;
1117 MonoMethodSignature *sig;
1118 int hashes_count;
1119 guint32 *hashes_start, *hashes;
1120 guint32 a, b, c;
1121 int i;
1123 /* This can be used to stress tests the collision code */
1124 //return 0;
1127 * We do this to simplify generic sharing. It will hurt
1128 * performance in cases where a class implements two different
1129 * instantiations of the same generic interface.
1130 * The code in build_imt_slots () depends on this.
1132 if (method->is_inflated)
1133 method = ((MonoMethodInflated*)method)->declaring;
1135 sig = mono_method_signature (method);
1136 hashes_count = sig->param_count + 4;
1137 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1138 hashes = hashes_start;
1140 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1141 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1142 method->klass->name_space, method->klass->name, method->name);
1145 /* Initialize hashes */
1146 hashes [0] = mono_metadata_str_hash (method->klass->name);
1147 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1148 hashes [2] = mono_metadata_str_hash (method->name);
1149 hashes [3] = mono_metadata_type_hash (sig->ret);
1150 for (i = 0; i < sig->param_count; i++) {
1151 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1154 /* Setup internal state */
1155 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1157 /* Handle most of the hashes */
1158 while (hashes_count > 3) {
1159 a += hashes [0];
1160 b += hashes [1];
1161 c += hashes [2];
1162 mix (a,b,c);
1163 hashes_count -= 3;
1164 hashes += 3;
1167 /* Handle the last 3 hashes (all the case statements fall through) */
1168 switch (hashes_count) {
1169 case 3 : c += hashes [2];
1170 case 2 : b += hashes [1];
1171 case 1 : a += hashes [0];
1172 final (a,b,c);
1173 case 0: /* nothing left to add */
1174 break;
1177 g_free (hashes_start);
1178 /* Report the result */
1179 return c % MONO_IMT_SIZE;
1181 #undef rot
1182 #undef mix
1183 #undef final
1185 #define DEBUG_IMT 0
1187 static void
1188 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1189 MONO_REQ_GC_NEUTRAL_MODE;
1191 guint32 imt_slot = mono_method_get_imt_slot (method);
1192 MonoImtBuilderEntry *entry;
1194 if (slot_num >= 0 && imt_slot != slot_num) {
1195 /* we build just a single imt slot and this is not it */
1196 return;
1199 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1200 entry->key = method;
1201 entry->value.vtable_slot = vtable_slot;
1202 entry->next = imt_builder [imt_slot];
1203 if (imt_builder [imt_slot] != NULL) {
1204 entry->children = imt_builder [imt_slot]->children + 1;
1205 if (entry->children == 1) {
1206 mono_stats.imt_slots_with_collisions++;
1207 *imt_collisions_bitmap |= (1 << imt_slot);
1209 } else {
1210 entry->children = 0;
1211 mono_stats.imt_used_slots++;
1213 imt_builder [imt_slot] = entry;
1214 #if DEBUG_IMT
1216 char *method_name = mono_method_full_name (method, TRUE);
1217 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1218 method, method_name, imt_slot, vtable_slot, entry->children);
1219 g_free (method_name);
1221 #endif
1224 #if DEBUG_IMT
1225 static void
1226 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1227 if (e != NULL) {
1228 MonoMethod *method = e->key;
1229 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1230 message,
1231 num,
1232 method,
1233 method->klass->name_space,
1234 method->klass->name,
1235 method->name);
1236 } else {
1237 printf (" * %s: NULL\n", message);
1240 #endif
1242 static int
1243 compare_imt_builder_entries (const void *p1, const void *p2) {
1244 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1245 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1247 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1250 static int
1251 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1253 MONO_REQ_GC_NEUTRAL_MODE;
1255 int count = end - start;
1256 int chunk_start = out_array->len;
1257 if (count < 4) {
1258 int i;
1259 for (i = start; i < end; ++i) {
1260 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1261 item->key = sorted_array [i]->key;
1262 item->value = sorted_array [i]->value;
1263 item->has_target_code = sorted_array [i]->has_target_code;
1264 item->is_equals = TRUE;
1265 if (i < end - 1)
1266 item->check_target_idx = out_array->len + 1;
1267 else
1268 item->check_target_idx = 0;
1269 g_ptr_array_add (out_array, item);
1271 } else {
1272 int middle = start + count / 2;
1273 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1275 item->key = sorted_array [middle]->key;
1276 item->is_equals = FALSE;
1277 g_ptr_array_add (out_array, item);
1278 imt_emit_ir (sorted_array, start, middle, out_array);
1279 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1281 return chunk_start;
1284 static GPtrArray*
1285 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1286 MONO_REQ_GC_NEUTRAL_MODE;
1288 int number_of_entries = entries->children + 1;
1289 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1290 GPtrArray *result = g_ptr_array_new ();
1291 MonoImtBuilderEntry *current_entry;
1292 int i;
1294 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1295 sorted_array [i] = current_entry;
1297 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1299 /*for (i = 0; i < number_of_entries; i++) {
1300 print_imt_entry (" sorted array:", sorted_array [i], i);
1303 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1305 g_free (sorted_array);
1306 return result;
1309 static gpointer
1310 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1312 MONO_REQ_GC_NEUTRAL_MODE;
1314 if (imt_builder_entry != NULL) {
1315 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1316 /* No collision, return the vtable slot contents */
1317 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1318 } else {
1319 /* Collision, build the trampoline */
1320 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1321 gpointer result;
1322 int i;
1323 result = imt_trampoline_builder (vtable, domain,
1324 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1325 for (i = 0; i < imt_ir->len; ++i)
1326 g_free (g_ptr_array_index (imt_ir, i));
1327 g_ptr_array_free (imt_ir, TRUE);
1328 return result;
1330 } else {
1331 if (fail_tramp)
1332 return fail_tramp;
1333 else
1334 /* Empty slot */
1335 return NULL;
1339 static MonoImtBuilderEntry*
1340 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1343 * LOCKING: requires the loader and domain locks.
1346 static void
1347 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1349 MONO_REQ_GC_NEUTRAL_MODE;
1351 int i;
1352 GSList *list_item;
1353 guint32 imt_collisions_bitmap = 0;
1354 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1355 int method_count = 0;
1356 gboolean record_method_count_for_max_collisions = FALSE;
1357 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1359 #if DEBUG_IMT
1360 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1361 #endif
1362 for (i = 0; i < klass->interface_offsets_count; ++i) {
1363 MonoClass *iface = klass->interfaces_packed [i];
1364 int interface_offset = klass->interface_offsets_packed [i];
1365 int method_slot_in_interface, vt_slot;
1367 if (mono_class_has_variant_generic_params (iface))
1368 has_variant_iface = TRUE;
1370 mono_class_setup_methods (iface);
1371 vt_slot = interface_offset;
1372 int mcount = mono_class_get_method_count (iface);
1373 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1374 MonoMethod *method;
1376 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1378 * The imt slot of the method is the same as for its declaring method,
1379 * see the comment in mono_method_get_imt_slot (), so we can
1380 * avoid inflating methods which will be discarded by
1381 * add_imt_builder_entry anyway.
1383 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1384 if (mono_method_get_imt_slot (method) != slot_num) {
1385 vt_slot ++;
1386 continue;
1389 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1390 if (method->is_generic) {
1391 has_generic_virtual = TRUE;
1392 vt_slot ++;
1393 continue;
1396 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1397 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1398 vt_slot ++;
1402 if (extra_interfaces) {
1403 int interface_offset = klass->vtable_size;
1405 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1406 MonoClass* iface = (MonoClass *)list_item->data;
1407 int method_slot_in_interface;
1408 int mcount = mono_class_get_method_count (iface);
1409 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1410 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1412 if (method->is_generic)
1413 has_generic_virtual = TRUE;
1414 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1416 interface_offset += mcount;
1419 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1420 /* overwrite the imt slot only if we're building all the entries or if
1421 * we're building this specific one
1423 if (slot_num < 0 || i == slot_num) {
1424 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1426 if (entries) {
1427 if (imt_builder [i]) {
1428 MonoImtBuilderEntry *entry;
1430 /* Link entries with imt_builder [i] */
1431 for (entry = entries; entry->next; entry = entry->next) {
1432 #if DEBUG_IMT
1433 MonoMethod *method = (MonoMethod*)entry->key;
1434 char *method_name = mono_method_full_name (method, TRUE);
1435 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1436 g_free (method_name);
1437 #endif
1439 entry->next = imt_builder [i];
1440 entries->children += imt_builder [i]->children + 1;
1442 imt_builder [i] = entries;
1445 if (has_generic_virtual || has_variant_iface) {
1447 * There might be collisions later when the the trampoline is expanded.
1449 imt_collisions_bitmap |= (1 << i);
1452 * The IMT trampoline might be called with an instance of one of the
1453 * generic virtual methods, so has to fallback to the IMT trampoline.
1455 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1456 } else {
1457 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1459 #if DEBUG_IMT
1460 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1461 #endif
1464 if (imt_builder [i] != NULL) {
1465 int methods_in_slot = imt_builder [i]->children + 1;
1466 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1467 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1468 record_method_count_for_max_collisions = TRUE;
1470 method_count += methods_in_slot;
1474 mono_stats.imt_number_of_methods += method_count;
1475 if (record_method_count_for_max_collisions) {
1476 mono_stats.imt_method_count_when_max_collisions = method_count;
1479 for (i = 0; i < MONO_IMT_SIZE; i++) {
1480 MonoImtBuilderEntry* entry = imt_builder [i];
1481 while (entry != NULL) {
1482 MonoImtBuilderEntry* next = entry->next;
1483 g_free (entry);
1484 entry = next;
1487 g_free (imt_builder);
1488 /* we OR the bitmap since we may build just a single imt slot at a time */
1489 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1492 static void
1493 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1494 MONO_REQ_GC_NEUTRAL_MODE;
1496 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1500 * mono_vtable_build_imt_slot:
1501 * @vtable: virtual object table struct
1502 * @imt_slot: slot in the IMT table
1504 * Fill the given @imt_slot in the IMT table of @vtable with
1505 * a trampoline or a trampoline for the case of collisions.
1506 * This is part of the internal mono API.
1508 * LOCKING: Take the domain lock.
1510 void
1511 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1513 MONO_REQ_GC_NEUTRAL_MODE;
1515 gpointer *imt = (gpointer*)vtable;
1516 imt -= MONO_IMT_SIZE;
1517 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1519 /* no support for extra interfaces: the proxy objects will need
1520 * to build the complete IMT
1521 * Update and heck needs to ahppen inside the proper domain lock, as all
1522 * the changes made to a MonoVTable.
1524 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1525 mono_domain_lock (vtable->domain);
1526 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1527 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1528 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1529 mono_domain_unlock (vtable->domain);
1530 mono_loader_unlock ();
1533 #define THUNK_THRESHOLD 10
1536 * mono_method_alloc_generic_virtual_trampoline:
1537 * @domain: a domain
1538 * @size: size in bytes
1540 * Allocs size bytes to be used for the code of a generic virtual
1541 * trampoline. It's either allocated from the domain's code manager or
1542 * reused from a previously invalidated piece.
1544 * LOCKING: The domain lock must be held.
1546 gpointer
1547 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1549 MONO_REQ_GC_NEUTRAL_MODE;
1551 static gboolean inited = FALSE;
1552 static int generic_virtual_trampolines_size = 0;
1554 if (!inited) {
1555 mono_counters_register ("Generic virtual trampoline bytes",
1556 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1557 inited = TRUE;
1559 generic_virtual_trampolines_size += size;
1561 return mono_domain_code_reserve (domain, size);
1564 typedef struct _GenericVirtualCase {
1565 MonoMethod *method;
1566 gpointer code;
1567 int count;
1568 struct _GenericVirtualCase *next;
1569 } GenericVirtualCase;
1572 * get_generic_virtual_entries:
1574 * Return IMT entries for the generic virtual method instances and
1575 * variant interface methods for vtable slot
1576 * VTABLE_SLOT.
1578 static MonoImtBuilderEntry*
1579 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1581 MONO_REQ_GC_NEUTRAL_MODE;
1583 GenericVirtualCase *list;
1584 MonoImtBuilderEntry *entries;
1586 mono_domain_lock (domain);
1587 if (!domain->generic_virtual_cases)
1588 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1590 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1592 entries = NULL;
1593 for (; list; list = list->next) {
1594 MonoImtBuilderEntry *entry;
1596 if (list->count < THUNK_THRESHOLD)
1597 continue;
1599 entry = g_new0 (MonoImtBuilderEntry, 1);
1600 entry->key = list->method;
1601 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1602 entry->has_target_code = 1;
1603 if (entries)
1604 entry->children = entries->children + 1;
1605 entry->next = entries;
1606 entries = entry;
1609 mono_domain_unlock (domain);
1611 /* FIXME: Leaking memory ? */
1612 return entries;
1616 * mono_method_add_generic_virtual_invocation:
1617 * @domain: a domain
1618 * @vtable_slot: pointer to the vtable slot
1619 * @method: the inflated generic virtual method
1620 * @code: the method's code
1622 * Registers a call via unmanaged code to a generic virtual method
1623 * instantiation or variant interface method. If the number of calls reaches a threshold
1624 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1625 * virtual method trampoline.
1627 void
1628 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1629 gpointer *vtable_slot,
1630 MonoMethod *method, gpointer code)
1632 MONO_REQ_GC_NEUTRAL_MODE;
1634 static gboolean inited = FALSE;
1635 static int num_added = 0;
1636 static int num_freed = 0;
1638 GenericVirtualCase *gvc, *list;
1639 MonoImtBuilderEntry *entries;
1640 int i;
1641 GPtrArray *sorted;
1643 mono_domain_lock (domain);
1644 if (!domain->generic_virtual_cases)
1645 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1647 if (!inited) {
1648 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1649 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1650 inited = TRUE;
1653 /* Check whether the case was already added */
1654 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1655 gvc = list;
1656 while (gvc) {
1657 if (gvc->method == method)
1658 break;
1659 gvc = gvc->next;
1662 /* If not found, make a new one */
1663 if (!gvc) {
1664 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1665 gvc->method = method;
1666 gvc->code = code;
1667 gvc->count = 0;
1668 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1670 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1672 num_added++;
1675 if (++gvc->count == THUNK_THRESHOLD) {
1676 gpointer *old_thunk = (void **)*vtable_slot;
1677 gpointer vtable_trampoline = NULL;
1678 gpointer imt_trampoline = NULL;
1680 if ((gpointer)vtable_slot < (gpointer)vtable) {
1681 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1682 int imt_slot = MONO_IMT_SIZE + displacement;
1684 /* Force the rebuild of the trampoline at the next call */
1685 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1686 *vtable_slot = imt_trampoline;
1687 } else {
1688 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1690 entries = get_generic_virtual_entries (domain, vtable_slot);
1692 sorted = imt_sort_slot_entries (entries);
1694 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1695 vtable_trampoline);
1697 while (entries) {
1698 MonoImtBuilderEntry *next = entries->next;
1699 g_free (entries);
1700 entries = next;
1703 for (i = 0; i < sorted->len; ++i)
1704 g_free (g_ptr_array_index (sorted, i));
1705 g_ptr_array_free (sorted, TRUE);
1707 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1708 num_freed ++;
1712 mono_domain_unlock (domain);
1715 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1718 * mono_class_vtable:
1719 * @domain: the application domain
1720 * @class: the class to initialize
1722 * VTables are domain specific because we create domain specific code, and
1723 * they contain the domain specific static class data.
1724 * On failure, NULL is returned, and class->exception_type is set.
1726 MonoVTable *
1727 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1729 MonoError error;
1730 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1731 mono_error_cleanup (&error);
1732 return vtable;
1736 * mono_class_vtable_full:
1737 * @domain: the application domain
1738 * @class: the class to initialize
1739 * @error set on failure.
1741 * VTables are domain specific because we create domain specific code, and
1742 * they contain the domain specific static class data.
1744 MonoVTable *
1745 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1747 MONO_REQ_GC_UNSAFE_MODE;
1749 MonoClassRuntimeInfo *runtime_info;
1751 mono_error_init (error);
1753 g_assert (klass);
1755 if (mono_class_has_failure (klass)) {
1756 mono_error_set_for_class_failure (error, klass);
1757 return NULL;
1760 /* this check can be inlined in jitted code, too */
1761 runtime_info = klass->runtime_info;
1762 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1763 return runtime_info->domain_vtables [domain->domain_id];
1764 return mono_class_create_runtime_vtable (domain, klass, error);
1768 * mono_class_try_get_vtable:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1772 * This function tries to get the associated vtable from @class if
1773 * it was already created.
1775 MonoVTable *
1776 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1778 MONO_REQ_GC_NEUTRAL_MODE;
1780 MonoClassRuntimeInfo *runtime_info;
1782 g_assert (klass);
1784 runtime_info = klass->runtime_info;
1785 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1786 return runtime_info->domain_vtables [domain->domain_id];
1787 return NULL;
1790 static gpointer*
1791 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1793 MONO_REQ_GC_NEUTRAL_MODE;
1795 size_t alloc_offset;
1798 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1799 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1800 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1802 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1803 g_assert ((imt_table_bytes & 7) == 4);
1804 vtable_size += 4;
1805 alloc_offset = 4;
1806 } else {
1807 alloc_offset = 0;
1810 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1813 static MonoVTable *
1814 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1816 MONO_REQ_GC_UNSAFE_MODE;
1818 MonoVTable *vt;
1819 MonoClassRuntimeInfo *runtime_info, *old_info;
1820 MonoClassField *field;
1821 char *t;
1822 int i, vtable_slots;
1823 size_t imt_table_bytes;
1824 int gc_bits;
1825 guint32 vtable_size, class_size;
1826 gpointer iter;
1827 gpointer *interface_offsets;
1829 mono_error_init (error);
1831 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1832 mono_domain_lock (domain);
1833 runtime_info = klass->runtime_info;
1834 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1835 mono_domain_unlock (domain);
1836 mono_loader_unlock ();
1837 return runtime_info->domain_vtables [domain->domain_id];
1839 if (!klass->inited || mono_class_has_failure (klass)) {
1840 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1841 mono_domain_unlock (domain);
1842 mono_loader_unlock ();
1843 mono_error_set_for_class_failure (error, klass);
1844 return NULL;
1848 /* Array types require that their element type be valid*/
1849 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1850 MonoClass *element_class = klass->element_class;
1851 if (!element_class->inited)
1852 mono_class_init (element_class);
1854 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1855 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1856 mono_class_setup_vtable (element_class);
1858 if (mono_class_has_failure (element_class)) {
1859 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1860 if (!mono_class_has_failure (klass))
1861 mono_class_set_type_load_failure (klass, "");
1862 mono_domain_unlock (domain);
1863 mono_loader_unlock ();
1864 mono_error_set_for_class_failure (error, klass);
1865 return NULL;
1870 * For some classes, mono_class_init () already computed klass->vtable_size, and
1871 * that is all that is needed because of the vtable trampolines.
1873 if (!klass->vtable_size)
1874 mono_class_setup_vtable (klass);
1876 if (mono_class_is_ginst (klass) && !klass->vtable)
1877 mono_class_check_vtable_constraints (klass, NULL);
1879 /* Initialize klass->has_finalize */
1880 mono_class_has_finalizer (klass);
1882 if (mono_class_has_failure (klass)) {
1883 mono_domain_unlock (domain);
1884 mono_loader_unlock ();
1885 mono_error_set_for_class_failure (error, klass);
1886 return NULL;
1889 vtable_slots = klass->vtable_size;
1890 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1891 class_size = mono_class_data_size (klass);
1892 if (class_size)
1893 vtable_slots++;
1895 if (klass->interface_offsets_count) {
1896 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1897 mono_stats.imt_number_of_tables++;
1898 mono_stats.imt_tables_size += imt_table_bytes;
1899 } else {
1900 imt_table_bytes = 0;
1903 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1905 mono_stats.used_class_count++;
1906 mono_stats.class_vtable_size += vtable_size;
1908 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1909 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1910 g_assert (!((gsize)vt & 7));
1912 vt->klass = klass;
1913 vt->rank = klass->rank;
1914 vt->domain = domain;
1916 mono_class_compute_gc_descriptor (klass);
1918 * We can't use typed allocation in the non-root domains, since the
1919 * collector needs the GC descriptor stored in the vtable even after
1920 * the mempool containing the vtable is destroyed when the domain is
1921 * unloaded. An alternative might be to allocate vtables in the GC
1922 * heap, but this does not seem to work (it leads to crashes inside
1923 * libgc). If that approach is tried, two gc descriptors need to be
1924 * allocated for each class: one for the root domain, and one for all
1925 * other domains. The second descriptor should contain a bit for the
1926 * vtable field in MonoObject, since we can no longer assume the
1927 * vtable is reachable by other roots after the appdomain is unloaded.
1929 #ifdef HAVE_BOEHM_GC
1930 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1931 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1932 else
1933 #endif
1934 vt->gc_descr = klass->gc_descr;
1936 gc_bits = mono_gc_get_vtable_bits (klass);
1937 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1939 vt->gc_bits = gc_bits;
1941 if (class_size) {
1942 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1943 if (klass->has_static_refs) {
1944 MonoGCDescriptor statics_gc_descr;
1945 int max_set = 0;
1946 gsize default_bitmap [4] = {0};
1947 gsize *bitmap;
1949 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1950 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1951 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1952 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1953 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1954 if (bitmap != default_bitmap)
1955 g_free (bitmap);
1956 } else {
1957 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1959 vt->has_static_fields = TRUE;
1960 mono_stats.class_static_data_size += class_size;
1963 iter = NULL;
1964 while ((field = mono_class_get_fields (klass, &iter))) {
1965 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1966 continue;
1967 if (mono_field_is_deleted (field))
1968 continue;
1969 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1970 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1971 if (special_static != SPECIAL_STATIC_NONE) {
1972 guint32 size, offset;
1973 gint32 align;
1974 gsize default_bitmap [4] = {0};
1975 gsize *bitmap;
1976 int max_set = 0;
1977 int numbits;
1978 MonoClass *fclass;
1979 if (mono_type_is_reference (field->type)) {
1980 default_bitmap [0] = 1;
1981 numbits = 1;
1982 bitmap = default_bitmap;
1983 } else if (mono_type_is_struct (field->type)) {
1984 fclass = mono_class_from_mono_type (field->type);
1985 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1986 numbits = max_set + 1;
1987 } else {
1988 default_bitmap [0] = 0;
1989 numbits = 0;
1990 bitmap = default_bitmap;
1992 size = mono_type_size (field->type, &align);
1993 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1994 if (!domain->special_static_fields)
1995 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1996 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1997 if (bitmap != default_bitmap)
1998 g_free (bitmap);
2000 * This marks the field as special static to speed up the
2001 * checks in mono_field_static_get/set_value ().
2003 field->offset = -1;
2004 continue;
2007 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2008 MonoClass *fklass = mono_class_from_mono_type (field->type);
2009 const char *data = mono_field_get_data (field);
2011 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2012 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2013 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2014 if (!data)
2015 continue;
2016 if (fklass->valuetype) {
2017 memcpy (t, data, mono_class_value_size (fklass, NULL));
2018 } else {
2019 /* it's a pointer type: add check */
2020 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2021 *t = *(char *)data;
2023 continue;
2027 vt->max_interface_id = klass->max_interface_id;
2028 vt->interface_bitmap = klass->interface_bitmap;
2030 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2031 // class->name, klass->interface_offsets_count);
2033 /* Initialize vtable */
2034 if (callbacks.get_vtable_trampoline) {
2035 // This also covers the AOT case
2036 for (i = 0; i < klass->vtable_size; ++i) {
2037 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2039 } else {
2040 mono_class_setup_vtable (klass);
2042 for (i = 0; i < klass->vtable_size; ++i) {
2043 MonoMethod *cm;
2045 cm = klass->vtable [i];
2046 if (cm) {
2047 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2048 if (!is_ok (error)) {
2049 mono_domain_unlock (domain);
2050 mono_loader_unlock ();
2051 return NULL;
2057 if (imt_table_bytes) {
2058 /* Now that the vtable is full, we can actually fill up the IMT */
2059 for (i = 0; i < MONO_IMT_SIZE; ++i)
2060 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2064 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2065 * re-acquire them and check if another thread has created the vtable in the meantime.
2067 /* Special case System.MonoType to avoid infinite recursion */
2068 if (klass != mono_defaults.runtimetype_class) {
2069 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2070 if (!is_ok (error)) {
2071 mono_domain_unlock (domain);
2072 mono_loader_unlock ();
2073 return NULL;
2076 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2077 /* This is unregistered in
2078 unregister_vtable_reflection_type() in
2079 domain.c. */
2080 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2083 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2085 /* class_vtable_array keeps an array of created vtables
2087 g_ptr_array_add (domain->class_vtable_array, vt);
2088 /* klass->runtime_info is protected by the loader lock, both when
2089 * it it enlarged and when it is stored info.
2093 * Store the vtable in klass->runtime_info.
2094 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2096 mono_memory_barrier ();
2098 old_info = klass->runtime_info;
2099 if (old_info && old_info->max_domain >= domain->domain_id) {
2100 /* someone already created a large enough runtime info */
2101 old_info->domain_vtables [domain->domain_id] = vt;
2102 } else {
2103 int new_size = domain->domain_id;
2104 if (old_info)
2105 new_size = MAX (new_size, old_info->max_domain);
2106 new_size++;
2107 /* make the new size a power of two */
2108 i = 2;
2109 while (new_size > i)
2110 i <<= 1;
2111 new_size = i;
2112 /* this is a bounded memory retention issue: may want to
2113 * handle it differently when we'll have a rcu-like system.
2115 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2116 runtime_info->max_domain = new_size - 1;
2117 /* copy the stuff from the older info */
2118 if (old_info) {
2119 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2121 runtime_info->domain_vtables [domain->domain_id] = vt;
2122 /* keep this last*/
2123 mono_memory_barrier ();
2124 klass->runtime_info = runtime_info;
2127 if (klass == mono_defaults.runtimetype_class) {
2128 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2129 if (!is_ok (error)) {
2130 mono_domain_unlock (domain);
2131 mono_loader_unlock ();
2132 return NULL;
2135 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2136 /* This is unregistered in
2137 unregister_vtable_reflection_type() in
2138 domain.c. */
2139 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2142 mono_domain_unlock (domain);
2143 mono_loader_unlock ();
2145 /* make sure the parent is initialized */
2146 /*FIXME shouldn't this fail the current type?*/
2147 if (klass->parent)
2148 mono_class_vtable_full (domain, klass->parent, error);
2150 return vt;
2153 #ifndef DISABLE_REMOTING
2155 * mono_class_proxy_vtable:
2156 * @domain: the application domain
2157 * @remove_class: the remote class
2158 * @error: set on error
2160 * Creates a vtable for transparent proxies. It is basically
2161 * a copy of the real vtable of the class wrapped in @remote_class,
2162 * but all function pointers invoke the remoting functions, and
2163 * vtable->klass points to the transparent proxy class, and not to @class.
2165 * On failure returns NULL and sets @error
2167 static MonoVTable *
2168 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2170 MONO_REQ_GC_UNSAFE_MODE;
2172 MonoVTable *vt, *pvt;
2173 int i, j, vtsize, extra_interface_vtsize = 0;
2174 guint32 max_interface_id;
2175 MonoClass *k;
2176 GSList *extra_interfaces = NULL;
2177 MonoClass *klass = remote_class->proxy_class;
2178 gpointer *interface_offsets;
2179 uint8_t *bitmap = NULL;
2180 int bsize;
2181 size_t imt_table_bytes;
2183 #ifdef COMPRESSED_INTERFACE_BITMAP
2184 int bcsize;
2185 #endif
2187 mono_error_init (error);
2189 vt = mono_class_vtable (domain, klass);
2190 g_assert (vt); /*FIXME property handle failure*/
2191 max_interface_id = vt->max_interface_id;
2193 /* Calculate vtable space for extra interfaces */
2194 for (j = 0; j < remote_class->interface_count; j++) {
2195 MonoClass* iclass = remote_class->interfaces[j];
2196 GPtrArray *ifaces;
2197 int method_count;
2199 /*FIXME test for interfaces with variant generic arguments*/
2200 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2201 continue; /* interface implemented by the class */
2202 if (g_slist_find (extra_interfaces, iclass))
2203 continue;
2205 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2207 method_count = mono_class_num_methods (iclass);
2209 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2210 if (!is_ok (error))
2211 goto failure;
2212 if (ifaces) {
2213 for (i = 0; i < ifaces->len; ++i) {
2214 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2215 /*FIXME test for interfaces with variant generic arguments*/
2216 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2217 continue; /* interface implemented by the class */
2218 if (g_slist_find (extra_interfaces, ic))
2219 continue;
2220 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2221 method_count += mono_class_num_methods (ic);
2223 g_ptr_array_free (ifaces, TRUE);
2224 ifaces = NULL;
2227 extra_interface_vtsize += method_count * sizeof (gpointer);
2228 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2231 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2232 mono_stats.imt_number_of_tables++;
2233 mono_stats.imt_tables_size += imt_table_bytes;
2235 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2237 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2239 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2240 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2241 g_assert (!((gsize)pvt & 7));
2243 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2245 pvt->klass = mono_defaults.transparent_proxy_class;
2246 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2247 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2249 /* initialize vtable */
2250 mono_class_setup_vtable (klass);
2251 for (i = 0; i < klass->vtable_size; ++i) {
2252 MonoMethod *cm;
2254 if ((cm = klass->vtable [i])) {
2255 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2256 if (!is_ok (error))
2257 goto failure;
2258 } else
2259 pvt->vtable [i] = NULL;
2262 if (mono_class_is_abstract (klass)) {
2263 /* create trampolines for abstract methods */
2264 for (k = klass; k; k = k->parent) {
2265 MonoMethod* m;
2266 gpointer iter = NULL;
2267 while ((m = mono_class_get_methods (k, &iter)))
2268 if (!pvt->vtable [m->slot]) {
2269 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2270 if (!is_ok (error))
2271 goto failure;
2276 pvt->max_interface_id = max_interface_id;
2277 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2278 #ifdef COMPRESSED_INTERFACE_BITMAP
2279 bitmap = (uint8_t *)g_malloc0 (bsize);
2280 #else
2281 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2282 #endif
2284 for (i = 0; i < klass->interface_offsets_count; ++i) {
2285 int interface_id = klass->interfaces_packed [i]->interface_id;
2286 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2289 if (extra_interfaces) {
2290 int slot = klass->vtable_size;
2291 MonoClass* interf;
2292 gpointer iter;
2293 MonoMethod* cm;
2294 GSList *list_item;
2296 /* Create trampolines for the methods of the interfaces */
2297 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2298 interf = (MonoClass *)list_item->data;
2300 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2302 iter = NULL;
2303 j = 0;
2304 while ((cm = mono_class_get_methods (interf, &iter))) {
2305 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2306 if (!is_ok (error))
2307 goto failure;
2310 slot += mono_class_num_methods (interf);
2314 /* Now that the vtable is full, we can actually fill up the IMT */
2315 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2316 if (extra_interfaces) {
2317 g_slist_free (extra_interfaces);
2320 #ifdef COMPRESSED_INTERFACE_BITMAP
2321 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2322 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2323 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2324 g_free (bitmap);
2325 #else
2326 pvt->interface_bitmap = bitmap;
2327 #endif
2328 return pvt;
2329 failure:
2330 if (extra_interfaces)
2331 g_slist_free (extra_interfaces);
2332 #ifdef COMPRESSED_INTERFACE_BITMAP
2333 g_free (bitmap);
2334 #endif
2335 return NULL;
2338 #endif /* DISABLE_REMOTING */
2341 * mono_class_field_is_special_static:
2343 * Returns whether @field is a thread/context static field.
2345 gboolean
2346 mono_class_field_is_special_static (MonoClassField *field)
2348 MONO_REQ_GC_NEUTRAL_MODE
2350 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2351 return FALSE;
2352 if (mono_field_is_deleted (field))
2353 return FALSE;
2354 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2355 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2356 return TRUE;
2358 return FALSE;
2362 * mono_class_field_get_special_static_type:
2363 * @field: The MonoClassField describing the field.
2365 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2366 * SPECIAL_STATIC_NONE otherwise.
2368 guint32
2369 mono_class_field_get_special_static_type (MonoClassField *field)
2371 MONO_REQ_GC_NEUTRAL_MODE
2373 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2374 return SPECIAL_STATIC_NONE;
2375 if (mono_field_is_deleted (field))
2376 return SPECIAL_STATIC_NONE;
2377 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2378 return field_is_special_static (field->parent, field);
2379 return SPECIAL_STATIC_NONE;
2383 * mono_class_has_special_static_fields:
2385 * Returns whenever @klass has any thread/context static fields.
2387 gboolean
2388 mono_class_has_special_static_fields (MonoClass *klass)
2390 MONO_REQ_GC_NEUTRAL_MODE
2392 MonoClassField *field;
2393 gpointer iter;
2395 iter = NULL;
2396 while ((field = mono_class_get_fields (klass, &iter))) {
2397 g_assert (field->parent == klass);
2398 if (mono_class_field_is_special_static (field))
2399 return TRUE;
2402 return FALSE;
2405 #ifndef DISABLE_REMOTING
2407 * create_remote_class_key:
2408 * Creates an array of pointers that can be used as a hash key for a remote class.
2409 * The first element of the array is the number of pointers.
2411 static gpointer*
2412 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2414 MONO_REQ_GC_NEUTRAL_MODE;
2416 gpointer *key;
2417 int i, j;
2419 if (remote_class == NULL) {
2420 if (mono_class_is_interface (extra_class)) {
2421 key = (void **)g_malloc (sizeof(gpointer) * 3);
2422 key [0] = GINT_TO_POINTER (2);
2423 key [1] = mono_defaults.marshalbyrefobject_class;
2424 key [2] = extra_class;
2425 } else {
2426 key = (void **)g_malloc (sizeof(gpointer) * 2);
2427 key [0] = GINT_TO_POINTER (1);
2428 key [1] = extra_class;
2430 } else {
2431 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2432 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2433 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2434 key [1] = remote_class->proxy_class;
2436 // Keep the list of interfaces sorted
2437 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2438 if (extra_class && remote_class->interfaces [i] > extra_class) {
2439 key [j++] = extra_class;
2440 extra_class = NULL;
2442 key [j] = remote_class->interfaces [i];
2444 if (extra_class)
2445 key [j] = extra_class;
2446 } else {
2447 // Replace the old class. The interface list is the same
2448 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2449 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2450 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2451 for (i = 0; i < remote_class->interface_count; i++)
2452 key [2 + i] = remote_class->interfaces [i];
2456 return key;
2460 * copy_remote_class_key:
2462 * Make a copy of KEY in the domain and return the copy.
2464 static gpointer*
2465 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2467 MONO_REQ_GC_NEUTRAL_MODE
2469 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2470 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2472 memcpy (mp_key, key, key_size);
2474 return mp_key;
2478 * mono_remote_class:
2479 * @domain: the application domain
2480 * @class_name: name of the remote class
2481 * @error: set on error
2483 * Creates and initializes a MonoRemoteClass object for a remote type.
2485 * On failure returns NULL and sets @error
2487 MonoRemoteClass*
2488 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2490 MONO_REQ_GC_UNSAFE_MODE;
2492 MonoRemoteClass *rc;
2493 gpointer* key, *mp_key;
2494 char *name;
2496 mono_error_init (error);
2498 key = create_remote_class_key (NULL, proxy_class);
2500 mono_domain_lock (domain);
2501 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2503 if (rc) {
2504 g_free (key);
2505 mono_domain_unlock (domain);
2506 return rc;
2509 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2510 if (!is_ok (error)) {
2511 g_free (key);
2512 mono_domain_unlock (domain);
2513 return NULL;
2516 mp_key = copy_remote_class_key (domain, key);
2517 g_free (key);
2518 key = mp_key;
2520 if (mono_class_is_interface (proxy_class)) {
2521 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2522 rc->interface_count = 1;
2523 rc->interfaces [0] = proxy_class;
2524 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2525 } else {
2526 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2527 rc->interface_count = 0;
2528 rc->proxy_class = proxy_class;
2531 rc->default_vtable = NULL;
2532 rc->xdomain_vtable = NULL;
2533 rc->proxy_class_name = name;
2534 #ifndef DISABLE_PERFCOUNTERS
2535 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2536 #endif
2538 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2540 mono_domain_unlock (domain);
2541 return rc;
2545 * clone_remote_class:
2546 * Creates a copy of the remote_class, adding the provided class or interface
2548 static MonoRemoteClass*
2549 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2551 MONO_REQ_GC_NEUTRAL_MODE;
2553 MonoRemoteClass *rc;
2554 gpointer* key, *mp_key;
2556 key = create_remote_class_key (remote_class, extra_class);
2557 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2558 if (rc != NULL) {
2559 g_free (key);
2560 return rc;
2563 mp_key = copy_remote_class_key (domain, key);
2564 g_free (key);
2565 key = mp_key;
2567 if (mono_class_is_interface (extra_class)) {
2568 int i,j;
2569 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2570 rc->proxy_class = remote_class->proxy_class;
2571 rc->interface_count = remote_class->interface_count + 1;
2573 // Keep the list of interfaces sorted, since the hash key of
2574 // the remote class depends on this
2575 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2576 if (remote_class->interfaces [i] > extra_class && i == j)
2577 rc->interfaces [j++] = extra_class;
2578 rc->interfaces [j] = remote_class->interfaces [i];
2580 if (i == j)
2581 rc->interfaces [j] = extra_class;
2582 } else {
2583 // Replace the old class. The interface array is the same
2584 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2585 rc->proxy_class = extra_class;
2586 rc->interface_count = remote_class->interface_count;
2587 if (rc->interface_count > 0)
2588 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2591 rc->default_vtable = NULL;
2592 rc->xdomain_vtable = NULL;
2593 rc->proxy_class_name = remote_class->proxy_class_name;
2595 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2597 return rc;
2600 gpointer
2601 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2603 MONO_REQ_GC_UNSAFE_MODE;
2605 mono_error_init (error);
2607 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2608 mono_domain_lock (domain);
2609 if (rp->target_domain_id != -1) {
2610 if (remote_class->xdomain_vtable == NULL)
2611 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2612 mono_domain_unlock (domain);
2613 mono_loader_unlock ();
2614 return_val_if_nok (error, NULL);
2615 return remote_class->xdomain_vtable;
2617 if (remote_class->default_vtable == NULL) {
2618 MonoType *type;
2619 MonoClass *klass;
2620 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2621 klass = mono_class_from_mono_type (type);
2622 #ifndef DISABLE_COM
2623 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)))
2624 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2625 else
2626 #endif
2627 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2628 /* N.B. both branches of the if modify error */
2629 if (!is_ok (error)) {
2630 mono_domain_unlock (domain);
2631 mono_loader_unlock ();
2632 return NULL;
2636 mono_domain_unlock (domain);
2637 mono_loader_unlock ();
2638 return remote_class->default_vtable;
2642 * mono_upgrade_remote_class:
2643 * @domain: the application domain
2644 * @tproxy: the proxy whose remote class has to be upgraded.
2645 * @klass: class to which the remote class can be casted.
2646 * @error: set on error
2648 * Updates the vtable of the remote class by adding the necessary method slots
2649 * and interface offsets so it can be safely casted to klass. klass can be a
2650 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2652 gboolean
2653 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2655 MONO_REQ_GC_UNSAFE_MODE;
2657 MonoTransparentProxy *tproxy;
2658 MonoRemoteClass *remote_class;
2659 gboolean redo_vtable;
2661 mono_error_init (error);
2662 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2663 mono_domain_lock (domain);
2665 tproxy = (MonoTransparentProxy*) proxy_object;
2666 remote_class = tproxy->remote_class;
2668 if (mono_class_is_interface (klass)) {
2669 int i;
2670 redo_vtable = TRUE;
2671 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2672 if (remote_class->interfaces [i] == klass)
2673 redo_vtable = FALSE;
2675 else {
2676 redo_vtable = (remote_class->proxy_class != klass);
2679 if (redo_vtable) {
2680 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2681 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2682 if (!is_ok (error))
2683 goto leave;
2686 leave:
2687 mono_domain_unlock (domain);
2688 mono_loader_unlock ();
2689 return is_ok (error);
2691 #endif /* DISABLE_REMOTING */
2695 * mono_object_get_virtual_method:
2696 * @obj: object to operate on.
2697 * @method: method
2699 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2700 * the instance of a callvirt of method.
2702 MonoMethod*
2703 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2705 MONO_REQ_GC_UNSAFE_MODE;
2707 MonoClass *klass;
2708 MonoMethod **vtable;
2709 gboolean is_proxy = FALSE;
2710 MonoMethod *res = NULL;
2712 klass = mono_object_class (obj);
2713 #ifndef DISABLE_REMOTING
2714 if (klass == mono_defaults.transparent_proxy_class) {
2715 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2716 is_proxy = TRUE;
2718 #endif
2720 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2721 return method;
2723 mono_class_setup_vtable (klass);
2724 vtable = klass->vtable;
2726 if (method->slot == -1) {
2727 /* method->slot might not be set for instances of generic methods */
2728 if (method->is_inflated) {
2729 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2730 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2731 } else {
2732 if (!is_proxy)
2733 g_assert_not_reached ();
2737 /* check method->slot is a valid index: perform isinstance? */
2738 if (method->slot != -1) {
2739 if (mono_class_is_interface (method->klass)) {
2740 if (!is_proxy) {
2741 gboolean variance_used = FALSE;
2742 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2743 g_assert (iface_offset > 0);
2744 res = vtable [iface_offset + method->slot];
2746 } else {
2747 res = vtable [method->slot];
2751 #ifndef DISABLE_REMOTING
2752 if (is_proxy) {
2753 /* It may be an interface, abstract class method or generic method */
2754 if (!res || mono_method_signature (res)->generic_param_count)
2755 res = method;
2757 /* generic methods demand invoke_with_check */
2758 if (mono_method_signature (res)->generic_param_count)
2759 res = mono_marshal_get_remoting_invoke_with_check (res);
2760 else {
2761 #ifndef DISABLE_COM
2762 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2763 res = mono_cominterop_get_invoke (res);
2764 else
2765 #endif
2766 res = mono_marshal_get_remoting_invoke (res);
2768 } else
2769 #endif
2771 if (method->is_inflated) {
2772 MonoError error;
2773 /* Have to inflate the result */
2774 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2775 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2779 g_assert (res);
2781 return res;
2784 static MonoObject*
2785 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2787 MONO_REQ_GC_UNSAFE_MODE;
2789 MonoObject *result = NULL;
2791 g_assert (callbacks.runtime_invoke);
2793 mono_error_init (error);
2795 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2796 mono_profiler_method_start_invoke (method);
2798 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2800 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2801 mono_profiler_method_end_invoke (method);
2803 if (!mono_error_ok (error))
2804 return NULL;
2806 return result;
2810 * mono_runtime_invoke:
2811 * @method: method to invoke
2812 * @obJ: object instance
2813 * @params: arguments to the method
2814 * @exc: exception information.
2816 * Invokes the method represented by @method on the object @obj.
2818 * obj is the 'this' pointer, it should be NULL for static
2819 * methods, a MonoObject* for object instances and a pointer to
2820 * the value type for value types.
2822 * The params array contains the arguments to the method with the
2823 * same convention: MonoObject* pointers for object instances and
2824 * pointers to the value type otherwise.
2826 * From unmanaged code you'll usually use the
2827 * mono_runtime_invoke() variant.
2829 * Note that this function doesn't handle virtual methods for
2830 * you, it will exec the exact method you pass: we still need to
2831 * expose a function to lookup the derived class implementation
2832 * of a virtual method (there are examples of this in the code,
2833 * though).
2835 * You can pass NULL as the exc argument if you don't want to
2836 * catch exceptions, otherwise, *exc will be set to the exception
2837 * thrown, if any. if an exception is thrown, you can't use the
2838 * MonoObject* result from the function.
2840 * If the method returns a value type, it is boxed in an object
2841 * reference.
2843 MonoObject*
2844 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2846 MonoError error;
2847 MonoObject *res;
2848 if (exc) {
2849 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2850 if (*exc == NULL && !mono_error_ok(&error)) {
2851 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2852 } else
2853 mono_error_cleanup (&error);
2854 } else {
2855 res = mono_runtime_invoke_checked (method, obj, params, &error);
2856 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2858 return res;
2862 * mono_runtime_try_invoke:
2863 * @method: method to invoke
2864 * @obJ: object instance
2865 * @params: arguments to the method
2866 * @exc: exception information.
2867 * @error: set on error
2869 * Invokes the method represented by @method on the object @obj.
2871 * obj is the 'this' pointer, it should be NULL for static
2872 * methods, a MonoObject* for object instances and a pointer to
2873 * the value type for value types.
2875 * The params array contains the arguments to the method with the
2876 * same convention: MonoObject* pointers for object instances and
2877 * pointers to the value type otherwise.
2879 * From unmanaged code you'll usually use the
2880 * mono_runtime_invoke() variant.
2882 * Note that this function doesn't handle virtual methods for
2883 * you, it will exec the exact method you pass: we still need to
2884 * expose a function to lookup the derived class implementation
2885 * of a virtual method (there are examples of this in the code,
2886 * though).
2888 * For this function, you must not pass NULL as the exc argument if
2889 * you don't want to catch exceptions, use
2890 * mono_runtime_invoke_checked(). If an exception is thrown, you
2891 * can't use the MonoObject* result from the function.
2893 * If this method cannot be invoked, @error will be set and @exc and
2894 * the return value must not be used.
2896 * If the method returns a value type, it is boxed in an object
2897 * reference.
2899 MonoObject*
2900 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2902 MONO_REQ_GC_UNSAFE_MODE;
2904 g_assert (exc != NULL);
2906 if (mono_runtime_get_no_exec ())
2907 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2909 return do_runtime_invoke (method, obj, params, exc, error);
2913 * mono_runtime_invoke_checked:
2914 * @method: method to invoke
2915 * @obJ: object instance
2916 * @params: arguments to the method
2917 * @error: set on error
2919 * Invokes the method represented by @method on the object @obj.
2921 * obj is the 'this' pointer, it should be NULL for static
2922 * methods, a MonoObject* for object instances and a pointer to
2923 * the value type for value types.
2925 * The params array contains the arguments to the method with the
2926 * same convention: MonoObject* pointers for object instances and
2927 * pointers to the value type otherwise.
2929 * From unmanaged code you'll usually use the
2930 * mono_runtime_invoke() variant.
2932 * Note that this function doesn't handle virtual methods for
2933 * you, it will exec the exact method you pass: we still need to
2934 * expose a function to lookup the derived class implementation
2935 * of a virtual method (there are examples of this in the code,
2936 * though).
2938 * If an exception is thrown, you can't use the MonoObject* result
2939 * from the function.
2941 * If this method cannot be invoked, @error will be set. If the
2942 * method throws an exception (and we're in coop mode) the exception
2943 * will be set in @error.
2945 * If the method returns a value type, it is boxed in an object
2946 * reference.
2948 MonoObject*
2949 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2951 MONO_REQ_GC_UNSAFE_MODE;
2953 if (mono_runtime_get_no_exec ())
2954 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2956 return do_runtime_invoke (method, obj, params, NULL, error);
2960 * mono_method_get_unmanaged_thunk:
2961 * @method: method to generate a thunk for.
2963 * Returns an unmanaged->managed thunk that can be used to call
2964 * a managed method directly from C.
2966 * The thunk's C signature closely matches the managed signature:
2968 * C#: public bool Equals (object obj);
2969 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2970 * MonoObject*, MonoException**);
2972 * The 1st ("this") parameter must not be used with static methods:
2974 * C#: public static bool ReferenceEquals (object a, object b);
2975 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2976 * MonoException**);
2978 * The last argument must be a non-null pointer of a MonoException* pointer.
2979 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2980 * exception has been thrown in managed code. Otherwise it will point
2981 * to the MonoException* caught by the thunk. In this case, the result of
2982 * the thunk is undefined:
2984 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2985 * MonoException *ex = NULL;
2986 * Equals func = mono_method_get_unmanaged_thunk (method);
2987 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2988 * if (ex) {
2989 * // handle exception
2992 * The calling convention of the thunk matches the platform's default
2993 * convention. This means that under Windows, C declarations must
2994 * contain the __stdcall attribute:
2996 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2997 * MonoObject*, MonoException**);
2999 * LIMITATIONS
3001 * Value type arguments and return values are treated as they were objects:
3003 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3004 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3006 * Arguments must be properly boxed upon trunk's invocation, while return
3007 * values must be unboxed.
3009 gpointer
3010 mono_method_get_unmanaged_thunk (MonoMethod *method)
3012 MONO_REQ_GC_NEUTRAL_MODE;
3013 MONO_REQ_API_ENTRYPOINT;
3015 MonoError error;
3016 gpointer res;
3018 g_assert (!mono_threads_is_coop_enabled ());
3020 MONO_ENTER_GC_UNSAFE;
3021 method = mono_marshal_get_thunk_invoke_wrapper (method);
3022 res = mono_compile_method_checked (method, &error);
3023 mono_error_cleanup (&error);
3024 MONO_EXIT_GC_UNSAFE;
3026 return res;
3029 void
3030 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3032 MONO_REQ_GC_UNSAFE_MODE;
3034 int t;
3035 if (type->byref) {
3036 /* object fields cannot be byref, so we don't need a
3037 wbarrier here */
3038 gpointer *p = (gpointer*)dest;
3039 *p = value;
3040 return;
3042 t = type->type;
3043 handle_enum:
3044 switch (t) {
3045 case MONO_TYPE_BOOLEAN:
3046 case MONO_TYPE_I1:
3047 case MONO_TYPE_U1: {
3048 guint8 *p = (guint8*)dest;
3049 *p = value ? *(guint8*)value : 0;
3050 return;
3052 case MONO_TYPE_I2:
3053 case MONO_TYPE_U2:
3054 case MONO_TYPE_CHAR: {
3055 guint16 *p = (guint16*)dest;
3056 *p = value ? *(guint16*)value : 0;
3057 return;
3059 #if SIZEOF_VOID_P == 4
3060 case MONO_TYPE_I:
3061 case MONO_TYPE_U:
3062 #endif
3063 case MONO_TYPE_I4:
3064 case MONO_TYPE_U4: {
3065 gint32 *p = (gint32*)dest;
3066 *p = value ? *(gint32*)value : 0;
3067 return;
3069 #if SIZEOF_VOID_P == 8
3070 case MONO_TYPE_I:
3071 case MONO_TYPE_U:
3072 #endif
3073 case MONO_TYPE_I8:
3074 case MONO_TYPE_U8: {
3075 gint64 *p = (gint64*)dest;
3076 *p = value ? *(gint64*)value : 0;
3077 return;
3079 case MONO_TYPE_R4: {
3080 float *p = (float*)dest;
3081 *p = value ? *(float*)value : 0;
3082 return;
3084 case MONO_TYPE_R8: {
3085 double *p = (double*)dest;
3086 *p = value ? *(double*)value : 0;
3087 return;
3089 case MONO_TYPE_STRING:
3090 case MONO_TYPE_SZARRAY:
3091 case MONO_TYPE_CLASS:
3092 case MONO_TYPE_OBJECT:
3093 case MONO_TYPE_ARRAY:
3094 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3095 return;
3096 case MONO_TYPE_FNPTR:
3097 case MONO_TYPE_PTR: {
3098 gpointer *p = (gpointer*)dest;
3099 *p = deref_pointer? *(gpointer*)value: value;
3100 return;
3102 case MONO_TYPE_VALUETYPE:
3103 /* note that 't' and 'type->type' can be different */
3104 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3105 t = mono_class_enum_basetype (type->data.klass)->type;
3106 goto handle_enum;
3107 } else {
3108 MonoClass *klass = mono_class_from_mono_type (type);
3109 int size = mono_class_value_size (klass, NULL);
3110 if (value == NULL)
3111 mono_gc_bzero_atomic (dest, size);
3112 else
3113 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3115 return;
3116 case MONO_TYPE_GENERICINST:
3117 t = type->data.generic_class->container_class->byval_arg.type;
3118 goto handle_enum;
3119 default:
3120 g_error ("got type %x", type->type);
3125 * mono_field_set_value:
3126 * @obj: Instance object
3127 * @field: MonoClassField describing the field to set
3128 * @value: The value to be set
3130 * Sets the value of the field described by @field in the object instance @obj
3131 * to the value passed in @value. This method should only be used for instance
3132 * fields. For static fields, use mono_field_static_set_value.
3134 * The value must be on the native format of the field type.
3136 void
3137 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3139 MONO_REQ_GC_UNSAFE_MODE;
3141 void *dest;
3143 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3145 dest = (char*)obj + field->offset;
3146 mono_copy_value (field->type, dest, value, FALSE);
3150 * mono_field_static_set_value:
3151 * @field: MonoClassField describing the field to set
3152 * @value: The value to be set
3154 * Sets the value of the static field described by @field
3155 * to the value passed in @value.
3157 * The value must be on the native format of the field type.
3159 void
3160 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3162 MONO_REQ_GC_UNSAFE_MODE;
3164 void *dest;
3166 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3167 /* you cant set a constant! */
3168 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3170 if (field->offset == -1) {
3171 /* Special static */
3172 gpointer addr;
3174 mono_domain_lock (vt->domain);
3175 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3176 mono_domain_unlock (vt->domain);
3177 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3178 } else {
3179 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3181 mono_copy_value (field->type, dest, value, FALSE);
3185 * mono_vtable_get_static_field_data:
3187 * Internal use function: return a pointer to the memory holding the static fields
3188 * for a class or NULL if there are no static fields.
3189 * This is exported only for use by the debugger.
3191 void *
3192 mono_vtable_get_static_field_data (MonoVTable *vt)
3194 MONO_REQ_GC_NEUTRAL_MODE
3196 if (!vt->has_static_fields)
3197 return NULL;
3198 return vt->vtable [vt->klass->vtable_size];
3201 static guint8*
3202 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3204 MONO_REQ_GC_UNSAFE_MODE;
3206 guint8 *src;
3208 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3209 if (field->offset == -1) {
3210 /* Special static */
3211 gpointer addr;
3213 mono_domain_lock (vt->domain);
3214 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3215 mono_domain_unlock (vt->domain);
3216 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3217 } else {
3218 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3220 } else {
3221 src = (guint8*)obj + field->offset;
3224 return src;
3228 * mono_field_get_value:
3229 * @obj: Object instance
3230 * @field: MonoClassField describing the field to fetch information from
3231 * @value: pointer to the location where the value will be stored
3233 * Use this routine to get the value of the field @field in the object
3234 * passed.
3236 * The pointer provided by value must be of the field type, for reference
3237 * types this is a MonoObject*, for value types its the actual pointer to
3238 * the value type.
3240 * For example:
3241 * int i;
3242 * mono_field_get_value (obj, int_field, &i);
3244 void
3245 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3247 MONO_REQ_GC_UNSAFE_MODE;
3249 void *src;
3251 g_assert (obj);
3253 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3255 src = (char*)obj + field->offset;
3256 mono_copy_value (field->type, value, src, TRUE);
3260 * mono_field_get_value_object:
3261 * @domain: domain where the object will be created (if boxing)
3262 * @field: MonoClassField describing the field to fetch information from
3263 * @obj: The object instance for the field.
3265 * Returns: a new MonoObject with the value from the given field. If the
3266 * field represents a value type, the value is boxed.
3269 MonoObject *
3270 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3272 MonoError error;
3273 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3274 mono_error_assert_ok (&error);
3275 return result;
3279 * mono_field_get_value_object_checked:
3280 * @domain: domain where the object will be created (if boxing)
3281 * @field: MonoClassField describing the field to fetch information from
3282 * @obj: The object instance for the field.
3283 * @error: Set on error.
3285 * Returns: a new MonoObject with the value from the given field. If the
3286 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3289 MonoObject *
3290 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3292 MONO_REQ_GC_UNSAFE_MODE;
3294 mono_error_init (error);
3296 MonoObject *o;
3297 MonoClass *klass;
3298 MonoVTable *vtable = NULL;
3299 gchar *v;
3300 gboolean is_static = FALSE;
3301 gboolean is_ref = FALSE;
3302 gboolean is_literal = FALSE;
3303 gboolean is_ptr = FALSE;
3304 MonoType *type = mono_field_get_type_checked (field, error);
3306 return_val_if_nok (error, NULL);
3308 switch (type->type) {
3309 case MONO_TYPE_STRING:
3310 case MONO_TYPE_OBJECT:
3311 case MONO_TYPE_CLASS:
3312 case MONO_TYPE_ARRAY:
3313 case MONO_TYPE_SZARRAY:
3314 is_ref = TRUE;
3315 break;
3316 case MONO_TYPE_U1:
3317 case MONO_TYPE_I1:
3318 case MONO_TYPE_BOOLEAN:
3319 case MONO_TYPE_U2:
3320 case MONO_TYPE_I2:
3321 case MONO_TYPE_CHAR:
3322 case MONO_TYPE_U:
3323 case MONO_TYPE_I:
3324 case MONO_TYPE_U4:
3325 case MONO_TYPE_I4:
3326 case MONO_TYPE_R4:
3327 case MONO_TYPE_U8:
3328 case MONO_TYPE_I8:
3329 case MONO_TYPE_R8:
3330 case MONO_TYPE_VALUETYPE:
3331 is_ref = type->byref;
3332 break;
3333 case MONO_TYPE_GENERICINST:
3334 is_ref = !mono_type_generic_inst_is_valuetype (type);
3335 break;
3336 case MONO_TYPE_PTR:
3337 is_ptr = TRUE;
3338 break;
3339 default:
3340 g_error ("type 0x%x not handled in "
3341 "mono_field_get_value_object", type->type);
3342 return NULL;
3345 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3346 is_literal = TRUE;
3348 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3349 is_static = TRUE;
3351 if (!is_literal) {
3352 vtable = mono_class_vtable_full (domain, field->parent, error);
3353 return_val_if_nok (error, NULL);
3355 if (!vtable->initialized) {
3356 mono_runtime_class_init_full (vtable, error);
3357 return_val_if_nok (error, NULL);
3360 } else {
3361 g_assert (obj);
3364 if (is_ref) {
3365 if (is_literal) {
3366 get_default_field_value (domain, field, &o, error);
3367 return_val_if_nok (error, NULL);
3368 } else if (is_static) {
3369 mono_field_static_get_value_checked (vtable, field, &o, error);
3370 return_val_if_nok (error, NULL);
3371 } else {
3372 mono_field_get_value (obj, field, &o);
3374 return o;
3377 if (is_ptr) {
3378 static MonoMethod *m;
3379 gpointer args [2];
3380 gpointer *ptr;
3381 gpointer v;
3383 if (!m) {
3384 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3385 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3386 g_assert (m);
3389 v = &ptr;
3390 if (is_literal) {
3391 get_default_field_value (domain, field, v, error);
3392 return_val_if_nok (error, NULL);
3393 } else if (is_static) {
3394 mono_field_static_get_value_checked (vtable, field, v, error);
3395 return_val_if_nok (error, NULL);
3396 } else {
3397 mono_field_get_value (obj, field, v);
3400 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3401 args [0] = ptr ? *ptr : NULL;
3402 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3403 return_val_if_nok (error, NULL);
3405 o = mono_runtime_invoke_checked (m, NULL, args, error);
3406 return_val_if_nok (error, NULL);
3408 return o;
3411 /* boxed value type */
3412 klass = mono_class_from_mono_type (type);
3414 if (mono_class_is_nullable (klass))
3415 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3417 o = mono_object_new_checked (domain, klass, error);
3418 return_val_if_nok (error, NULL);
3419 v = ((gchar *) o) + sizeof (MonoObject);
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 return o;
3435 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3437 MONO_REQ_GC_UNSAFE_MODE;
3439 mono_error_init (error);
3440 int retval = 0;
3441 const char *p = blob;
3442 mono_metadata_decode_blob_size (p, &p);
3444 switch (type) {
3445 case MONO_TYPE_BOOLEAN:
3446 case MONO_TYPE_U1:
3447 case MONO_TYPE_I1:
3448 *(guint8 *) value = *p;
3449 break;
3450 case MONO_TYPE_CHAR:
3451 case MONO_TYPE_U2:
3452 case MONO_TYPE_I2:
3453 *(guint16*) value = read16 (p);
3454 break;
3455 case MONO_TYPE_U4:
3456 case MONO_TYPE_I4:
3457 *(guint32*) value = read32 (p);
3458 break;
3459 case MONO_TYPE_U8:
3460 case MONO_TYPE_I8:
3461 *(guint64*) value = read64 (p);
3462 break;
3463 case MONO_TYPE_R4:
3464 readr4 (p, (float*) value);
3465 break;
3466 case MONO_TYPE_R8:
3467 readr8 (p, (double*) value);
3468 break;
3469 case MONO_TYPE_STRING:
3470 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3471 break;
3472 case MONO_TYPE_CLASS:
3473 *(gpointer*) value = NULL;
3474 break;
3475 default:
3476 retval = -1;
3477 g_warning ("type 0x%02x should not be in constant table", type);
3479 return retval;
3482 static void
3483 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3485 MONO_REQ_GC_NEUTRAL_MODE;
3487 MonoTypeEnum def_type;
3488 const char* data;
3490 mono_error_init (error);
3492 data = mono_class_get_field_default_value (field, &def_type);
3493 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3496 void
3497 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3499 MONO_REQ_GC_UNSAFE_MODE;
3501 void *src;
3503 mono_error_init (error);
3505 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3507 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3508 get_default_field_value (vt->domain, field, value, error);
3509 return;
3512 if (field->offset == -1) {
3513 /* Special static */
3514 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3515 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3516 } else {
3517 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3519 mono_copy_value (field->type, value, src, TRUE);
3523 * mono_field_static_get_value:
3524 * @vt: vtable to the object
3525 * @field: MonoClassField describing the field to fetch information from
3526 * @value: where the value is returned
3528 * Use this routine to get the value of the static field @field value.
3530 * The pointer provided by value must be of the field type, for reference
3531 * types this is a MonoObject*, for value types its the actual pointer to
3532 * the value type.
3534 * For example:
3535 * int i;
3536 * mono_field_static_get_value (vt, int_field, &i);
3538 void
3539 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3541 MONO_REQ_GC_NEUTRAL_MODE;
3543 MonoError error;
3544 mono_field_static_get_value_checked (vt, field, value, &error);
3545 mono_error_cleanup (&error);
3549 * mono_field_static_get_value_checked:
3550 * @vt: vtable to the object
3551 * @field: MonoClassField describing the field to fetch information from
3552 * @value: where the value is returned
3553 * @error: set on error
3555 * Use this routine to get the value of the static field @field value.
3557 * The pointer provided by value must be of the field type, for reference
3558 * types this is a MonoObject*, for value types its the actual pointer to
3559 * the value type.
3561 * For example:
3562 * int i;
3563 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3564 * if (!is_ok (error)) { ... }
3566 * On failure sets @error.
3568 void
3569 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3571 MONO_REQ_GC_NEUTRAL_MODE;
3573 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3577 * mono_property_set_value:
3578 * @prop: MonoProperty to set
3579 * @obj: instance object on which to act
3580 * @params: parameters to pass to the propery
3581 * @exc: optional exception
3583 * Invokes the property's set method with the given arguments on the
3584 * object instance obj (or NULL for static properties).
3586 * You can pass NULL as the exc argument if you don't want to
3587 * catch exceptions, otherwise, *exc will be set to the exception
3588 * thrown, if any. if an exception is thrown, you can't use the
3589 * MonoObject* result from the function.
3591 void
3592 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3594 MONO_REQ_GC_UNSAFE_MODE;
3596 MonoError error;
3597 do_runtime_invoke (prop->set, obj, params, exc, &error);
3598 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3599 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3600 } else {
3601 mono_error_cleanup (&error);
3606 * mono_property_set_value_checked:
3607 * @prop: MonoProperty to set
3608 * @obj: instance object on which to act
3609 * @params: parameters to pass to the propery
3610 * @error: set on error
3612 * Invokes the property's set method with the given arguments on the
3613 * object instance obj (or NULL for static properties).
3615 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3616 * If an exception is thrown, it will be caught and returned via @error.
3618 gboolean
3619 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3621 MONO_REQ_GC_UNSAFE_MODE;
3623 MonoObject *exc;
3625 mono_error_init (error);
3626 do_runtime_invoke (prop->set, obj, params, &exc, error);
3627 if (exc != NULL && is_ok (error))
3628 mono_error_set_exception_instance (error, (MonoException*)exc);
3629 return is_ok (error);
3633 * mono_property_get_value:
3634 * @prop: MonoProperty to fetch
3635 * @obj: instance object on which to act
3636 * @params: parameters to pass to the propery
3637 * @exc: optional exception
3639 * Invokes the property's get method with the given arguments on the
3640 * object instance obj (or NULL for static properties).
3642 * You can pass NULL as the exc argument if you don't want to
3643 * catch exceptions, otherwise, *exc will be set to the exception
3644 * thrown, if any. if an exception is thrown, you can't use the
3645 * MonoObject* result from the function.
3647 * Returns: the value from invoking the get method on the property.
3649 MonoObject*
3650 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3652 MONO_REQ_GC_UNSAFE_MODE;
3654 MonoError error;
3655 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3656 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3657 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3658 } else {
3659 mono_error_cleanup (&error); /* FIXME don't raise here */
3662 return val;
3666 * mono_property_get_value_checked:
3667 * @prop: MonoProperty to fetch
3668 * @obj: instance object on which to act
3669 * @params: parameters to pass to the propery
3670 * @error: set on error
3672 * Invokes the property's get method with the given arguments on the
3673 * object instance obj (or NULL for static properties).
3675 * If an exception is thrown, you can't use the
3676 * MonoObject* result from the function. The exception will be propagated via @error.
3678 * Returns: the value from invoking the get method on the property. On
3679 * failure returns NULL and sets @error.
3681 MonoObject*
3682 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3684 MONO_REQ_GC_UNSAFE_MODE;
3686 MonoObject *exc;
3687 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3688 if (exc != NULL && !is_ok (error))
3689 mono_error_set_exception_instance (error, (MonoException*) exc);
3690 if (!is_ok (error))
3691 val = NULL;
3692 return val;
3697 * mono_nullable_init:
3698 * @buf: The nullable structure to initialize.
3699 * @value: the value to initialize from
3700 * @klass: the type for the object
3702 * Initialize the nullable structure pointed to by @buf from @value which
3703 * should be a boxed value type. The size of @buf should be able to hold
3704 * as much data as the @klass->instance_size (which is the number of bytes
3705 * that will be copies).
3707 * Since Nullables have variable structure, we can not define a C
3708 * structure for them.
3710 void
3711 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3713 MONO_REQ_GC_UNSAFE_MODE;
3715 MonoClass *param_class = klass->cast_class;
3717 mono_class_setup_fields (klass);
3718 g_assert (klass->fields_inited);
3720 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3721 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3723 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3724 if (value) {
3725 if (param_class->has_references)
3726 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3727 else
3728 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3729 } else {
3730 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3735 * mono_nullable_box:
3736 * @buf: The buffer representing the data to be boxed
3737 * @klass: the type to box it as.
3738 * @error: set on oerr
3740 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3741 * @buf. On failure returns NULL and sets @error
3743 MonoObject*
3744 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3746 MONO_REQ_GC_UNSAFE_MODE;
3748 mono_error_init (error);
3749 MonoClass *param_class = klass->cast_class;
3751 mono_class_setup_fields (klass);
3752 g_assert (klass->fields_inited);
3754 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3755 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3757 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3758 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3759 return_val_if_nok (error, NULL);
3760 if (param_class->has_references)
3761 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3762 else
3763 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3764 return o;
3766 else
3767 return NULL;
3771 * mono_get_delegate_invoke:
3772 * @klass: The delegate class
3774 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3776 MonoMethod *
3777 mono_get_delegate_invoke (MonoClass *klass)
3779 MONO_REQ_GC_NEUTRAL_MODE;
3781 MonoMethod *im;
3783 /* This is called at runtime, so avoid the slower search in metadata */
3784 mono_class_setup_methods (klass);
3785 if (mono_class_has_failure (klass))
3786 return NULL;
3787 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3788 return im;
3792 * mono_get_delegate_begin_invoke:
3793 * @klass: The delegate class
3795 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3797 MonoMethod *
3798 mono_get_delegate_begin_invoke (MonoClass *klass)
3800 MONO_REQ_GC_NEUTRAL_MODE;
3802 MonoMethod *im;
3804 /* This is called at runtime, so avoid the slower search in metadata */
3805 mono_class_setup_methods (klass);
3806 if (mono_class_has_failure (klass))
3807 return NULL;
3808 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3809 return im;
3813 * mono_get_delegate_end_invoke:
3814 * @klass: The delegate class
3816 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3818 MonoMethod *
3819 mono_get_delegate_end_invoke (MonoClass *klass)
3821 MONO_REQ_GC_NEUTRAL_MODE;
3823 MonoMethod *im;
3825 /* This is called at runtime, so avoid the slower search in metadata */
3826 mono_class_setup_methods (klass);
3827 if (mono_class_has_failure (klass))
3828 return NULL;
3829 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3830 return im;
3834 * mono_runtime_delegate_invoke:
3835 * @delegate: pointer to a delegate object.
3836 * @params: parameters for the delegate.
3837 * @exc: Pointer to the exception result.
3839 * Invokes the delegate method @delegate with the parameters provided.
3841 * You can pass NULL as the exc argument if you don't want to
3842 * catch exceptions, otherwise, *exc will be set to the exception
3843 * thrown, if any. if an exception is thrown, you can't use the
3844 * MonoObject* result from the function.
3846 MonoObject*
3847 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3849 MONO_REQ_GC_UNSAFE_MODE;
3851 MonoError error;
3852 if (exc) {
3853 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3854 if (*exc) {
3855 mono_error_cleanup (&error);
3856 return NULL;
3857 } else {
3858 if (!is_ok (&error))
3859 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3860 return result;
3862 } else {
3863 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3864 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3865 return result;
3870 * mono_runtime_delegate_try_invoke:
3871 * @delegate: pointer to a delegate object.
3872 * @params: parameters for the delegate.
3873 * @exc: Pointer to the exception result.
3874 * @error: set on error
3876 * Invokes the delegate method @delegate with the parameters provided.
3878 * You can pass NULL as the exc argument if you don't want to
3879 * catch exceptions, otherwise, *exc will be set to the exception
3880 * thrown, if any. On failure to execute, @error will be set.
3881 * if an exception is thrown, you can't use the
3882 * MonoObject* result from the function.
3884 MonoObject*
3885 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3887 MONO_REQ_GC_UNSAFE_MODE;
3889 mono_error_init (error);
3890 MonoMethod *im;
3891 MonoClass *klass = delegate->vtable->klass;
3892 MonoObject *o;
3894 im = mono_get_delegate_invoke (klass);
3895 if (!im)
3896 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3898 if (exc) {
3899 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3900 } else {
3901 o = mono_runtime_invoke_checked (im, delegate, params, error);
3904 return o;
3908 * mono_runtime_delegate_invoke_checked:
3909 * @delegate: pointer to a delegate object.
3910 * @params: parameters for the delegate.
3911 * @error: set on error
3913 * Invokes the delegate method @delegate with the parameters provided.
3915 * On failure @error will be set and you can't use the MonoObject*
3916 * result from the function.
3918 MonoObject*
3919 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3921 mono_error_init (error);
3922 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3925 static char **main_args = NULL;
3926 static int num_main_args = 0;
3929 * mono_runtime_get_main_args:
3931 * Returns: a MonoArray with the arguments passed to the main program
3933 MonoArray*
3934 mono_runtime_get_main_args (void)
3936 MONO_REQ_GC_UNSAFE_MODE;
3937 MonoError error;
3938 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3939 mono_error_assert_ok (&error);
3940 return result;
3944 * mono_runtime_get_main_args:
3945 * @error: set on error
3947 * Returns: a MonoArray with the arguments passed to the main
3948 * program. On failure returns NULL and sets @error.
3950 MonoArray*
3951 mono_runtime_get_main_args_checked (MonoError *error)
3953 MonoArray *res;
3954 int i;
3955 MonoDomain *domain = mono_domain_get ();
3957 mono_error_init (error);
3959 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3960 return_val_if_nok (error, NULL);
3962 for (i = 0; i < num_main_args; ++i)
3963 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3965 return res;
3968 static void
3969 free_main_args (void)
3971 MONO_REQ_GC_NEUTRAL_MODE;
3973 int i;
3975 for (i = 0; i < num_main_args; ++i)
3976 g_free (main_args [i]);
3977 g_free (main_args);
3978 num_main_args = 0;
3979 main_args = NULL;
3983 * mono_runtime_set_main_args:
3984 * @argc: number of arguments from the command line
3985 * @argv: array of strings from the command line
3987 * Set the command line arguments from an embedding application that doesn't otherwise call
3988 * mono_runtime_run_main ().
3991 mono_runtime_set_main_args (int argc, char* argv[])
3993 MONO_REQ_GC_NEUTRAL_MODE;
3995 int i;
3997 free_main_args ();
3998 main_args = g_new0 (char*, argc);
3999 num_main_args = argc;
4001 for (i = 0; i < argc; ++i) {
4002 gchar *utf8_arg;
4004 utf8_arg = mono_utf8_from_external (argv[i]);
4005 if (utf8_arg == NULL) {
4006 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4007 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4008 exit (-1);
4011 main_args [i] = utf8_arg;
4014 return 0;
4018 * Prepare an array of arguments in order to execute a standard Main()
4019 * method (argc/argv contains the executable name). This method also
4020 * sets the command line argument value needed by System.Environment.
4023 static MonoArray*
4024 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4026 MONO_REQ_GC_UNSAFE_MODE;
4028 MonoError error;
4029 int i;
4030 MonoArray *args = NULL;
4031 MonoDomain *domain = mono_domain_get ();
4032 gchar *utf8_fullpath;
4033 MonoMethodSignature *sig;
4035 g_assert (method != NULL);
4037 mono_thread_set_main (mono_thread_current ());
4039 main_args = g_new0 (char*, argc);
4040 num_main_args = argc;
4042 if (!g_path_is_absolute (argv [0])) {
4043 gchar *basename = g_path_get_basename (argv [0]);
4044 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4045 basename,
4046 NULL);
4048 utf8_fullpath = mono_utf8_from_external (fullpath);
4049 if(utf8_fullpath == NULL) {
4050 /* Printing the arg text will cause glib to
4051 * whinge about "Invalid UTF-8", but at least
4052 * its relevant, and shows the problem text
4053 * string.
4055 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4056 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4057 exit (-1);
4060 g_free (fullpath);
4061 g_free (basename);
4062 } else {
4063 utf8_fullpath = mono_utf8_from_external (argv[0]);
4064 if(utf8_fullpath == NULL) {
4065 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4066 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4067 exit (-1);
4071 main_args [0] = utf8_fullpath;
4073 for (i = 1; i < argc; ++i) {
4074 gchar *utf8_arg;
4076 utf8_arg=mono_utf8_from_external (argv[i]);
4077 if(utf8_arg==NULL) {
4078 /* Ditto the comment about Invalid UTF-8 here */
4079 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4080 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4081 exit (-1);
4084 main_args [i] = utf8_arg;
4086 argc--;
4087 argv++;
4089 sig = mono_method_signature (method);
4090 if (!sig) {
4091 g_print ("Unable to load Main method.\n");
4092 exit (-1);
4095 if (sig->param_count) {
4096 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4097 mono_error_assert_ok (&error);
4098 for (i = 0; i < argc; ++i) {
4099 /* The encodings should all work, given that
4100 * we've checked all these args for the
4101 * main_args array.
4103 gchar *str = mono_utf8_from_external (argv [i]);
4104 MonoString *arg = mono_string_new (domain, str);
4105 mono_array_setref (args, i, arg);
4106 g_free (str);
4108 } else {
4109 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4110 mono_error_assert_ok (&error);
4113 mono_assembly_set_main (method->klass->image->assembly);
4115 return args;
4119 * mono_runtime_run_main:
4120 * @method: the method to start the application with (usually Main)
4121 * @argc: number of arguments from the command line
4122 * @argv: array of strings from the command line
4123 * @exc: excetption results
4125 * Execute a standard Main() method (argc/argv contains the
4126 * executable name). This method also sets the command line argument value
4127 * needed by System.Environment.
4132 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4133 MonoObject **exc)
4135 MONO_REQ_GC_UNSAFE_MODE;
4137 MonoError error;
4138 MonoArray *args = prepare_run_main (method, argc, argv);
4139 int res;
4140 if (exc) {
4141 res = mono_runtime_try_exec_main (method, args, exc);
4142 } else {
4143 res = mono_runtime_exec_main_checked (method, args, &error);
4144 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4146 return res;
4150 * mono_runtime_run_main_checked:
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 * @error: set on error
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. On failure sets @error.
4163 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4164 MonoError *error)
4166 mono_error_init (error);
4167 MonoArray *args = prepare_run_main (method, argc, argv);
4168 return mono_runtime_exec_main_checked (method, args, error);
4172 * mono_runtime_try_run_main:
4173 * @method: the method to start the application with (usually Main)
4174 * @argc: number of arguments from the command line
4175 * @argv: array of strings from the command line
4176 * @exc: set if Main throws an exception
4177 * @error: set if Main can't be executed
4179 * Execute a standard Main() method (argc/argv contains the executable
4180 * name). This method also sets the command line argument value needed
4181 * by System.Environment. On failure sets @error if Main can't be
4182 * executed or @exc if it threw and exception.
4187 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4188 MonoObject **exc)
4190 g_assert (exc);
4191 MonoArray *args = prepare_run_main (method, argc, argv);
4192 return mono_runtime_try_exec_main (method, args, exc);
4196 static MonoObject*
4197 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4199 static MonoMethod *serialize_method;
4201 MonoError error;
4202 void *params [1];
4203 MonoObject *array;
4205 if (!serialize_method) {
4206 MonoClass *klass = mono_class_get_remoting_services_class ();
4207 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4210 if (!serialize_method) {
4211 *failure = TRUE;
4212 return NULL;
4215 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4217 params [0] = obj;
4218 *exc = NULL;
4220 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4221 if (*exc == NULL && !mono_error_ok (&error))
4222 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4223 else
4224 mono_error_cleanup (&error);
4226 if (*exc)
4227 *failure = TRUE;
4229 return array;
4232 static MonoObject*
4233 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4235 MONO_REQ_GC_UNSAFE_MODE;
4237 static MonoMethod *deserialize_method;
4239 MonoError error;
4240 void *params [1];
4241 MonoObject *result;
4243 if (!deserialize_method) {
4244 MonoClass *klass = mono_class_get_remoting_services_class ();
4245 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4247 if (!deserialize_method) {
4248 *failure = TRUE;
4249 return NULL;
4252 params [0] = obj;
4253 *exc = NULL;
4255 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4256 if (*exc == NULL && !mono_error_ok (&error))
4257 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4258 else
4259 mono_error_cleanup (&error);
4261 if (*exc)
4262 *failure = TRUE;
4264 return result;
4267 #ifndef DISABLE_REMOTING
4268 static MonoObject*
4269 make_transparent_proxy (MonoObject *obj, MonoError *error)
4271 MONO_REQ_GC_UNSAFE_MODE;
4273 static MonoMethod *get_proxy_method;
4275 MonoDomain *domain = mono_domain_get ();
4276 MonoRealProxy *real_proxy;
4277 MonoReflectionType *reflection_type;
4278 MonoTransparentProxy *transparent_proxy;
4280 mono_error_init (error);
4282 if (!get_proxy_method)
4283 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4285 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4287 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4288 return_val_if_nok (error, NULL);
4289 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4290 return_val_if_nok (error, NULL);
4292 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4293 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4295 MonoObject *exc = NULL;
4297 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4298 if (exc != NULL && is_ok (error))
4299 mono_error_set_exception_instance (error, (MonoException*)exc);
4301 return (MonoObject*) transparent_proxy;
4303 #endif /* DISABLE_REMOTING */
4306 * mono_object_xdomain_representation
4307 * @obj: an object
4308 * @target_domain: a domain
4309 * @error: set on error.
4311 * Creates a representation of obj in the domain target_domain. This
4312 * is either a copy of obj arrived through via serialization and
4313 * deserialization or a proxy, depending on whether the object is
4314 * serializable or marshal by ref. obj must not be in target_domain.
4316 * If the object cannot be represented in target_domain, NULL is
4317 * returned and @error is set appropriately.
4319 MonoObject*
4320 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4322 MONO_REQ_GC_UNSAFE_MODE;
4324 mono_error_init (error);
4325 MonoObject *deserialized = NULL;
4327 #ifndef DISABLE_REMOTING
4328 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4329 deserialized = make_transparent_proxy (obj, error);
4331 else
4332 #endif
4334 gboolean failure = FALSE;
4335 MonoDomain *domain = mono_domain_get ();
4336 MonoObject *serialized;
4337 MonoObject *exc = NULL;
4339 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4340 serialized = serialize_object (obj, &failure, &exc);
4341 mono_domain_set_internal_with_options (target_domain, FALSE);
4342 if (!failure)
4343 deserialized = deserialize_object (serialized, &failure, &exc);
4344 if (domain != target_domain)
4345 mono_domain_set_internal_with_options (domain, FALSE);
4346 if (failure)
4347 mono_error_set_exception_instance (error, (MonoException*)exc);
4350 return deserialized;
4353 /* Used in call_unhandled_exception_delegate */
4354 static MonoObject *
4355 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4357 MONO_REQ_GC_UNSAFE_MODE;
4359 mono_error_init (error);
4360 MonoClass *klass;
4361 gpointer args [2];
4362 MonoMethod *method = NULL;
4363 MonoBoolean is_terminating = TRUE;
4364 MonoObject *obj;
4366 klass = mono_class_get_unhandled_exception_event_args_class ();
4367 mono_class_init (klass);
4369 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4370 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4371 g_assert (method);
4373 args [0] = exc;
4374 args [1] = &is_terminating;
4376 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4377 return_val_if_nok (error, NULL);
4379 mono_runtime_invoke_checked (method, obj, args, error);
4380 return_val_if_nok (error, NULL);
4382 return obj;
4385 /* Used in mono_unhandled_exception */
4386 static void
4387 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4388 MONO_REQ_GC_UNSAFE_MODE;
4390 MonoError error;
4391 MonoObject *e = NULL;
4392 gpointer pa [2];
4393 MonoDomain *current_domain = mono_domain_get ();
4395 if (domain != current_domain)
4396 mono_domain_set_internal_with_options (domain, FALSE);
4398 g_assert (domain == mono_object_domain (domain->domain));
4400 if (mono_object_domain (exc) != domain) {
4402 exc = mono_object_xdomain_representation (exc, domain, &error);
4403 if (!exc) {
4404 if (!is_ok (&error)) {
4405 MonoError inner_error;
4406 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4407 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4408 mono_error_assert_ok (&inner_error);
4409 } else {
4410 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4411 "System.Runtime.Serialization", "SerializationException",
4412 "Could not serialize unhandled exception.");
4416 g_assert (mono_object_domain (exc) == domain);
4418 pa [0] = domain->domain;
4419 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4420 mono_error_assert_ok (&error);
4421 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4422 if (!is_ok (&error)) {
4423 if (e == NULL)
4424 e = (MonoObject*)mono_error_convert_to_exception (&error);
4425 else
4426 mono_error_cleanup (&error);
4429 if (domain != current_domain)
4430 mono_domain_set_internal_with_options (current_domain, FALSE);
4432 if (e) {
4433 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4434 if (!mono_error_ok (&error)) {
4435 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4436 mono_error_cleanup (&error);
4437 } else {
4438 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4439 g_free (msg);
4444 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4447 * mono_runtime_unhandled_exception_policy_set:
4448 * @policy: the new policy
4450 * This is a VM internal routine.
4452 * Sets the runtime policy for handling unhandled exceptions.
4454 void
4455 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4456 runtime_unhandled_exception_policy = policy;
4460 * mono_runtime_unhandled_exception_policy_get:
4462 * This is a VM internal routine.
4464 * Gets the runtime policy for handling unhandled exceptions.
4466 MonoRuntimeUnhandledExceptionPolicy
4467 mono_runtime_unhandled_exception_policy_get (void) {
4468 return runtime_unhandled_exception_policy;
4472 * mono_unhandled_exception:
4473 * @exc: exception thrown
4475 * This is a VM internal routine.
4477 * We call this function when we detect an unhandled exception
4478 * in the default domain.
4480 * It invokes the * UnhandledException event in AppDomain or prints
4481 * a warning to the console
4483 void
4484 mono_unhandled_exception (MonoObject *exc)
4486 MONO_REQ_GC_UNSAFE_MODE;
4488 MonoError error;
4489 MonoClassField *field;
4490 MonoDomain *current_domain, *root_domain;
4491 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4493 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4494 return;
4496 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4497 g_assert (field);
4499 current_domain = mono_domain_get ();
4500 root_domain = mono_get_root_domain ();
4502 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4503 mono_error_assert_ok (&error);
4504 if (current_domain != root_domain) {
4505 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4506 mono_error_assert_ok (&error);
4509 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4510 mono_print_unhandled_exception (exc);
4511 } else {
4512 /* unhandled exception callbacks must not be aborted */
4513 mono_threads_begin_abort_protected_block ();
4514 if (root_appdomain_delegate)
4515 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4516 if (current_appdomain_delegate)
4517 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4518 mono_threads_end_abort_protected_block ();
4521 /* set exitcode only if we will abort the process */
4522 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4523 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4525 mono_environment_exitcode_set (1);
4530 * mono_runtime_exec_managed_code:
4531 * @domain: Application domain
4532 * @main_func: function to invoke from the execution thread
4533 * @main_args: parameter to the main_func
4535 * Launch a new thread to execute a function
4537 * main_func is called back from the thread with main_args as the
4538 * parameter. The callback function is expected to start Main()
4539 * eventually. This function then waits for all managed threads to
4540 * finish.
4541 * It is not necesseray anymore to execute managed code in a subthread,
4542 * so this function should not be used anymore by default: just
4543 * execute the code and then call mono_thread_manage ().
4545 void
4546 mono_runtime_exec_managed_code (MonoDomain *domain,
4547 MonoMainThreadFunc main_func,
4548 gpointer main_args)
4550 MonoError error;
4551 mono_thread_create_checked (domain, main_func, main_args, &error);
4552 mono_error_assert_ok (&error);
4554 mono_thread_manage ();
4557 static void
4558 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4560 MonoInternalThread* thread = mono_thread_internal_current ();
4561 MonoCustomAttrInfo* cinfo;
4562 gboolean has_stathread_attribute;
4564 if (!domain->entry_assembly) {
4565 gchar *str;
4566 MonoAssembly *assembly;
4568 assembly = method->klass->image->assembly;
4569 domain->entry_assembly = assembly;
4570 /* Domains created from another domain already have application_base and configuration_file set */
4571 if (domain->setup->application_base == NULL) {
4572 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4575 if (domain->setup->configuration_file == NULL) {
4576 str = g_strconcat (assembly->image->name, ".config", NULL);
4577 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4578 g_free (str);
4579 mono_domain_set_options_from_config (domain);
4583 MonoError cattr_error;
4584 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4585 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4586 if (cinfo) {
4587 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4588 if (!cinfo->cached)
4589 mono_custom_attrs_free (cinfo);
4590 } else {
4591 has_stathread_attribute = FALSE;
4593 if (has_stathread_attribute) {
4594 thread->apartment_state = ThreadApartmentState_STA;
4595 } else {
4596 thread->apartment_state = ThreadApartmentState_MTA;
4598 mono_thread_init_apartment_state ();
4602 static int
4603 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4605 MONO_REQ_GC_UNSAFE_MODE;
4607 gpointer pa [1];
4608 int rval;
4610 mono_error_init (error);
4611 g_assert (args);
4613 pa [0] = args;
4615 /* FIXME: check signature of method */
4616 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4617 MonoObject *res;
4618 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4619 if (is_ok (error))
4620 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4621 else
4622 rval = -1;
4623 mono_environment_exitcode_set (rval);
4624 } else {
4625 mono_runtime_invoke_checked (method, NULL, pa, error);
4627 if (is_ok (error))
4628 rval = 0;
4629 else {
4630 rval = -1;
4633 return rval;
4636 static int
4637 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4639 MONO_REQ_GC_UNSAFE_MODE;
4641 gpointer pa [1];
4642 int rval;
4644 g_assert (args);
4645 g_assert (exc);
4647 pa [0] = args;
4649 /* FIXME: check signature of method */
4650 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4651 MonoError inner_error;
4652 MonoObject *res;
4653 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4654 if (*exc == NULL && !mono_error_ok (&inner_error))
4655 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4656 else
4657 mono_error_cleanup (&inner_error);
4659 if (*exc == NULL)
4660 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4661 else
4662 rval = -1;
4664 mono_environment_exitcode_set (rval);
4665 } else {
4666 MonoError inner_error;
4667 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4668 if (*exc == NULL && !mono_error_ok (&inner_error))
4669 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4670 else
4671 mono_error_cleanup (&inner_error);
4673 if (*exc == NULL)
4674 rval = 0;
4675 else {
4676 /* If the return type of Main is void, only
4677 * set the exitcode if an exception was thrown
4678 * (we don't want to blow away an
4679 * explicitly-set exit code)
4681 rval = -1;
4682 mono_environment_exitcode_set (rval);
4686 return rval;
4690 * Execute a standard Main() method (args doesn't contain the
4691 * executable name).
4694 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4696 MonoError error;
4697 prepare_thread_to_exec_main (mono_object_domain (args), method);
4698 if (exc) {
4699 int rval = do_try_exec_main (method, args, exc);
4700 return rval;
4701 } else {
4702 int rval = do_exec_main_checked (method, args, &error);
4703 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4704 return rval;
4709 * Execute a standard Main() method (args doesn't contain the
4710 * executable name).
4712 * On failure sets @error
4715 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4717 mono_error_init (error);
4718 prepare_thread_to_exec_main (mono_object_domain (args), method);
4719 return do_exec_main_checked (method, args, error);
4723 * Execute a standard Main() method (args doesn't contain the
4724 * executable name).
4726 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4729 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4731 prepare_thread_to_exec_main (mono_object_domain (args), method);
4732 return do_try_exec_main (method, args, exc);
4737 /** invoke_array_extract_argument:
4738 * @params: array of arguments to the method.
4739 * @i: the index of the argument to extract.
4740 * @t: ith type from the method signature.
4741 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4742 * @error: set on error.
4744 * Given an array of method arguments, return the ith one using the corresponding type
4745 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4747 * On failure sets @error and returns NULL.
4749 static gpointer
4750 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4752 MonoType *t_orig = t;
4753 gpointer result = NULL;
4754 mono_error_init (error);
4755 again:
4756 switch (t->type) {
4757 case MONO_TYPE_U1:
4758 case MONO_TYPE_I1:
4759 case MONO_TYPE_BOOLEAN:
4760 case MONO_TYPE_U2:
4761 case MONO_TYPE_I2:
4762 case MONO_TYPE_CHAR:
4763 case MONO_TYPE_U:
4764 case MONO_TYPE_I:
4765 case MONO_TYPE_U4:
4766 case MONO_TYPE_I4:
4767 case MONO_TYPE_U8:
4768 case MONO_TYPE_I8:
4769 case MONO_TYPE_R4:
4770 case MONO_TYPE_R8:
4771 case MONO_TYPE_VALUETYPE:
4772 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4773 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4774 result = mono_array_get (params, MonoObject*, i);
4775 if (t->byref)
4776 *has_byref_nullables = TRUE;
4777 } else {
4778 /* MS seems to create the objects if a null is passed in */
4779 if (!mono_array_get (params, MonoObject*, i)) {
4780 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4781 return_val_if_nok (error, NULL);
4782 mono_array_setref (params, i, o);
4785 if (t->byref) {
4787 * We can't pass the unboxed vtype byref to the callee, since
4788 * that would mean the callee would be able to modify boxed
4789 * primitive types. So we (and MS) make a copy of the boxed
4790 * object, pass that to the callee, and replace the original
4791 * boxed object in the arg array with the copy.
4793 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4794 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4795 return_val_if_nok (error, NULL);
4796 mono_array_setref (params, i, copy);
4799 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4801 break;
4802 case MONO_TYPE_STRING:
4803 case MONO_TYPE_OBJECT:
4804 case MONO_TYPE_CLASS:
4805 case MONO_TYPE_ARRAY:
4806 case MONO_TYPE_SZARRAY:
4807 if (t->byref)
4808 result = mono_array_addr (params, MonoObject*, i);
4809 // FIXME: I need to check this code path
4810 else
4811 result = mono_array_get (params, MonoObject*, i);
4812 break;
4813 case MONO_TYPE_GENERICINST:
4814 if (t->byref)
4815 t = &t->data.generic_class->container_class->this_arg;
4816 else
4817 t = &t->data.generic_class->container_class->byval_arg;
4818 goto again;
4819 case MONO_TYPE_PTR: {
4820 MonoObject *arg;
4822 /* The argument should be an IntPtr */
4823 arg = mono_array_get (params, MonoObject*, i);
4824 if (arg == NULL) {
4825 result = NULL;
4826 } else {
4827 g_assert (arg->vtable->klass == mono_defaults.int_class);
4828 result = ((MonoIntPtr*)arg)->m_value;
4830 break;
4832 default:
4833 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4835 return result;
4838 * mono_runtime_invoke_array:
4839 * @method: method to invoke
4840 * @obJ: object instance
4841 * @params: arguments to the method
4842 * @exc: exception information.
4844 * Invokes the method represented by @method on the object @obj.
4846 * obj is the 'this' pointer, it should be NULL for static
4847 * methods, a MonoObject* for object instances and a pointer to
4848 * the value type for value types.
4850 * The params array contains the arguments to the method with the
4851 * same convention: MonoObject* pointers for object instances and
4852 * pointers to the value type otherwise. The _invoke_array
4853 * variant takes a C# object[] as the params argument (MonoArray
4854 * *params): in this case the value types are boxed inside the
4855 * respective reference representation.
4857 * From unmanaged code you'll usually use the
4858 * mono_runtime_invoke_checked() variant.
4860 * Note that this function doesn't handle virtual methods for
4861 * you, it will exec the exact method you pass: we still need to
4862 * expose a function to lookup the derived class implementation
4863 * of a virtual method (there are examples of this in the code,
4864 * though).
4866 * You can pass NULL as the exc argument if you don't want to
4867 * catch exceptions, otherwise, *exc will be set to the exception
4868 * thrown, if any. if an exception is thrown, you can't use the
4869 * MonoObject* result from the function.
4871 * If the method returns a value type, it is boxed in an object
4872 * reference.
4874 MonoObject*
4875 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4876 MonoObject **exc)
4878 MonoError error;
4879 if (exc) {
4880 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4881 if (*exc) {
4882 mono_error_cleanup (&error);
4883 return NULL;
4884 } else {
4885 if (!is_ok (&error))
4886 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4887 return result;
4889 } else {
4890 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4891 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4892 return result;
4897 * mono_runtime_invoke_array_checked:
4898 * @method: method to invoke
4899 * @obJ: object instance
4900 * @params: arguments to the method
4901 * @error: set on failure.
4903 * Invokes the method represented by @method on the object @obj.
4905 * obj is the 'this' pointer, it should be NULL for static
4906 * methods, a MonoObject* for object instances and a pointer to
4907 * the value type for value types.
4909 * The params array contains the arguments to the method with the
4910 * same convention: MonoObject* pointers for object instances and
4911 * pointers to the value type otherwise. The _invoke_array
4912 * variant takes a C# object[] as the params argument (MonoArray
4913 * *params): in this case the value types are boxed inside the
4914 * respective reference representation.
4916 * From unmanaged code you'll usually use the
4917 * mono_runtime_invoke_checked() variant.
4919 * Note that this function doesn't handle virtual methods for
4920 * you, it will exec the exact method you pass: we still need to
4921 * expose a function to lookup the derived class implementation
4922 * of a virtual method (there are examples of this in the code,
4923 * though).
4925 * On failure or exception, @error will be set. In that case, you
4926 * can't use the MonoObject* result from the function.
4928 * If the method returns a value type, it is boxed in an object
4929 * reference.
4931 MonoObject*
4932 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4933 MonoError *error)
4935 mono_error_init (error);
4936 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4940 * mono_runtime_try_invoke_array:
4941 * @method: method to invoke
4942 * @obJ: object instance
4943 * @params: arguments to the method
4944 * @exc: exception information.
4945 * @error: set on failure.
4947 * Invokes the method represented by @method on the object @obj.
4949 * obj is the 'this' pointer, it should be NULL for static
4950 * methods, a MonoObject* for object instances and a pointer to
4951 * the value type for value types.
4953 * The params array contains the arguments to the method with the
4954 * same convention: MonoObject* pointers for object instances and
4955 * pointers to the value type otherwise. The _invoke_array
4956 * variant takes a C# object[] as the params argument (MonoArray
4957 * *params): in this case the value types are boxed inside the
4958 * respective reference representation.
4960 * From unmanaged code you'll usually use the
4961 * mono_runtime_invoke_checked() variant.
4963 * Note that this function doesn't handle virtual methods for
4964 * you, it will exec the exact method you pass: we still need to
4965 * expose a function to lookup the derived class implementation
4966 * of a virtual method (there are examples of this in the code,
4967 * though).
4969 * You can pass NULL as the exc argument if you don't want to catch
4970 * exceptions, otherwise, *exc will be set to the exception thrown, if
4971 * any. On other failures, @error will be set. If an exception is
4972 * thrown or there's an error, you can't use the MonoObject* result
4973 * from the function.
4975 * If the method returns a value type, it is boxed in an object
4976 * reference.
4978 MonoObject*
4979 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4980 MonoObject **exc, MonoError *error)
4982 MONO_REQ_GC_UNSAFE_MODE;
4984 mono_error_init (error);
4986 MonoMethodSignature *sig = mono_method_signature (method);
4987 gpointer *pa = NULL;
4988 MonoObject *res;
4989 int i;
4990 gboolean has_byref_nullables = FALSE;
4992 if (NULL != params) {
4993 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4994 for (i = 0; i < mono_array_length (params); i++) {
4995 MonoType *t = sig->params [i];
4996 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4997 return_val_if_nok (error, NULL);
5001 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5002 void *o = obj;
5004 if (mono_class_is_nullable (method->klass)) {
5005 /* Need to create a boxed vtype instead */
5006 g_assert (!obj);
5008 if (!params)
5009 return NULL;
5010 else {
5011 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5015 if (!obj) {
5016 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5017 mono_error_assert_ok (error);
5018 g_assert (obj); /*maybe we should raise a TLE instead?*/
5019 #ifndef DISABLE_REMOTING
5020 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5021 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5023 #endif
5024 if (method->klass->valuetype)
5025 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5026 else
5027 o = obj;
5028 } else if (method->klass->valuetype) {
5029 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5030 return_val_if_nok (error, NULL);
5033 if (exc) {
5034 mono_runtime_try_invoke (method, o, pa, exc, error);
5035 } else {
5036 mono_runtime_invoke_checked (method, o, pa, error);
5039 return (MonoObject *)obj;
5040 } else {
5041 if (mono_class_is_nullable (method->klass)) {
5042 MonoObject *nullable;
5044 /* Convert the unboxed vtype into a Nullable structure */
5045 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5046 return_val_if_nok (error, NULL);
5048 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5049 return_val_if_nok (error, NULL);
5050 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5051 obj = mono_object_unbox (nullable);
5054 /* obj must be already unboxed if needed */
5055 if (exc) {
5056 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5057 } else {
5058 res = mono_runtime_invoke_checked (method, obj, pa, error);
5060 return_val_if_nok (error, NULL);
5062 if (sig->ret->type == MONO_TYPE_PTR) {
5063 MonoClass *pointer_class;
5064 static MonoMethod *box_method;
5065 void *box_args [2];
5066 MonoObject *box_exc;
5069 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5070 * convert it to a Pointer object.
5072 pointer_class = mono_class_get_pointer_class ();
5073 if (!box_method)
5074 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5076 g_assert (res->vtable->klass == mono_defaults.int_class);
5077 box_args [0] = ((MonoIntPtr*)res)->m_value;
5078 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5079 return_val_if_nok (error, NULL);
5081 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5082 g_assert (box_exc == NULL);
5083 mono_error_assert_ok (error);
5086 if (has_byref_nullables) {
5088 * The runtime invoke wrapper already converted byref nullables back,
5089 * and stored them in pa, we just need to copy them back to the
5090 * managed array.
5092 for (i = 0; i < mono_array_length (params); i++) {
5093 MonoType *t = sig->params [i];
5095 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5096 mono_array_setref (params, i, pa [i]);
5100 return res;
5105 * mono_object_new:
5106 * @klass: the class of the object that we want to create
5108 * Returns: a newly created object whose definition is
5109 * looked up using @klass. This will not invoke any constructors,
5110 * so the consumer of this routine has to invoke any constructors on
5111 * its own to initialize the object.
5113 * It returns NULL on failure.
5115 MonoObject *
5116 mono_object_new (MonoDomain *domain, MonoClass *klass)
5118 MONO_REQ_GC_UNSAFE_MODE;
5120 MonoError error;
5122 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5124 mono_error_cleanup (&error);
5125 return result;
5128 MonoObject *
5129 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5131 MONO_REQ_GC_UNSAFE_MODE;
5133 MonoError error;
5135 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5137 mono_error_set_pending_exception (&error);
5138 return result;
5142 * mono_object_new_checked:
5143 * @klass: the class of the object that we want to create
5144 * @error: set on error
5146 * Returns: a newly created object whose definition is
5147 * looked up using @klass. This will not invoke any constructors,
5148 * so the consumer of this routine has to invoke any constructors on
5149 * its own to initialize the object.
5151 * It returns NULL on failure and sets @error.
5153 MonoObject *
5154 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5156 MONO_REQ_GC_UNSAFE_MODE;
5158 MonoVTable *vtable;
5160 vtable = mono_class_vtable (domain, klass);
5161 g_assert (vtable); /* FIXME don't swallow the error */
5163 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5164 return o;
5168 * mono_object_new_pinned:
5170 * Same as mono_object_new, but the returned object will be pinned.
5171 * For SGEN, these objects will only be freed at appdomain unload.
5173 MonoObject *
5174 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5176 MONO_REQ_GC_UNSAFE_MODE;
5178 MonoVTable *vtable;
5180 mono_error_init (error);
5182 vtable = mono_class_vtable (domain, klass);
5183 g_assert (vtable); /* FIXME don't swallow the error */
5185 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5187 if (G_UNLIKELY (!o))
5188 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5189 else if (G_UNLIKELY (vtable->klass->has_finalize))
5190 mono_object_register_finalizer (o);
5192 return o;
5196 * mono_object_new_specific:
5197 * @vtable: the vtable of the object that we want to create
5199 * Returns: A newly created object with class and domain specified
5200 * by @vtable
5202 MonoObject *
5203 mono_object_new_specific (MonoVTable *vtable)
5205 MonoError error;
5206 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5207 mono_error_cleanup (&error);
5209 return o;
5212 MonoObject *
5213 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5215 MONO_REQ_GC_UNSAFE_MODE;
5217 MonoObject *o;
5219 mono_error_init (error);
5221 /* check for is_com_object for COM Interop */
5222 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5224 gpointer pa [1];
5225 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5227 if (im == NULL) {
5228 MonoClass *klass = mono_class_get_activation_services_class ();
5230 if (!klass->inited)
5231 mono_class_init (klass);
5233 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5234 if (!im) {
5235 mono_error_set_not_supported (error, "Linked away.");
5236 return NULL;
5238 vtable->domain->create_proxy_for_type_method = im;
5241 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5242 if (!mono_error_ok (error))
5243 return NULL;
5245 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5246 if (!mono_error_ok (error))
5247 return NULL;
5249 if (o != NULL)
5250 return o;
5253 return mono_object_new_alloc_specific_checked (vtable, error);
5256 MonoObject *
5257 ves_icall_object_new_specific (MonoVTable *vtable)
5259 MonoError error;
5260 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5261 mono_error_set_pending_exception (&error);
5263 return o;
5267 * mono_object_new_alloc_specific:
5268 * @vtable: virtual table for the object.
5270 * This function allocates a new `MonoObject` with the type derived
5271 * from the @vtable information. If the class of this object has a
5272 * finalizer, then the object will be tracked for finalization.
5274 * This method might raise an exception on errors. Use the
5275 * `mono_object_new_fast_checked` method if you want to manually raise
5276 * the exception.
5278 * Returns: the allocated object.
5280 MonoObject *
5281 mono_object_new_alloc_specific (MonoVTable *vtable)
5283 MonoError error;
5284 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5285 mono_error_cleanup (&error);
5287 return o;
5291 * mono_object_new_alloc_specific_checked:
5292 * @vtable: virtual table for the object.
5293 * @error: holds the error return value.
5295 * This function allocates a new `MonoObject` with the type derived
5296 * from the @vtable information. If the class of this object has a
5297 * finalizer, then the object will be tracked for finalization.
5299 * If there is not enough memory, the @error parameter will be set
5300 * and will contain a user-visible message with the amount of bytes
5301 * that were requested.
5303 * Returns: the allocated object, or NULL if there is not enough memory
5306 MonoObject *
5307 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5309 MONO_REQ_GC_UNSAFE_MODE;
5311 MonoObject *o;
5313 mono_error_init (error);
5315 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5317 if (G_UNLIKELY (!o))
5318 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5319 else if (G_UNLIKELY (vtable->klass->has_finalize))
5320 mono_object_register_finalizer (o);
5322 return o;
5326 * mono_object_new_fast:
5327 * @vtable: virtual table for the object.
5329 * This function allocates a new `MonoObject` with the type derived
5330 * from the @vtable information. The returned object is not tracked
5331 * for finalization. If your object implements a finalizer, you should
5332 * use `mono_object_new_alloc_specific` instead.
5334 * This method might raise an exception on errors. Use the
5335 * `mono_object_new_fast_checked` method if you want to manually raise
5336 * the exception.
5338 * Returns: the allocated object.
5340 MonoObject*
5341 mono_object_new_fast (MonoVTable *vtable)
5343 MonoError error;
5344 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5345 mono_error_cleanup (&error);
5347 return o;
5351 * mono_object_new_fast_checked:
5352 * @vtable: virtual table for the object.
5353 * @error: holds the error return value.
5355 * This function allocates a new `MonoObject` with the type derived
5356 * from the @vtable information. The returned object is not tracked
5357 * for finalization. If your object implements a finalizer, you should
5358 * use `mono_object_new_alloc_specific_checked` instead.
5360 * If there is not enough memory, the @error parameter will be set
5361 * and will contain a user-visible message with the amount of bytes
5362 * that were requested.
5364 * Returns: the allocated object, or NULL if there is not enough memory
5367 MonoObject*
5368 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5370 MONO_REQ_GC_UNSAFE_MODE;
5372 MonoObject *o;
5374 mono_error_init (error);
5376 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5378 if (G_UNLIKELY (!o))
5379 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5381 return o;
5384 MonoObject *
5385 ves_icall_object_new_fast (MonoVTable *vtable)
5387 MonoError error;
5388 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5389 mono_error_set_pending_exception (&error);
5391 return o;
5394 MonoObject*
5395 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5397 MONO_REQ_GC_UNSAFE_MODE;
5399 MonoObject *o;
5401 mono_error_init (error);
5403 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5405 if (G_UNLIKELY (!o))
5406 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5407 else if (G_UNLIKELY (vtable->klass->has_finalize))
5408 mono_object_register_finalizer (o);
5410 return o;
5414 * mono_class_get_allocation_ftn:
5415 * @vtable: vtable
5416 * @for_box: the object will be used for boxing
5417 * @pass_size_in_words:
5419 * Return the allocation function appropriate for the given class.
5422 void*
5423 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5425 MONO_REQ_GC_NEUTRAL_MODE;
5427 *pass_size_in_words = FALSE;
5429 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5430 return ves_icall_object_new_specific;
5432 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5434 return ves_icall_object_new_fast;
5437 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5438 * of the overhead of parameter passing.
5441 *pass_size_in_words = TRUE;
5442 #ifdef GC_REDIRECT_TO_LOCAL
5443 return GC_local_gcj_fast_malloc;
5444 #else
5445 return GC_gcj_fast_malloc;
5446 #endif
5450 return ves_icall_object_new_specific;
5454 * mono_object_new_from_token:
5455 * @image: Context where the type_token is hosted
5456 * @token: a token of the type that we want to create
5458 * Returns: A newly created object whose definition is
5459 * looked up using @token in the @image image
5461 MonoObject *
5462 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5464 MONO_REQ_GC_UNSAFE_MODE;
5466 MonoError error;
5467 MonoObject *result;
5468 MonoClass *klass;
5470 klass = mono_class_get_checked (image, token, &error);
5471 mono_error_assert_ok (&error);
5473 result = mono_object_new_checked (domain, klass, &error);
5475 mono_error_cleanup (&error);
5476 return result;
5482 * mono_object_clone:
5483 * @obj: the object to clone
5485 * Returns: A newly created object who is a shallow copy of @obj
5487 MonoObject *
5488 mono_object_clone (MonoObject *obj)
5490 MonoError error;
5491 MonoObject *o = mono_object_clone_checked (obj, &error);
5492 mono_error_cleanup (&error);
5494 return o;
5497 MonoObject *
5498 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5500 MONO_REQ_GC_UNSAFE_MODE;
5502 MonoObject *o;
5503 int size;
5505 mono_error_init (error);
5507 size = obj->vtable->klass->instance_size;
5509 if (obj->vtable->klass->rank)
5510 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5512 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5514 if (G_UNLIKELY (!o)) {
5515 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5516 return NULL;
5519 /* If the object doesn't contain references this will do a simple memmove. */
5520 mono_gc_wbarrier_object_copy (o, obj);
5522 if (obj->vtable->klass->has_finalize)
5523 mono_object_register_finalizer (o);
5524 return o;
5528 * mono_array_full_copy:
5529 * @src: source array to copy
5530 * @dest: destination array
5532 * Copies the content of one array to another with exactly the same type and size.
5534 void
5535 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5537 MONO_REQ_GC_UNSAFE_MODE;
5539 uintptr_t size;
5540 MonoClass *klass = src->obj.vtable->klass;
5542 g_assert (klass == dest->obj.vtable->klass);
5544 size = mono_array_length (src);
5545 g_assert (size == mono_array_length (dest));
5546 size *= mono_array_element_size (klass);
5547 #ifdef HAVE_SGEN_GC
5548 if (klass->element_class->valuetype) {
5549 if (klass->element_class->has_references)
5550 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5551 else
5552 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5553 } else {
5554 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5556 #else
5557 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5558 #endif
5562 * mono_array_clone_in_domain:
5563 * @domain: the domain in which the array will be cloned into
5564 * @array: the array to clone
5565 * @error: set on error
5567 * This routine returns a copy of the array that is hosted on the
5568 * specified MonoDomain. On failure returns NULL and sets @error.
5570 MonoArray*
5571 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5573 MONO_REQ_GC_UNSAFE_MODE;
5575 MonoArray *o;
5576 uintptr_t size, i;
5577 uintptr_t *sizes;
5578 MonoClass *klass = array->obj.vtable->klass;
5580 mono_error_init (error);
5582 if (array->bounds == NULL) {
5583 size = mono_array_length (array);
5584 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5585 return_val_if_nok (error, NULL);
5587 size *= mono_array_element_size (klass);
5588 #ifdef HAVE_SGEN_GC
5589 if (klass->element_class->valuetype) {
5590 if (klass->element_class->has_references)
5591 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5592 else
5593 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5594 } else {
5595 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5597 #else
5598 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5599 #endif
5600 return o;
5603 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5604 size = mono_array_element_size (klass);
5605 for (i = 0; i < klass->rank; ++i) {
5606 sizes [i] = array->bounds [i].length;
5607 size *= array->bounds [i].length;
5608 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5610 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5611 return_val_if_nok (error, NULL);
5612 #ifdef HAVE_SGEN_GC
5613 if (klass->element_class->valuetype) {
5614 if (klass->element_class->has_references)
5615 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5616 else
5617 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5618 } else {
5619 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5621 #else
5622 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5623 #endif
5625 return o;
5629 * mono_array_clone:
5630 * @array: the array to clone
5632 * Returns: A newly created array who is a shallow copy of @array
5634 MonoArray*
5635 mono_array_clone (MonoArray *array)
5637 MONO_REQ_GC_UNSAFE_MODE;
5639 MonoError error;
5640 MonoArray *result = mono_array_clone_checked (array, &error);
5641 mono_error_cleanup (&error);
5642 return result;
5646 * mono_array_clone_checked:
5647 * @array: the array to clone
5648 * @error: set on error
5650 * Returns: A newly created array who is a shallow copy of @array. On
5651 * failure returns NULL and sets @error.
5653 MonoArray*
5654 mono_array_clone_checked (MonoArray *array, MonoError *error)
5657 MONO_REQ_GC_UNSAFE_MODE;
5658 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5661 /* helper macros to check for overflow when calculating the size of arrays */
5662 #ifdef MONO_BIG_ARRAYS
5663 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5664 #define MYGUINT_MAX MYGUINT64_MAX
5665 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5666 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5667 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5668 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5669 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5670 #else
5671 #define MYGUINT32_MAX 4294967295U
5672 #define MYGUINT_MAX MYGUINT32_MAX
5673 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5674 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5675 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5676 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5677 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5678 #endif
5680 gboolean
5681 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5683 MONO_REQ_GC_NEUTRAL_MODE;
5685 uintptr_t byte_len;
5687 byte_len = mono_array_element_size (klass);
5688 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5689 return FALSE;
5690 byte_len *= len;
5691 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5692 return FALSE;
5693 byte_len += MONO_SIZEOF_MONO_ARRAY;
5695 *res = byte_len;
5697 return TRUE;
5701 * mono_array_new_full:
5702 * @domain: domain where the object is created
5703 * @array_class: array class
5704 * @lengths: lengths for each dimension in the array
5705 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5707 * This routine creates a new array objects with the given dimensions,
5708 * lower bounds and type.
5710 MonoArray*
5711 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5713 MonoError error;
5714 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5715 mono_error_cleanup (&error);
5717 return array;
5720 MonoArray*
5721 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5723 MONO_REQ_GC_UNSAFE_MODE;
5725 uintptr_t byte_len = 0, len, bounds_size;
5726 MonoObject *o;
5727 MonoArray *array;
5728 MonoArrayBounds *bounds;
5729 MonoVTable *vtable;
5730 int i;
5732 mono_error_init (error);
5734 if (!array_class->inited)
5735 mono_class_init (array_class);
5737 len = 1;
5739 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5740 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5741 len = lengths [0];
5742 if (len > MONO_ARRAY_MAX_INDEX) {
5743 mono_error_set_generic_error (error, "System", "OverflowException", "");
5744 return NULL;
5746 bounds_size = 0;
5747 } else {
5748 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5750 for (i = 0; i < array_class->rank; ++i) {
5751 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5752 mono_error_set_generic_error (error, "System", "OverflowException", "");
5753 return NULL;
5755 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5756 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5757 return NULL;
5759 len *= lengths [i];
5763 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5764 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5765 return NULL;
5768 if (bounds_size) {
5769 /* align */
5770 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5771 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5772 return NULL;
5774 byte_len = (byte_len + 3) & ~3;
5775 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5776 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5777 return NULL;
5779 byte_len += bounds_size;
5782 * Following three lines almost taken from mono_object_new ():
5783 * they need to be kept in sync.
5785 vtable = mono_class_vtable_full (domain, array_class, error);
5786 return_val_if_nok (error, NULL);
5788 if (bounds_size)
5789 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5790 else
5791 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5793 if (G_UNLIKELY (!o)) {
5794 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5795 return NULL;
5798 array = (MonoArray*)o;
5800 bounds = array->bounds;
5802 if (bounds_size) {
5803 for (i = 0; i < array_class->rank; ++i) {
5804 bounds [i].length = lengths [i];
5805 if (lower_bounds)
5806 bounds [i].lower_bound = lower_bounds [i];
5810 return array;
5814 * mono_array_new:
5815 * @domain: domain where the object is created
5816 * @eclass: element class
5817 * @n: number of array elements
5819 * This routine creates a new szarray with @n elements of type @eclass.
5821 MonoArray *
5822 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5824 MONO_REQ_GC_UNSAFE_MODE;
5826 MonoError error;
5827 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5828 mono_error_cleanup (&error);
5829 return result;
5833 * mono_array_new_checked:
5834 * @domain: domain where the object is created
5835 * @eclass: element class
5836 * @n: number of array elements
5837 * @error: set on error
5839 * This routine creates a new szarray with @n elements of type @eclass.
5840 * On failure returns NULL and sets @error.
5842 MonoArray *
5843 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5845 MonoClass *ac;
5847 mono_error_init (error);
5849 ac = mono_array_class_get (eclass, 1);
5850 g_assert (ac);
5852 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5853 return_val_if_nok (error, NULL);
5855 return mono_array_new_specific_checked (vtable, n, error);
5858 MonoArray*
5859 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5861 MonoError error;
5862 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5863 mono_error_set_pending_exception (&error);
5865 return arr;
5869 * mono_array_new_specific:
5870 * @vtable: a vtable in the appropriate domain for an initialized class
5871 * @n: number of array elements
5873 * This routine is a fast alternative to mono_array_new() for code which
5874 * can be sure about the domain it operates in.
5876 MonoArray *
5877 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5879 MonoError error;
5880 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5881 mono_error_cleanup (&error);
5883 return arr;
5886 MonoArray*
5887 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5889 MONO_REQ_GC_UNSAFE_MODE;
5891 MonoObject *o;
5892 uintptr_t byte_len;
5894 mono_error_init (error);
5896 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5897 mono_error_set_generic_error (error, "System", "OverflowException", "");
5898 return NULL;
5901 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5902 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5903 return NULL;
5905 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5907 if (G_UNLIKELY (!o)) {
5908 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5909 return NULL;
5912 return (MonoArray*)o;
5915 MonoArray*
5916 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5918 MonoError error;
5919 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5920 mono_error_set_pending_exception (&error);
5922 return arr;
5926 * mono_string_empty_wrapper:
5928 * Returns: The same empty string instance as the managed string.Empty
5930 MonoString*
5931 mono_string_empty_wrapper (void)
5933 MonoDomain *domain = mono_domain_get ();
5934 return mono_string_empty (domain);
5938 * mono_string_empty:
5940 * Returns: The same empty string instance as the managed string.Empty
5942 MonoString*
5943 mono_string_empty (MonoDomain *domain)
5945 g_assert (domain);
5946 g_assert (domain->empty_string);
5947 return domain->empty_string;
5951 * mono_string_new_utf16:
5952 * @text: a pointer to an utf16 string
5953 * @len: the length of the string
5955 * Returns: A newly created string object which contains @text.
5957 MonoString *
5958 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5960 MONO_REQ_GC_UNSAFE_MODE;
5962 MonoError error;
5963 MonoString *res = NULL;
5964 res = mono_string_new_utf16_checked (domain, text, len, &error);
5965 mono_error_cleanup (&error);
5967 return res;
5971 * mono_string_new_utf16_checked:
5972 * @text: a pointer to an utf16 string
5973 * @len: the length of the string
5974 * @error: written on error.
5976 * Returns: A newly created string object which contains @text.
5977 * On error, returns NULL and sets @error.
5979 MonoString *
5980 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5982 MONO_REQ_GC_UNSAFE_MODE;
5984 MonoString *s;
5986 mono_error_init (error);
5988 s = mono_string_new_size_checked (domain, len, error);
5989 if (s != NULL)
5990 memcpy (mono_string_chars (s), text, len * 2);
5992 return s;
5996 * mono_string_new_utf32:
5997 * @text: a pointer to an utf32 string
5998 * @len: the length of the string
5999 * @error: set on failure.
6001 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6003 static MonoString *
6004 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6006 MONO_REQ_GC_UNSAFE_MODE;
6008 MonoString *s;
6009 mono_unichar2 *utf16_output = NULL;
6010 gint32 utf16_len = 0;
6011 GError *gerror = NULL;
6012 glong items_written;
6014 mono_error_init (error);
6015 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6017 if (gerror)
6018 g_error_free (gerror);
6020 while (utf16_output [utf16_len]) utf16_len++;
6022 s = mono_string_new_size_checked (domain, utf16_len, error);
6023 return_val_if_nok (error, NULL);
6025 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6027 g_free (utf16_output);
6029 return s;
6033 * mono_string_new_utf32:
6034 * @text: a pointer to an utf32 string
6035 * @len: the length of the string
6037 * Returns: A newly created string object which contains @text.
6039 MonoString *
6040 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6042 MonoError error;
6043 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6044 mono_error_cleanup (&error);
6045 return result;
6049 * mono_string_new_size:
6050 * @text: a pointer to an utf16 string
6051 * @len: the length of the string
6053 * Returns: A newly created string object of @len
6055 MonoString *
6056 mono_string_new_size (MonoDomain *domain, gint32 len)
6058 MonoError error;
6059 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6060 mono_error_cleanup (&error);
6062 return str;
6065 MonoString *
6066 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6068 MONO_REQ_GC_UNSAFE_MODE;
6070 MonoString *s;
6071 MonoVTable *vtable;
6072 size_t size;
6074 mono_error_init (error);
6076 /* check for overflow */
6077 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6078 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6079 return NULL;
6082 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6083 g_assert (size > 0);
6085 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6086 g_assert (vtable);
6088 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6090 if (G_UNLIKELY (!s)) {
6091 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6092 return NULL;
6095 return s;
6099 * mono_string_new_len:
6100 * @text: a pointer to an utf8 string
6101 * @length: number of bytes in @text to consider
6103 * Returns: A newly created string object which contains @text.
6105 MonoString*
6106 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6108 MONO_REQ_GC_UNSAFE_MODE;
6110 MonoError error;
6111 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6112 mono_error_cleanup (&error);
6113 return result;
6117 * mono_string_new_len_checked:
6118 * @text: a pointer to an utf8 string
6119 * @length: number of bytes in @text to consider
6120 * @error: set on error
6122 * Returns: A newly created string object which contains @text. On
6123 * failure returns NULL and sets @error.
6125 MonoString*
6126 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6128 MONO_REQ_GC_UNSAFE_MODE;
6130 mono_error_init (error);
6132 GError *eg_error = NULL;
6133 MonoString *o = NULL;
6134 guint16 *ut = NULL;
6135 glong items_written;
6137 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6139 if (!eg_error)
6140 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6141 else
6142 g_error_free (eg_error);
6144 g_free (ut);
6146 return o;
6150 * mono_string_new:
6151 * @text: a pointer to an utf8 string
6153 * Returns: A newly created string object which contains @text.
6155 * This function asserts if it cannot allocate a new string.
6157 * @deprecated Use mono_string_new_checked in new code.
6159 MonoString*
6160 mono_string_new (MonoDomain *domain, const char *text)
6162 MonoError error;
6163 MonoString *res = NULL;
6164 res = mono_string_new_checked (domain, text, &error);
6165 mono_error_assert_ok (&error);
6166 return res;
6170 * mono_string_new_checked:
6171 * @text: a pointer to an utf8 string
6172 * @merror: set on error
6174 * Returns: A newly created string object which contains @text.
6175 * On error returns NULL and sets @merror.
6177 MonoString*
6178 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6180 MONO_REQ_GC_UNSAFE_MODE;
6182 GError *eg_error = NULL;
6183 MonoString *o = NULL;
6184 guint16 *ut;
6185 glong items_written;
6186 int l;
6188 mono_error_init (error);
6190 l = strlen (text);
6192 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6194 if (!eg_error)
6195 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6196 else
6197 g_error_free (eg_error);
6199 g_free (ut);
6201 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6202 #if 0
6203 gunichar2 *str;
6204 const gchar *end;
6205 int len;
6206 MonoString *o = NULL;
6208 if (!g_utf8_validate (text, -1, &end)) {
6209 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6210 goto leave;
6213 len = g_utf8_strlen (text, -1);
6214 o = mono_string_new_size_checked (domain, len, error);
6215 if (!o)
6216 goto leave;
6217 str = mono_string_chars (o);
6219 while (text < end) {
6220 *str++ = g_utf8_get_char (text);
6221 text = g_utf8_next_char (text);
6224 leave:
6225 #endif
6226 return o;
6230 * mono_string_new_wrapper:
6231 * @text: pointer to utf8 characters.
6233 * Helper function to create a string object from @text in the current domain.
6235 MonoString*
6236 mono_string_new_wrapper (const char *text)
6238 MONO_REQ_GC_UNSAFE_MODE;
6240 MonoDomain *domain = mono_domain_get ();
6242 if (text)
6243 return mono_string_new (domain, text);
6245 return NULL;
6249 * mono_value_box:
6250 * @class: the class of the value
6251 * @value: a pointer to the unboxed data
6253 * Returns: A newly created object which contains @value.
6255 MonoObject *
6256 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6258 MonoError error;
6259 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6260 mono_error_cleanup (&error);
6261 return result;
6265 * mono_value_box_checked:
6266 * @domain: the domain of the new object
6267 * @class: the class of the value
6268 * @value: a pointer to the unboxed data
6269 * @error: set on error
6271 * Returns: A newly created object which contains @value. On failure
6272 * returns NULL and sets @error.
6274 MonoObject *
6275 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6277 MONO_REQ_GC_UNSAFE_MODE;
6278 MonoObject *res;
6279 int size;
6280 MonoVTable *vtable;
6282 mono_error_init (error);
6284 g_assert (klass->valuetype);
6285 if (mono_class_is_nullable (klass))
6286 return mono_nullable_box ((guint8 *)value, klass, error);
6288 vtable = mono_class_vtable (domain, klass);
6289 if (!vtable)
6290 return NULL;
6291 size = mono_class_instance_size (klass);
6292 res = mono_object_new_alloc_specific_checked (vtable, error);
6293 return_val_if_nok (error, NULL);
6295 size = size - sizeof (MonoObject);
6297 #ifdef HAVE_SGEN_GC
6298 g_assert (size == mono_class_value_size (klass, NULL));
6299 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6300 #else
6301 #if NO_UNALIGNED_ACCESS
6302 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6303 #else
6304 switch (size) {
6305 case 1:
6306 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6307 break;
6308 case 2:
6309 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6310 break;
6311 case 4:
6312 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6313 break;
6314 case 8:
6315 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6316 break;
6317 default:
6318 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6320 #endif
6321 #endif
6322 if (klass->has_finalize) {
6323 mono_object_register_finalizer (res);
6324 return_val_if_nok (error, NULL);
6326 return res;
6330 * mono_value_copy:
6331 * @dest: destination pointer
6332 * @src: source pointer
6333 * @klass: a valuetype class
6335 * Copy a valuetype from @src to @dest. This function must be used
6336 * when @klass contains references fields.
6338 void
6339 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6341 MONO_REQ_GC_UNSAFE_MODE;
6343 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6347 * mono_value_copy_array:
6348 * @dest: destination array
6349 * @dest_idx: index in the @dest array
6350 * @src: source pointer
6351 * @count: number of items
6353 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6354 * This function must be used when @klass contains references fields.
6355 * Overlap is handled.
6357 void
6358 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6360 MONO_REQ_GC_UNSAFE_MODE;
6362 int size = mono_array_element_size (dest->obj.vtable->klass);
6363 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6364 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6365 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6369 * mono_object_get_domain:
6370 * @obj: object to query
6372 * Returns: the MonoDomain where the object is hosted
6374 MonoDomain*
6375 mono_object_get_domain (MonoObject *obj)
6377 MONO_REQ_GC_UNSAFE_MODE;
6379 return mono_object_domain (obj);
6383 * mono_object_get_class:
6384 * @obj: object to query
6386 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6388 * Returns: the MonoClass of the object.
6390 MonoClass*
6391 mono_object_get_class (MonoObject *obj)
6393 MONO_REQ_GC_UNSAFE_MODE;
6395 return mono_object_class (obj);
6398 * mono_object_get_size:
6399 * @o: object to query
6401 * Returns: the size, in bytes, of @o
6403 guint
6404 mono_object_get_size (MonoObject* o)
6406 MONO_REQ_GC_UNSAFE_MODE;
6408 MonoClass* klass = mono_object_class (o);
6409 if (klass == mono_defaults.string_class) {
6410 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6411 } else if (o->vtable->rank) {
6412 MonoArray *array = (MonoArray*)o;
6413 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6414 if (array->bounds) {
6415 size += 3;
6416 size &= ~3;
6417 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6419 return size;
6420 } else {
6421 return mono_class_instance_size (klass);
6426 * mono_object_unbox:
6427 * @obj: object to unbox
6429 * Returns: a pointer to the start of the valuetype boxed in this
6430 * object.
6432 * This method will assert if the object passed is not a valuetype.
6434 gpointer
6435 mono_object_unbox (MonoObject *obj)
6437 MONO_REQ_GC_UNSAFE_MODE;
6439 /* add assert for valuetypes? */
6440 g_assert (obj->vtable->klass->valuetype);
6441 return ((char*)obj) + sizeof (MonoObject);
6445 * mono_object_isinst:
6446 * @obj: an object
6447 * @klass: a pointer to a class
6449 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6451 MonoObject *
6452 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6454 MONO_REQ_GC_UNSAFE_MODE;
6456 MonoError error;
6457 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6458 mono_error_cleanup (&error);
6459 return result;
6464 * mono_object_isinst_checked:
6465 * @obj: an object
6466 * @klass: a pointer to a class
6467 * @error: set on error
6469 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6470 * On failure returns NULL and sets @error.
6472 MonoObject *
6473 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6475 MONO_REQ_GC_UNSAFE_MODE;
6477 mono_error_init (error);
6479 MonoObject *result = NULL;
6481 if (!klass->inited)
6482 mono_class_init (klass);
6484 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6485 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6486 return result;
6489 if (!obj)
6490 return NULL;
6492 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6495 MonoObject *
6496 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6498 MONO_REQ_GC_UNSAFE_MODE;
6500 MonoError error;
6501 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6502 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6503 return result;
6506 MonoObject *
6507 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6509 MONO_REQ_GC_UNSAFE_MODE;
6511 MonoVTable *vt;
6513 mono_error_init (error);
6515 if (!obj)
6516 return NULL;
6518 vt = obj->vtable;
6520 if (mono_class_is_interface (klass)) {
6521 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6522 return obj;
6525 /* casting an array one of the invariant interfaces that must act as such */
6526 if (klass->is_array_special_interface) {
6527 if (mono_class_is_assignable_from (klass, vt->klass))
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 else 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;
6954 char *
6955 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6957 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6961 * mono_string_to_utf8_ignore:
6962 * @s: a MonoString
6964 * Converts a MonoString to its UTF8 representation. Will ignore
6965 * invalid surrogate pairs.
6966 * The resulting buffer should be freed with mono_free().
6969 char *
6970 mono_string_to_utf8_ignore (MonoString *s)
6972 MONO_REQ_GC_UNSAFE_MODE;
6974 long written = 0;
6975 char *as;
6977 if (s == NULL)
6978 return NULL;
6980 if (!s->length)
6981 return g_strdup ("");
6983 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6985 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6986 if (s->length > written) {
6987 /* allocate the total length and copy the part of the string that has been converted */
6988 char *as2 = (char *)g_malloc0 (s->length);
6989 memcpy (as2, as, written);
6990 g_free (as);
6991 as = as2;
6994 return as;
6998 * mono_string_to_utf8_image_ignore:
6999 * @s: a System.String
7001 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7003 char *
7004 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7006 MONO_REQ_GC_UNSAFE_MODE;
7008 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7012 * mono_string_to_utf8_mp_ignore:
7013 * @s: a System.String
7015 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7017 char *
7018 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7020 MONO_REQ_GC_UNSAFE_MODE;
7022 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7027 * mono_string_to_utf16:
7028 * @s: a MonoString
7030 * Return an null-terminated array of the utf-16 chars
7031 * contained in @s. The result must be freed with g_free().
7032 * This is a temporary helper until our string implementation
7033 * is reworked to always include the null terminating char.
7035 mono_unichar2*
7036 mono_string_to_utf16 (MonoString *s)
7038 MONO_REQ_GC_UNSAFE_MODE;
7040 char *as;
7042 if (s == NULL)
7043 return NULL;
7045 as = (char *)g_malloc ((s->length * 2) + 2);
7046 as [(s->length * 2)] = '\0';
7047 as [(s->length * 2) + 1] = '\0';
7049 if (!s->length) {
7050 return (gunichar2 *)(as);
7053 memcpy (as, mono_string_chars(s), s->length * 2);
7054 return (gunichar2 *)(as);
7058 * mono_string_to_utf32:
7059 * @s: a MonoString
7061 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7062 * contained in @s. The result must be freed with g_free().
7064 mono_unichar4*
7065 mono_string_to_utf32 (MonoString *s)
7067 MONO_REQ_GC_UNSAFE_MODE;
7069 mono_unichar4 *utf32_output = NULL;
7070 GError *error = NULL;
7071 glong items_written;
7073 if (s == NULL)
7074 return NULL;
7076 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7078 if (error)
7079 g_error_free (error);
7081 return utf32_output;
7085 * mono_string_from_utf16:
7086 * @data: the UTF16 string (LPWSTR) to convert
7088 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7090 * Returns: a MonoString.
7092 MonoString *
7093 mono_string_from_utf16 (gunichar2 *data)
7095 MonoError error;
7096 MonoString *result = mono_string_from_utf16_checked (data, &error);
7097 mono_error_cleanup (&error);
7098 return result;
7102 * mono_string_from_utf16_checked:
7103 * @data: the UTF16 string (LPWSTR) to convert
7104 * @error: set on error
7106 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7108 * Returns: a MonoString. On failure sets @error and returns NULL.
7110 MonoString *
7111 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7114 MONO_REQ_GC_UNSAFE_MODE;
7116 mono_error_init (error);
7117 MonoDomain *domain = mono_domain_get ();
7118 int len = 0;
7120 if (!data)
7121 return NULL;
7123 while (data [len]) len++;
7125 return mono_string_new_utf16_checked (domain, data, len, error);
7129 * mono_string_from_utf32:
7130 * @data: the UTF32 string (LPWSTR) to convert
7132 * Converts a UTF32 (UCS-4)to a MonoString.
7134 * Returns: a MonoString.
7136 MonoString *
7137 mono_string_from_utf32 (mono_unichar4 *data)
7139 MonoError error;
7140 MonoString *result = mono_string_from_utf32_checked (data, &error);
7141 mono_error_cleanup (&error);
7142 return result;
7146 * mono_string_from_utf32_checked:
7147 * @data: the UTF32 string (LPWSTR) to convert
7148 * @error: set on error
7150 * Converts a UTF32 (UCS-4)to a MonoString.
7152 * Returns: a MonoString. On failure returns NULL and sets @error.
7154 MonoString *
7155 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7157 MONO_REQ_GC_UNSAFE_MODE;
7159 mono_error_init (error);
7160 MonoString* result = NULL;
7161 mono_unichar2 *utf16_output = NULL;
7162 GError *gerror = NULL;
7163 glong items_written;
7164 int len = 0;
7166 if (!data)
7167 return NULL;
7169 while (data [len]) len++;
7171 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7173 if (gerror)
7174 g_error_free (gerror);
7176 result = mono_string_from_utf16_checked (utf16_output, error);
7177 g_free (utf16_output);
7178 return result;
7181 static char *
7182 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7184 MONO_REQ_GC_UNSAFE_MODE;
7186 char *r;
7187 char *mp_s;
7188 int len;
7190 if (ignore_error) {
7191 r = mono_string_to_utf8_ignore (s);
7192 } else {
7193 r = mono_string_to_utf8_checked (s, error);
7194 if (!mono_error_ok (error))
7195 return NULL;
7198 if (!mp && !image)
7199 return r;
7201 len = strlen (r) + 1;
7202 if (mp)
7203 mp_s = (char *)mono_mempool_alloc (mp, len);
7204 else
7205 mp_s = (char *)mono_image_alloc (image, len);
7207 memcpy (mp_s, r, len);
7209 g_free (r);
7211 return mp_s;
7215 * mono_string_to_utf8_image:
7216 * @s: a System.String
7218 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7220 char *
7221 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7223 MONO_REQ_GC_UNSAFE_MODE;
7225 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7229 * mono_string_to_utf8_mp:
7230 * @s: a System.String
7232 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7234 char *
7235 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7237 MONO_REQ_GC_UNSAFE_MODE;
7239 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7243 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7245 void
7246 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7248 eh_callbacks = *cbs;
7251 MonoRuntimeExceptionHandlingCallbacks *
7252 mono_get_eh_callbacks (void)
7254 return &eh_callbacks;
7258 * mono_raise_exception:
7259 * @ex: exception object
7261 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7263 void
7264 mono_raise_exception (MonoException *ex)
7266 MONO_REQ_GC_UNSAFE_MODE;
7269 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7270 * that will cause gcc to omit the function epilog, causing problems when
7271 * the JIT tries to walk the stack, since the return address on the stack
7272 * will point into the next function in the executable, not this one.
7274 eh_callbacks.mono_raise_exception (ex);
7277 void
7278 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7280 MONO_REQ_GC_UNSAFE_MODE;
7282 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7286 * mono_wait_handle_new:
7287 * @domain: Domain where the object will be created
7288 * @handle: Handle for the wait handle
7289 * @error: set on error.
7291 * Returns: A new MonoWaitHandle created in the given domain for the
7292 * given handle. On failure returns NULL and sets @rror.
7294 MonoWaitHandle *
7295 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7297 MONO_REQ_GC_UNSAFE_MODE;
7299 MonoWaitHandle *res;
7300 gpointer params [1];
7301 static MonoMethod *handle_set;
7303 mono_error_init (error);
7304 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7305 return_val_if_nok (error, NULL);
7307 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7308 if (!handle_set)
7309 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7311 params [0] = &handle;
7313 mono_runtime_invoke_checked (handle_set, res, params, error);
7314 return res;
7317 HANDLE
7318 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7320 MONO_REQ_GC_UNSAFE_MODE;
7322 static MonoClassField *f_safe_handle = NULL;
7323 MonoSafeHandle *sh;
7325 if (!f_safe_handle) {
7326 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7327 g_assert (f_safe_handle);
7330 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7331 return sh->handle;
7335 static MonoObject*
7336 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7338 MONO_REQ_GC_UNSAFE_MODE;
7340 RuntimeInvokeFunction runtime_invoke;
7342 mono_error_init (error);
7344 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7345 MonoMethod *method = mono_get_context_capture_method ();
7346 MonoMethod *wrapper;
7347 if (!method)
7348 return NULL;
7349 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7350 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7351 return_val_if_nok (error, NULL);
7352 domain->capture_context_method = mono_compile_method_checked (method, error);
7353 return_val_if_nok (error, NULL);
7356 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7358 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7361 * mono_async_result_new:
7362 * @domain:domain where the object will be created.
7363 * @handle: wait handle.
7364 * @state: state to pass to AsyncResult
7365 * @data: C closure data.
7366 * @error: set on error.
7368 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7369 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7370 * On failure returns NULL and sets @error.
7373 MonoAsyncResult *
7374 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7376 MONO_REQ_GC_UNSAFE_MODE;
7378 mono_error_init (error);
7379 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7380 return_val_if_nok (error, NULL);
7381 MonoObject *context = mono_runtime_capture_context (domain, error);
7382 return_val_if_nok (error, NULL);
7383 /* we must capture the execution context from the original thread */
7384 if (context) {
7385 MONO_OBJECT_SETREF (res, execution_context, context);
7386 /* note: result may be null if the flow is suppressed */
7389 res->data = (void **)data;
7390 MONO_OBJECT_SETREF (res, object_data, object_data);
7391 MONO_OBJECT_SETREF (res, async_state, state);
7392 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7393 return_val_if_nok (error, NULL);
7394 if (handle != NULL)
7395 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7397 res->sync_completed = FALSE;
7398 res->completed = FALSE;
7400 return res;
7403 MonoObject *
7404 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7406 MONO_REQ_GC_UNSAFE_MODE;
7408 MonoError error;
7409 MonoAsyncCall *ac;
7410 MonoObject *res;
7412 g_assert (ares);
7413 g_assert (ares->async_delegate);
7415 ac = (MonoAsyncCall*) ares->object_data;
7416 if (!ac) {
7417 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7418 if (mono_error_set_pending_exception (&error))
7419 return NULL;
7420 } else {
7421 gpointer wait_event = NULL;
7423 ac->msg->exc = NULL;
7425 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7427 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7428 mono_threads_begin_abort_protected_block ();
7430 if (!ac->msg->exc) {
7431 MonoException *ex = mono_error_convert_to_exception (&error);
7432 ac->msg->exc = (MonoObject *)ex;
7433 } else {
7434 mono_error_cleanup (&error);
7437 MONO_OBJECT_SETREF (ac, res, res);
7439 mono_monitor_enter ((MonoObject*) ares);
7440 ares->completed = 1;
7441 if (ares->handle)
7442 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7443 mono_monitor_exit ((MonoObject*) ares);
7445 if (wait_event != NULL)
7446 mono_w32event_set (wait_event);
7448 mono_error_init (&error); //the else branch would leave it in an undefined state
7449 if (ac->cb_method)
7450 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7452 mono_threads_end_abort_protected_block ();
7454 if (mono_error_set_pending_exception (&error))
7455 return NULL;
7458 return res;
7461 gboolean
7462 mono_message_init (MonoDomain *domain,
7463 MonoMethodMessage *this_obj,
7464 MonoReflectionMethod *method,
7465 MonoArray *out_args,
7466 MonoError *error)
7468 MONO_REQ_GC_UNSAFE_MODE;
7470 static MonoMethod *init_message_method = NULL;
7472 if (!init_message_method) {
7473 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7474 g_assert (init_message_method != NULL);
7477 mono_error_init (error);
7478 /* FIXME set domain instead? */
7479 g_assert (domain == mono_domain_get ());
7481 gpointer args[2];
7483 args[0] = method;
7484 args[1] = out_args;
7486 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7487 return is_ok (error);
7490 #ifndef DISABLE_REMOTING
7492 * mono_remoting_invoke:
7493 * @real_proxy: pointer to a RealProxy object
7494 * @msg: The MonoMethodMessage to execute
7495 * @exc: used to store exceptions
7496 * @out_args: used to store output arguments
7498 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7499 * IMessage interface and it is not trivial to extract results from there. So
7500 * we call an helper method PrivateInvoke instead of calling
7501 * RealProxy::Invoke() directly.
7503 * Returns: the result object.
7505 MonoObject *
7506 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7508 MONO_REQ_GC_UNSAFE_MODE;
7510 MonoObject *o;
7511 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7512 gpointer pa [4];
7514 g_assert (exc);
7516 mono_error_init (error);
7518 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7520 if (!im) {
7521 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7522 if (!im) {
7523 mono_error_set_not_supported (error, "Linked away.");
7524 return NULL;
7526 real_proxy->vtable->domain->private_invoke_method = im;
7529 pa [0] = real_proxy;
7530 pa [1] = msg;
7531 pa [2] = exc;
7532 pa [3] = out_args;
7534 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7535 return_val_if_nok (error, NULL);
7537 return o;
7539 #endif
7541 MonoObject *
7542 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7543 MonoObject **exc, MonoArray **out_args, MonoError *error)
7545 MONO_REQ_GC_UNSAFE_MODE;
7547 static MonoClass *object_array_klass;
7548 mono_error_init (error);
7550 MonoDomain *domain;
7551 MonoMethod *method;
7552 MonoMethodSignature *sig;
7553 MonoArray *arr;
7554 int i, j, outarg_count = 0;
7556 #ifndef DISABLE_REMOTING
7557 if (target && mono_object_is_transparent_proxy (target)) {
7558 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7559 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7560 target = tp->rp->unwrapped_server;
7561 } else {
7562 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7565 #endif
7567 domain = mono_domain_get ();
7568 method = msg->method->method;
7569 sig = mono_method_signature (method);
7571 for (i = 0; i < sig->param_count; i++) {
7572 if (sig->params [i]->byref)
7573 outarg_count++;
7576 if (!object_array_klass) {
7577 MonoClass *klass;
7579 klass = mono_array_class_get (mono_defaults.object_class, 1);
7580 g_assert (klass);
7582 mono_memory_barrier ();
7583 object_array_klass = klass;
7586 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7587 return_val_if_nok (error, NULL);
7589 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7590 *exc = NULL;
7592 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7593 return_val_if_nok (error, NULL);
7595 for (i = 0, j = 0; i < sig->param_count; i++) {
7596 if (sig->params [i]->byref) {
7597 MonoObject* arg;
7598 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7599 mono_array_setref (*out_args, j, arg);
7600 j++;
7604 return ret;
7608 * prepare_to_string_method:
7609 * @obj: The object
7610 * @target: Set to @obj or unboxed value if a valuetype
7612 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7614 static MonoMethod *
7615 prepare_to_string_method (MonoObject *obj, void **target)
7617 MONO_REQ_GC_UNSAFE_MODE;
7619 static MonoMethod *to_string = NULL;
7620 MonoMethod *method;
7621 g_assert (target);
7622 g_assert (obj);
7624 *target = obj;
7626 if (!to_string)
7627 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7629 method = mono_object_get_virtual_method (obj, to_string);
7631 // Unbox value type if needed
7632 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7633 *target = mono_object_unbox (obj);
7635 return method;
7639 * mono_object_to_string:
7640 * @obj: The object
7641 * @exc: Any exception thrown by ToString (). May be NULL.
7643 * Returns: the result of calling ToString () on an object.
7645 MonoString *
7646 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7648 MonoError error;
7649 MonoString *s = NULL;
7650 void *target;
7651 MonoMethod *method = prepare_to_string_method (obj, &target);
7652 if (exc) {
7653 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7654 if (*exc == NULL && !mono_error_ok (&error))
7655 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7656 else
7657 mono_error_cleanup (&error);
7658 } else {
7659 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7660 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7663 return s;
7667 * mono_object_to_string_checked:
7668 * @obj: The object
7669 * @error: Set on error.
7671 * Returns: the result of calling ToString () on an object. If the
7672 * method cannot be invoked or if it raises an exception, sets @error
7673 * and returns NULL.
7675 MonoString *
7676 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7678 mono_error_init (error);
7679 void *target;
7680 MonoMethod *method = prepare_to_string_method (obj, &target);
7681 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7685 * mono_object_try_to_string:
7686 * @obj: The object
7687 * @exc: Any exception thrown by ToString (). Must not be NULL.
7688 * @error: Set if method cannot be invoked.
7690 * Returns: the result of calling ToString () on an object. If the
7691 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7692 * and returns NULL.
7694 MonoString *
7695 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7697 g_assert (exc);
7698 mono_error_init (error);
7699 void *target;
7700 MonoMethod *method = prepare_to_string_method (obj, &target);
7701 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7706 static char *
7707 get_native_backtrace (MonoException *exc_raw)
7709 HANDLE_FUNCTION_ENTER ();
7710 MONO_HANDLE_DCL(MonoException, exc);
7711 char * trace = mono_exception_handle_get_native_backtrace (exc);
7712 HANDLE_FUNCTION_RETURN_VAL (trace);
7716 * mono_print_unhandled_exception:
7717 * @exc: The exception
7719 * Prints the unhandled exception.
7721 void
7722 mono_print_unhandled_exception (MonoObject *exc)
7724 MONO_REQ_GC_UNSAFE_MODE;
7726 MonoString * str;
7727 char *message = (char*)"";
7728 gboolean free_message = FALSE;
7729 MonoError error;
7731 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7732 message = g_strdup ("OutOfMemoryException");
7733 free_message = TRUE;
7734 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7735 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7736 free_message = TRUE;
7737 } else {
7739 if (((MonoException*)exc)->native_trace_ips) {
7740 message = get_native_backtrace ((MonoException*)exc);
7741 free_message = TRUE;
7742 } else {
7743 MonoObject *other_exc = NULL;
7744 str = mono_object_try_to_string (exc, &other_exc, &error);
7745 if (other_exc == NULL && !is_ok (&error))
7746 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7747 else
7748 mono_error_cleanup (&error);
7749 if (other_exc) {
7750 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7751 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7753 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7754 original_backtrace, nested_backtrace);
7756 g_free (original_backtrace);
7757 g_free (nested_backtrace);
7758 free_message = TRUE;
7759 } else if (str) {
7760 message = mono_string_to_utf8_checked (str, &error);
7761 if (!mono_error_ok (&error)) {
7762 mono_error_cleanup (&error);
7763 message = (char *) "";
7764 } else {
7765 free_message = TRUE;
7772 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7773 * exc->vtable->klass->name, message);
7775 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7777 if (free_message)
7778 g_free (message);
7782 * mono_delegate_ctor_with_method:
7783 * @this: pointer to an uninitialized delegate object
7784 * @target: target object
7785 * @addr: pointer to native code
7786 * @method: method
7787 * @error: set on error.
7789 * Initialize a delegate and sets a specific method, not the one
7790 * associated with addr. This is useful when sharing generic code.
7791 * In that case addr will most probably not be associated with the
7792 * correct instantiation of the method.
7793 * On failure returns FALSE and sets @error.
7795 gboolean
7796 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7798 MONO_REQ_GC_UNSAFE_MODE;
7800 mono_error_init (error);
7801 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7803 g_assert (this_obj);
7804 g_assert (addr);
7806 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7808 if (method)
7809 delegate->method = method;
7811 mono_stats.delegate_creations++;
7813 #ifndef DISABLE_REMOTING
7814 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7815 g_assert (method);
7816 method = mono_marshal_get_remoting_invoke (method);
7817 delegate->method_ptr = mono_compile_method_checked (method, error);
7818 return_val_if_nok (error, FALSE);
7819 MONO_OBJECT_SETREF (delegate, target, target);
7820 } else
7821 #endif
7823 delegate->method_ptr = addr;
7824 MONO_OBJECT_SETREF (delegate, target, target);
7827 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7828 if (callbacks.init_delegate)
7829 callbacks.init_delegate (delegate);
7830 return TRUE;
7834 * mono_delegate_ctor:
7835 * @this: pointer to an uninitialized delegate object
7836 * @target: target object
7837 * @addr: pointer to native code
7838 * @error: set on error.
7840 * This is used to initialize a delegate.
7841 * On failure returns FALSE and sets @error.
7843 gboolean
7844 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7846 MONO_REQ_GC_UNSAFE_MODE;
7848 mono_error_init (error);
7849 MonoDomain *domain = mono_domain_get ();
7850 MonoJitInfo *ji;
7851 MonoMethod *method = NULL;
7853 g_assert (addr);
7855 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7856 /* Shared code */
7857 if (!ji && domain != mono_get_root_domain ())
7858 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7859 if (ji) {
7860 method = mono_jit_info_get_method (ji);
7861 g_assert (!mono_class_is_gtd (method->klass));
7864 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7868 * mono_method_call_message_new:
7869 * @method: method to encapsulate
7870 * @params: parameters to the method
7871 * @invoke: optional, delegate invoke.
7872 * @cb: async callback delegate.
7873 * @state: state passed to the async callback.
7874 * @error: set on error.
7876 * Translates arguments pointers into a MonoMethodMessage.
7877 * On failure returns NULL and sets @error.
7879 MonoMethodMessage *
7880 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7881 MonoDelegate **cb, MonoObject **state, MonoError *error)
7883 MONO_REQ_GC_UNSAFE_MODE;
7885 mono_error_init (error);
7887 MonoDomain *domain = mono_domain_get ();
7888 MonoMethodSignature *sig = mono_method_signature (method);
7889 MonoMethodMessage *msg;
7890 int i, count;
7892 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7893 return_val_if_nok (error, NULL);
7895 if (invoke) {
7896 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7897 return_val_if_nok (error, NULL);
7898 mono_message_init (domain, msg, rm, NULL, error);
7899 return_val_if_nok (error, NULL);
7900 count = sig->param_count - 2;
7901 } else {
7902 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7903 return_val_if_nok (error, NULL);
7904 mono_message_init (domain, msg, rm, NULL, error);
7905 return_val_if_nok (error, NULL);
7906 count = sig->param_count;
7909 for (i = 0; i < count; i++) {
7910 gpointer vpos;
7911 MonoClass *klass;
7912 MonoObject *arg;
7914 if (sig->params [i]->byref)
7915 vpos = *((gpointer *)params [i]);
7916 else
7917 vpos = params [i];
7919 klass = mono_class_from_mono_type (sig->params [i]);
7921 if (klass->valuetype) {
7922 arg = mono_value_box_checked (domain, klass, vpos, error);
7923 return_val_if_nok (error, NULL);
7924 } else
7925 arg = *((MonoObject **)vpos);
7927 mono_array_setref (msg->args, i, arg);
7930 if (cb != NULL && state != NULL) {
7931 *cb = *((MonoDelegate **)params [i]);
7932 i++;
7933 *state = *((MonoObject **)params [i]);
7936 return msg;
7940 * mono_method_return_message_restore:
7942 * Restore results from message based processing back to arguments pointers
7944 void
7945 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7947 MONO_REQ_GC_UNSAFE_MODE;
7949 mono_error_init (error);
7951 MonoMethodSignature *sig = mono_method_signature (method);
7952 int i, j, type, size, out_len;
7954 if (out_args == NULL)
7955 return;
7956 out_len = mono_array_length (out_args);
7957 if (out_len == 0)
7958 return;
7960 for (i = 0, j = 0; i < sig->param_count; i++) {
7961 MonoType *pt = sig->params [i];
7963 if (pt->byref) {
7964 char *arg;
7965 if (j >= out_len) {
7966 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7967 return;
7970 arg = (char *)mono_array_get (out_args, gpointer, j);
7971 type = pt->type;
7973 g_assert (type != MONO_TYPE_VOID);
7975 if (MONO_TYPE_IS_REFERENCE (pt)) {
7976 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7977 } else {
7978 if (arg) {
7979 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7980 size = mono_class_value_size (klass, NULL);
7981 if (klass->has_references)
7982 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7983 else
7984 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7985 } else {
7986 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7987 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7991 j++;
7996 #ifndef DISABLE_REMOTING
7999 * mono_load_remote_field:
8000 * @this: pointer to an object
8001 * @klass: klass of the object containing @field
8002 * @field: the field to load
8003 * @res: a storage to store the result
8005 * This method is called by the runtime on attempts to load fields of
8006 * transparent proxy objects. @this points to such TP, @klass is the class of
8007 * the object containing @field. @res is a storage location which can be
8008 * used to store the result.
8010 * Returns: an address pointing to the value of field.
8012 gpointer
8013 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8015 MonoError error;
8016 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8017 mono_error_cleanup (&error);
8018 return result;
8022 * mono_load_remote_field_checked:
8023 * @this: pointer to an object
8024 * @klass: klass of the object containing @field
8025 * @field: the field to load
8026 * @res: a storage to store the result
8027 * @error: set on error
8029 * This method is called by the runtime on attempts to load fields of
8030 * transparent proxy objects. @this points to such TP, @klass is the class of
8031 * the object containing @field. @res is a storage location which can be
8032 * used to store the result.
8034 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8036 gpointer
8037 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8039 MONO_REQ_GC_UNSAFE_MODE;
8041 static MonoMethod *getter = NULL;
8043 mono_error_init (error);
8045 MonoDomain *domain = mono_domain_get ();
8046 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8047 MonoClass *field_class;
8048 MonoMethodMessage *msg;
8049 MonoArray *out_args;
8050 MonoObject *exc;
8051 char* full_name;
8053 g_assert (mono_object_is_transparent_proxy (this_obj));
8054 g_assert (res != NULL);
8056 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8057 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8058 return res;
8061 if (!getter) {
8062 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8063 if (!getter) {
8064 mono_error_set_not_supported (error, "Linked away.");
8065 return NULL;
8069 field_class = mono_class_from_mono_type (field->type);
8071 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8072 return_val_if_nok (error, NULL);
8073 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8074 return_val_if_nok (error, NULL);
8075 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8076 return_val_if_nok (error, NULL);
8077 mono_message_init (domain, msg, rm, out_args, error);
8078 return_val_if_nok (error, NULL);
8080 full_name = mono_type_get_full_name (klass);
8081 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8082 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8083 g_free (full_name);
8085 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8086 return_val_if_nok (error, NULL);
8088 if (exc) {
8089 mono_error_set_exception_instance (error, (MonoException *)exc);
8090 return NULL;
8093 if (mono_array_length (out_args) == 0)
8094 return NULL;
8096 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8098 if (field_class->valuetype) {
8099 return ((char *)*res) + sizeof (MonoObject);
8100 } else
8101 return res;
8105 * mono_load_remote_field_new:
8106 * @this:
8107 * @klass:
8108 * @field:
8110 * Missing documentation.
8112 MonoObject *
8113 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8115 MonoError error;
8117 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8118 mono_error_cleanup (&error);
8119 return result;
8123 * mono_load_remote_field_new_checked:
8124 * @this: pointer to an object
8125 * @klass: klass of the object containing @field
8126 * @field: the field to load
8127 * @error: set on error.
8129 * This method is called by the runtime on attempts to load fields of
8130 * transparent proxy objects. @this points to such TP, @klass is the class of
8131 * the object containing @field.
8133 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8135 MonoObject *
8136 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8138 MONO_REQ_GC_UNSAFE_MODE;
8140 mono_error_init (error);
8142 static MonoMethod *tp_load = NULL;
8144 g_assert (mono_object_is_transparent_proxy (this_obj));
8146 if (!tp_load) {
8147 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8148 if (!tp_load) {
8149 mono_error_set_not_supported (error, "Linked away.");
8150 return NULL;
8154 /* MonoType *type = mono_class_get_type (klass); */
8156 gpointer args[2];
8157 args [0] = &klass;
8158 args [1] = &field;
8160 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8164 * mono_store_remote_field:
8165 * @this_obj: pointer to an object
8166 * @klass: klass of the object containing @field
8167 * @field: the field to load
8168 * @val: the value/object to store
8170 * This method is called by the runtime on attempts to store fields of
8171 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8172 * the object containing @field. @val is the new value to store in @field.
8174 void
8175 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8177 MonoError error;
8178 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8179 mono_error_cleanup (&error);
8183 * mono_store_remote_field_checked:
8184 * @this_obj: pointer to an object
8185 * @klass: klass of the object containing @field
8186 * @field: the field to load
8187 * @val: the value/object to store
8188 * @error: set on error
8190 * This method is called by the runtime on attempts to store fields of
8191 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8192 * the object containing @field. @val is the new value to store in @field.
8194 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8196 gboolean
8197 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8200 MONO_REQ_GC_UNSAFE_MODE;
8202 mono_error_init (error);
8204 MonoDomain *domain = mono_domain_get ();
8205 MonoClass *field_class;
8206 MonoObject *arg;
8208 g_assert (mono_object_is_transparent_proxy (this_obj));
8210 field_class = mono_class_from_mono_type (field->type);
8212 if (field_class->valuetype) {
8213 arg = mono_value_box_checked (domain, field_class, val, error);
8214 return_val_if_nok (error, FALSE);
8215 } else {
8216 arg = *((MonoObject**)val);
8219 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8223 * mono_store_remote_field_new:
8224 * @this_obj:
8225 * @klass:
8226 * @field:
8227 * @arg:
8229 * Missing documentation
8231 void
8232 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8234 MonoError error;
8235 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8236 mono_error_cleanup (&error);
8240 * mono_store_remote_field_new_checked:
8241 * @this_obj:
8242 * @klass:
8243 * @field:
8244 * @arg:
8245 * @error:
8247 * Missing documentation
8249 gboolean
8250 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8252 MONO_REQ_GC_UNSAFE_MODE;
8254 static MonoMethod *tp_store = NULL;
8256 mono_error_init (error);
8258 g_assert (mono_object_is_transparent_proxy (this_obj));
8260 if (!tp_store) {
8261 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8262 if (!tp_store) {
8263 mono_error_set_not_supported (error, "Linked away.");
8264 return FALSE;
8268 gpointer args[3];
8269 args [0] = &klass;
8270 args [1] = &field;
8271 args [2] = arg;
8273 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8274 return is_ok (error);
8276 #endif
8279 * mono_create_ftnptr:
8281 * Given a function address, create a function descriptor for it.
8282 * This is only needed on some platforms.
8284 gpointer
8285 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8287 return callbacks.create_ftnptr (domain, addr);
8291 * mono_get_addr_from_ftnptr:
8293 * Given a pointer to a function descriptor, return the function address.
8294 * This is only needed on some platforms.
8296 gpointer
8297 mono_get_addr_from_ftnptr (gpointer descr)
8299 return callbacks.get_addr_from_ftnptr (descr);
8303 * mono_string_chars:
8304 * @s: a MonoString
8306 * Returns a pointer to the UCS16 characters stored in the MonoString
8308 gunichar2 *
8309 mono_string_chars (MonoString *s)
8311 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8313 return s->chars;
8317 * mono_string_length:
8318 * @s: MonoString
8320 * Returns the lenght in characters of the string
8323 mono_string_length (MonoString *s)
8325 MONO_REQ_GC_UNSAFE_MODE;
8327 return s->length;
8331 * mono_array_length:
8332 * @array: a MonoArray*
8334 * Returns the total number of elements in the array. This works for
8335 * both vectors and multidimensional arrays.
8337 uintptr_t
8338 mono_array_length (MonoArray *array)
8340 MONO_REQ_GC_UNSAFE_MODE;
8342 return array->max_length;
8346 * mono_array_addr_with_size:
8347 * @array: a MonoArray*
8348 * @size: size of the array elements
8349 * @idx: index into the array
8351 * Use this function to obtain the address for the @idx item on the
8352 * @array containing elements of size @size.
8354 * This method performs no bounds checking or type checking.
8356 * Returns the address of the @idx element in the array.
8358 char*
8359 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8361 MONO_REQ_GC_UNSAFE_MODE;
8363 return ((char*)(array)->vector) + size * idx;
8367 MonoArray *
8368 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8370 MonoDomain *domain = mono_domain_get ();
8371 MonoArray *res;
8372 int len, i;
8374 mono_error_init (error);
8375 if (!list)
8376 return NULL;
8378 len = g_list_length (list);
8379 res = mono_array_new_checked (domain, eclass, len, error);
8380 return_val_if_nok (error, NULL);
8382 for (i = 0; list; list = list->next, i++)
8383 mono_array_set (res, gpointer, i, list->data);
8385 return res;
8388 #if NEVER_DEFINED
8390 * The following section is purely to declare prototypes and
8391 * document the API, as these C files are processed by our
8392 * tool
8396 * mono_array_set:
8397 * @array: array to alter
8398 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8399 * @index: index into the array
8400 * @value: value to set
8402 * Value Type version: This sets the @index's element of the @array
8403 * with elements of size sizeof(type) to the provided @value.
8405 * This macro does not attempt to perform type checking or bounds checking.
8407 * Use this to set value types in a `MonoArray`.
8409 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8414 * mono_array_setref:
8415 * @array: array to alter
8416 * @index: index into the array
8417 * @value: value to set
8419 * Reference Type version: This sets the @index's element of the
8420 * @array with elements of size sizeof(type) to the provided @value.
8422 * This macro does not attempt to perform type checking or bounds checking.
8424 * Use this to reference types in a `MonoArray`.
8426 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8431 * mono_array_get:
8432 * @array: array on which to operate on
8433 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8434 * @index: index into the array
8436 * Use this macro to retrieve the @index element of an @array and
8437 * extract the value assuming that the elements of the array match
8438 * the provided type value.
8440 * This method can be used with both arrays holding value types and
8441 * reference types. For reference types, the @type parameter should
8442 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8444 * This macro does not attempt to perform type checking or bounds checking.
8446 * Returns: The element at the @index position in the @array.
8448 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8451 #endif