mono_class_enum_basetype to mono_class_enum_basetype_internal to skip GC mode machine...
[mono-project.git] / mono / metadata / object.c
blob24e4d0177b1f53ac2af155e74788e5456439a288
1 /**
2 * \file
3 * Object creation for the Mono runtime
5 * Author:
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <config.h>
15 #ifdef HAVE_ALLOCA_H
16 #include <alloca.h>
17 #endif
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include "mono/metadata/class-init.h"
33 #include <mono/metadata/assembly.h>
34 #include <mono/metadata/marshal.h>
35 #include "mono/metadata/debug-helpers.h"
36 #include <mono/metadata/threads.h>
37 #include <mono/metadata/threads-types.h>
38 #include <mono/metadata/environment.h>
39 #include "mono/metadata/profiler-private.h"
40 #include "mono/metadata/security-manager.h"
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/reflection-internals.h>
43 #include <mono/metadata/w32event.h>
44 #include <mono/metadata/custom-attrs-internals.h>
45 #include <mono/metadata/abi-details.h>
46 #include <mono/utils/strenc.h>
47 #include <mono/utils/mono-counters.h>
48 #include <mono/utils/mono-error-internals.h>
49 #include <mono/utils/mono-memory-model.h>
50 #include <mono/utils/checked-build.h>
51 #include <mono/utils/mono-threads.h>
52 #include <mono/utils/mono-threads-coop.h>
53 #include <mono/utils/mono-logger-internals.h>
54 #include "cominterop.h"
55 #include <mono/utils/w32api.h>
56 #include <mono/utils/unlocked.h>
58 static void
59 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
61 static MonoString*
62 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
64 static void
65 free_main_args (void);
67 static char *
68 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error);
70 static char *
71 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error);
73 static void
74 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
76 /* Class lazy loading functions */
77 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
78 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
79 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
80 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
81 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
83 static GENERATE_GET_CLASS_WITH_CACHE (asyncresult, "System.Runtime.Remoting.Messaging", "AsyncResult");
85 #define ldstr_lock() mono_coop_mutex_lock (&ldstr_section)
86 #define ldstr_unlock() mono_coop_mutex_unlock (&ldstr_section)
87 static MonoCoopMutex ldstr_section;
90 /**
91 * mono_runtime_object_init:
92 * \param this_obj the object to initialize
93 * This function calls the zero-argument constructor (which must
94 * exist) for the given object.
96 void
97 mono_runtime_object_init (MonoObject *this_obj)
99 ERROR_DECL (error);
100 mono_runtime_object_init_checked (this_obj, error);
101 mono_error_assert_ok (error);
105 * mono_runtime_object_init_checked:
106 * \param this_obj the object to initialize
107 * \param error set on error.
108 * This function calls the zero-argument constructor (which must
109 * exist) for the given object and returns TRUE on success, or FALSE
110 * on error and sets \p error.
112 gboolean
113 mono_runtime_object_init_handle (MonoObjectHandle this_obj, MonoError *error)
115 MONO_REQ_GC_UNSAFE_MODE;
117 error_init (error);
119 MonoClass * const klass = MONO_HANDLE_GETVAL (this_obj, vtable)->klass;
120 MonoMethod * const method = mono_class_get_method_from_name_checked (klass, ".ctor", 0, 0, error);
121 mono_error_assert_msg_ok (error, "Could not lookup zero argument constructor");
122 g_assertf (method, "Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
124 if (m_class_is_valuetype (method->klass)) {
125 guint gchandle = 0;
126 gpointer raw = mono_object_handle_pin_unbox (this_obj, &gchandle);
127 mono_runtime_invoke_checked (method, raw, NULL, error);
128 mono_gchandle_free (gchandle);
129 } else {
130 mono_runtime_invoke_handle (method, this_obj, NULL, error);
133 return is_ok (error);
137 * mono_runtime_object_init_checked:
138 * \param this_obj the object to initialize
139 * \param error set on error.
140 * This function calls the zero-argument constructor (which must
141 * exist) for the given object and returns TRUE on success, or FALSE
142 * on error and sets \p error.
144 gboolean
145 mono_runtime_object_init_checked (MonoObject *this_obj_raw, MonoError *error)
147 HANDLE_FUNCTION_ENTER ();
148 MONO_HANDLE_DCL (MonoObject, this_obj);
149 HANDLE_FUNCTION_RETURN_VAL (mono_runtime_object_init_handle (this_obj, error));
152 /* The pseudo algorithm for type initialization from the spec
153 Note it doesn't say anything about domains - only threads.
155 2. If the type is initialized you are done.
156 2.1. If the type is not yet initialized, try to take an
157 initialization lock.
158 2.2. If successful, record this thread as responsible for
159 initializing the type and proceed to step 2.3.
160 2.2.1. If not, see whether this thread or any thread
161 waiting for this thread to complete already holds the lock.
162 2.2.2. If so, return since blocking would create a deadlock. This thread
163 will now see an incompletely initialized state for the type,
164 but no deadlock will arise.
165 2.2.3 If not, block until the type is initialized then return.
166 2.3 Initialize the parent type and then all interfaces implemented
167 by this type.
168 2.4 Execute the type initialization code for this type.
169 2.5 Mark the type as initialized, release the initialization lock,
170 awaken any threads waiting for this type to be initialized,
171 and return.
175 typedef struct
177 MonoNativeThreadId initializing_tid;
178 guint32 waiting_count;
179 gboolean done;
180 MonoCoopMutex mutex;
181 /* condvar used to wait for 'done' becoming TRUE */
182 MonoCoopCond cond;
183 } TypeInitializationLock;
185 /* for locking access to type_initialization_hash and blocked_thread_hash */
186 static MonoCoopMutex type_initialization_section;
188 static inline void
189 mono_type_initialization_lock (void)
191 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
192 mono_coop_mutex_lock (&type_initialization_section);
195 static inline void
196 mono_type_initialization_unlock (void)
198 mono_coop_mutex_unlock (&type_initialization_section);
201 static void
202 mono_type_init_lock (TypeInitializationLock *lock)
204 MONO_REQ_GC_NEUTRAL_MODE;
206 mono_coop_mutex_lock (&lock->mutex);
209 static void
210 mono_type_init_unlock (TypeInitializationLock *lock)
212 mono_coop_mutex_unlock (&lock->mutex);
215 /* from vtable to lock */
216 static GHashTable *type_initialization_hash;
218 /* from thread id to thread id being waited on */
219 static GHashTable *blocked_thread_hash;
221 /* Main thread */
222 static MonoThread *main_thread;
224 /* Functions supplied by the runtime */
225 static MonoRuntimeCallbacks callbacks;
228 * mono_thread_set_main:
229 * \param thread thread to set as the main thread
230 * This function can be used to instruct the runtime to treat \p thread
231 * as the main thread, ie, the thread that would normally execute the \c Main
232 * method. This basically means that at the end of \p thread, the runtime will
233 * wait for the existing foreground threads to quit and other such details.
235 void
236 mono_thread_set_main (MonoThread *thread)
238 MONO_REQ_GC_UNSAFE_MODE;
240 static gboolean registered = FALSE;
242 if (!registered) {
243 void *key = thread->internal_thread ? (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread->internal_thread->tid) : NULL;
244 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, key, "Thread Main Object");
245 registered = TRUE;
248 main_thread = thread;
252 * mono_thread_get_main:
254 MonoThread*
255 mono_thread_get_main (void)
257 MONO_REQ_GC_UNSAFE_MODE;
259 return main_thread;
262 void
263 mono_type_initialization_init (void)
265 mono_coop_mutex_init_recursive (&type_initialization_section);
266 type_initialization_hash = g_hash_table_new (NULL, NULL);
267 blocked_thread_hash = g_hash_table_new (NULL, NULL);
268 mono_coop_mutex_init (&ldstr_section);
269 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
272 void
273 mono_type_initialization_cleanup (void)
275 #if 0
276 /* This is causing race conditions with
277 * mono_release_type_locks
279 mono_coop_mutex_destroy (&type_initialization_section);
280 g_hash_table_destroy (type_initialization_hash);
281 type_initialization_hash = NULL;
282 #endif
283 mono_coop_mutex_destroy (&ldstr_section);
284 g_hash_table_destroy (blocked_thread_hash);
285 blocked_thread_hash = NULL;
287 free_main_args ();
290 static MonoException*
291 mono_get_exception_type_initialization_checked (const gchar *type_name, MonoException* inner_raw, MonoError *error)
293 HANDLE_FUNCTION_ENTER ();
294 MONO_HANDLE_DCL (MonoException, inner);
295 HANDLE_FUNCTION_RETURN_OBJ (mono_get_exception_type_initialization_handle (type_name, inner, error));
299 * get_type_init_exception_for_vtable:
301 * Return the stored type initialization exception for VTABLE.
303 static MonoException*
304 get_type_init_exception_for_vtable (MonoVTable *vtable)
306 MONO_REQ_GC_UNSAFE_MODE;
308 ERROR_DECL (error);
309 MonoDomain *domain = vtable->domain;
310 MonoClass *klass = vtable->klass;
311 MonoException *ex;
312 gchar *full_name;
314 if (!vtable->init_failed)
315 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
318 * If the initializing thread was rudely aborted, the exception is not stored
319 * in the hash.
321 ex = NULL;
322 mono_domain_lock (domain);
323 if (domain->type_init_exception_hash)
324 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
325 mono_domain_unlock (domain);
327 if (!ex) {
328 const char *klass_name_space = m_class_get_name_space (klass);
329 const char *klass_name = m_class_get_name (klass);
330 if (klass_name_space && *klass_name_space)
331 full_name = g_strdup_printf ("%s.%s", klass_name_space, klass_name);
332 else
333 full_name = g_strdup (klass_name);
334 ex = mono_get_exception_type_initialization_checked (full_name, NULL, error);
335 g_free (full_name);
336 return_val_if_nok (error, NULL);
339 return ex;
343 * mono_runtime_class_init:
344 * \param vtable vtable that needs to be initialized
345 * This routine calls the class constructor for \p vtable.
347 void
348 mono_runtime_class_init (MonoVTable *vtable)
350 MONO_REQ_GC_UNSAFE_MODE;
351 ERROR_DECL (error);
353 mono_runtime_class_init_full (vtable, error);
354 mono_error_assert_ok (error);
358 * Returns TRUE if the lock was freed.
359 * LOCKING: Caller should hold type_initialization_lock.
361 static gboolean
362 unref_type_lock (TypeInitializationLock *lock)
364 --lock->waiting_count;
365 if (lock->waiting_count == 0) {
366 mono_coop_mutex_destroy (&lock->mutex);
367 mono_coop_cond_destroy (&lock->cond);
368 g_free (lock);
369 return TRUE;
370 } else {
371 return FALSE;
376 * mono_runtime_class_init_full:
377 * \param vtable that neeeds to be initialized
378 * \param error set on error
379 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
381 gboolean
382 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
384 MONO_REQ_GC_UNSAFE_MODE;
386 MonoMethod *method = NULL;
387 MonoClass *klass;
388 gchar *full_name;
389 MonoDomain *domain = vtable->domain;
390 TypeInitializationLock *lock;
391 MonoNativeThreadId tid;
392 int do_initialization = 0;
393 MonoDomain *last_domain = NULL;
394 gboolean pending_tae = FALSE;
396 error_init (error);
398 if (vtable->initialized)
399 return TRUE;
401 klass = vtable->klass;
403 MonoImage *klass_image = m_class_get_image (klass);
404 if (!klass_image->checked_module_cctor) {
405 mono_image_check_for_module_cctor (klass_image);
406 if (klass_image->has_module_cctor) {
407 MonoClass *module_klass;
408 MonoVTable *module_vtable;
410 module_klass = mono_class_get_checked (klass_image, MONO_TOKEN_TYPE_DEF | 1, error);
411 if (!module_klass) {
412 return FALSE;
415 module_vtable = mono_class_vtable_checked (vtable->domain, module_klass, error);
416 if (!module_vtable)
417 return FALSE;
418 if (!mono_runtime_class_init_full (module_vtable, error))
419 return FALSE;
422 method = mono_class_get_cctor (klass);
423 if (!method) {
424 vtable->initialized = 1;
425 return TRUE;
428 tid = mono_native_thread_id_get ();
431 * Due some preprocessing inside a global lock. If we are the first thread
432 * trying to initialize this class, create a separate lock+cond var, and
433 * acquire it before leaving the global lock. The other threads will wait
434 * on this cond var.
437 mono_type_initialization_lock ();
438 /* double check... */
439 if (vtable->initialized) {
440 mono_type_initialization_unlock ();
441 return TRUE;
443 if (vtable->init_failed) {
444 mono_type_initialization_unlock ();
446 /* The type initialization already failed once, rethrow the same exception */
447 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
448 return FALSE;
450 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
451 if (lock == NULL) {
452 /* This thread will get to do the initialization */
453 if (mono_domain_get () != domain) {
454 /* Transfer into the target domain */
455 last_domain = mono_domain_get ();
456 if (!mono_domain_set (domain, FALSE)) {
457 vtable->initialized = 1;
458 mono_type_initialization_unlock ();
459 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
460 return FALSE;
463 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
464 mono_coop_mutex_init_recursive (&lock->mutex);
465 mono_coop_cond_init (&lock->cond);
466 lock->initializing_tid = tid;
467 lock->waiting_count = 1;
468 lock->done = FALSE;
469 g_hash_table_insert (type_initialization_hash, vtable, lock);
470 do_initialization = 1;
471 } else {
472 gpointer blocked;
473 TypeInitializationLock *pending_lock;
475 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
476 mono_type_initialization_unlock ();
477 return TRUE;
479 /* see if the thread doing the initialization is already blocked on this thread */
480 gboolean is_blocked = TRUE;
481 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
482 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
483 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
484 if (!pending_lock->done) {
485 mono_type_initialization_unlock ();
486 return TRUE;
487 } else {
488 /* the thread doing the initialization is blocked on this thread,
489 but on a lock that has already been freed. It just hasn't got
490 time to awake */
491 is_blocked = FALSE;
492 break;
495 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
497 ++lock->waiting_count;
498 /* record the fact that we are waiting on the initializing thread */
499 if (is_blocked)
500 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
502 mono_type_initialization_unlock ();
504 if (do_initialization) {
505 MonoException *exc = NULL;
507 /* We are holding the per-vtable lock, do the actual initialization */
509 mono_threads_begin_abort_protected_block ();
510 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
511 mono_threads_end_abort_protected_block ();
513 //exception extracted, error will be set to the right value later
514 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
515 exc = mono_error_convert_to_exception (error);
516 else
517 mono_error_cleanup (error);
519 error_init (error);
521 const char *klass_name_space = m_class_get_name_space (klass);
522 const char *klass_name = m_class_get_name (klass);
523 /* If the initialization failed, mark the class as unusable. */
524 /* Avoid infinite loops */
525 if (!(!exc ||
526 (klass_image == mono_defaults.corlib &&
527 !strcmp (klass_name_space, "System") &&
528 !strcmp (klass_name, "TypeInitializationException")))) {
529 vtable->init_failed = 1;
531 if (klass_name_space && *klass_name_space)
532 full_name = g_strdup_printf ("%s.%s", klass_name_space, klass_name);
533 else
534 full_name = g_strdup (klass_name);
536 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
537 g_free (full_name);
539 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
542 * Store the exception object so it could be thrown on subsequent
543 * accesses.
545 mono_domain_lock (domain);
546 if (!domain->type_init_exception_hash)
547 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Type Initialization Exception Table");
548 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
549 mono_domain_unlock (domain);
552 if (last_domain)
553 mono_domain_set (last_domain, TRUE);
555 /* Signal to the other threads that we are done */
556 mono_type_init_lock (lock);
557 lock->done = TRUE;
558 mono_coop_cond_broadcast (&lock->cond);
559 mono_type_init_unlock (lock);
562 * This can happen if the cctor self-aborts. We need to reactivate tae
563 * (next interruption checkpoint will throw it) and make sure we won't
564 * throw tie for the type.
566 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
567 pending_tae = TRUE;
568 mono_thread_resume_interruption (FALSE);
570 } else {
571 /* this just blocks until the initializing thread is done */
572 mono_type_init_lock (lock);
573 while (!lock->done)
574 mono_coop_cond_wait (&lock->cond, &lock->mutex);
575 mono_type_init_unlock (lock);
578 /* Do cleanup and setting vtable->initialized inside the global lock again */
579 mono_type_initialization_lock ();
580 if (!do_initialization)
581 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
582 gboolean deleted = unref_type_lock (lock);
583 if (deleted)
584 g_hash_table_remove (type_initialization_hash, vtable);
585 /* Have to set this here since we check it inside the global lock */
586 if (do_initialization && !vtable->init_failed)
587 vtable->initialized = 1;
588 mono_type_initialization_unlock ();
590 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
591 if (vtable->init_failed && !pending_tae) {
592 /* Either we were the initializing thread or we waited for the initialization */
593 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
594 return FALSE;
596 return TRUE;
599 MonoDomain *
600 mono_vtable_domain (MonoVTable *vtable)
602 return vtable->domain;
605 MonoClass *
606 mono_vtable_class (MonoVTable *vtable)
608 return vtable->klass;
611 static
612 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
614 MONO_REQ_GC_NEUTRAL_MODE;
616 MonoVTable *vtable = (MonoVTable*)key;
618 TypeInitializationLock *lock = (TypeInitializationLock*) value;
619 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
620 lock->done = TRUE;
622 * Have to set this since it cannot be set by the normal code in
623 * mono_runtime_class_init (). In this case, the exception object is not stored,
624 * and get_type_init_exception_for_class () needs to be aware of this.
626 mono_type_init_lock (lock);
627 vtable->init_failed = 1;
628 mono_coop_cond_broadcast (&lock->cond);
629 mono_type_init_unlock (lock);
630 gboolean deleted = unref_type_lock (lock);
631 if (deleted)
632 return TRUE;
634 return FALSE;
637 void
638 mono_release_type_locks (MonoInternalThread *thread)
640 MONO_REQ_GC_UNSAFE_MODE;
642 mono_type_initialization_lock ();
643 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
644 mono_type_initialization_unlock ();
647 #ifndef DISABLE_REMOTING
649 static gpointer
650 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
652 if (!callbacks.create_remoting_trampoline)
653 g_error ("remoting not installed");
654 return callbacks.create_remoting_trampoline (domain, method, target, error);
657 #endif
659 static MonoImtTrampolineBuilder imt_trampoline_builder;
660 static gboolean always_build_imt_trampolines;
662 #if (MONO_IMT_SIZE > 32)
663 #error "MONO_IMT_SIZE cannot be larger than 32"
664 #endif
666 void
667 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
669 memcpy (&callbacks, cbs, sizeof (*cbs));
672 MonoRuntimeCallbacks*
673 mono_get_runtime_callbacks (void)
675 return &callbacks;
678 void
679 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
681 imt_trampoline_builder = func;
684 void
685 mono_set_always_build_imt_trampolines (gboolean value)
687 always_build_imt_trampolines = value;
691 * mono_compile_method:
692 * \param method The method to compile.
693 * This JIT-compiles the method, and returns the pointer to the native code
694 * produced.
696 gpointer
697 mono_compile_method (MonoMethod *method)
699 ERROR_DECL (error);
700 gpointer result = mono_compile_method_checked (method, error);
701 mono_error_cleanup (error);
702 return result;
706 * mono_compile_method_checked:
707 * \param method The method to compile.
708 * \param error set on error.
709 * This JIT-compiles the method, and returns the pointer to the native code
710 * produced. On failure returns NULL and sets \p error.
712 gpointer
713 mono_compile_method_checked (MonoMethod *method, MonoError *error)
715 gpointer res;
717 MONO_REQ_GC_NEUTRAL_MODE
719 error_init (error);
721 g_assert (callbacks.compile_method);
722 res = callbacks.compile_method (method, error);
723 return res;
726 gpointer
727 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
729 gpointer res;
731 MONO_REQ_GC_NEUTRAL_MODE;
733 error_init (error);
734 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
735 return res;
738 gpointer
739 mono_runtime_create_delegate_trampoline (MonoClass *klass)
741 MONO_REQ_GC_NEUTRAL_MODE
743 g_assert (callbacks.create_delegate_trampoline);
744 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
748 * mono_runtime_free_method:
749 * \param domain domain where the method is hosted
750 * \param method method to release
751 * This routine is invoked to free the resources associated with
752 * a method that has been JIT compiled. This is used to discard
753 * methods that were used only temporarily (for example, used in marshalling)
755 void
756 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
758 MONO_REQ_GC_NEUTRAL_MODE
760 if (callbacks.free_method)
761 callbacks.free_method (domain, method);
763 mono_method_clear_object (domain, method);
765 mono_free_method (method);
769 * The vtables in the root appdomain are assumed to be reachable by other
770 * roots, and we don't use typed allocation in the other domains.
773 /* The sync block is no longer a GC pointer */
774 #define GC_HEADER_BITMAP (0)
776 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
778 #define MONO_OBJECT_HEADER_BITS (MONO_ABI_SIZEOF (MonoObject) / MONO_ABI_SIZEOF (gpointer))
780 static gsize*
781 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
783 MONO_REQ_GC_NEUTRAL_MODE;
785 MonoClassField *field;
786 MonoClass *p;
787 guint32 pos;
788 int max_size, wordsize;
790 wordsize = TARGET_SIZEOF_VOID_P;
792 if (static_fields)
793 max_size = mono_class_data_size (klass) / wordsize;
794 else
795 max_size = m_class_get_instance_size (klass) / wordsize;
796 if (max_size > size) {
797 g_assert (offset <= 0);
798 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
799 size = max_size;
802 /* An Ephemeron cannot be marked by sgen */
803 if (mono_gc_is_moving () && !static_fields && m_class_get_image (klass) == mono_defaults.corlib && !strcmp ("Ephemeron", m_class_get_name (klass))) {
804 *max_set = 0;
805 memset (bitmap, 0, size / 8);
806 return bitmap;
809 for (p = klass; p != NULL; p = m_class_get_parent (p)) {
810 gpointer iter = NULL;
811 while ((field = mono_class_get_fields_internal (p, &iter))) {
812 MonoType *type;
814 if (static_fields) {
815 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
816 continue;
817 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
818 continue;
819 } else {
820 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
821 continue;
823 /* FIXME: should not happen, flag as type load error */
824 if (field->type->byref)
825 break;
827 if (static_fields && field->offset == -1)
828 /* special static */
829 continue;
831 pos = field->offset / TARGET_SIZEOF_VOID_P;
832 pos += offset;
834 type = mono_type_get_underlying_type (field->type);
835 switch (type->type) {
836 case MONO_TYPE_U:
837 case MONO_TYPE_I:
838 case MONO_TYPE_PTR:
839 case MONO_TYPE_FNPTR:
840 break;
841 case MONO_TYPE_STRING:
842 case MONO_TYPE_SZARRAY:
843 case MONO_TYPE_CLASS:
844 case MONO_TYPE_OBJECT:
845 case MONO_TYPE_ARRAY:
846 g_assert ((field->offset % wordsize) == 0);
848 g_assert (pos < size || pos <= max_size);
849 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
850 *max_set = MAX (*max_set, pos);
851 break;
852 case MONO_TYPE_GENERICINST:
853 if (!mono_type_generic_inst_is_valuetype (type)) {
854 g_assert ((field->offset % wordsize) == 0);
856 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
857 *max_set = MAX (*max_set, pos);
858 break;
859 } else {
860 /* fall through */
862 case MONO_TYPE_VALUETYPE: {
863 MonoClass *fclass = mono_class_from_mono_type (field->type);
864 if (m_class_has_references (fclass)) {
865 /* remove the object header */
866 compute_class_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS, max_set, FALSE);
868 break;
870 case MONO_TYPE_I1:
871 case MONO_TYPE_U1:
872 case MONO_TYPE_I2:
873 case MONO_TYPE_U2:
874 case MONO_TYPE_I4:
875 case MONO_TYPE_U4:
876 case MONO_TYPE_I8:
877 case MONO_TYPE_U8:
878 case MONO_TYPE_R4:
879 case MONO_TYPE_R8:
880 case MONO_TYPE_BOOLEAN:
881 case MONO_TYPE_CHAR:
882 break;
883 default:
884 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
885 break;
888 if (static_fields)
889 break;
891 return bitmap;
895 * mono_class_compute_bitmap:
897 * Mono internal function to compute a bitmap of reference fields in a class.
899 gsize*
900 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
902 MONO_REQ_GC_NEUTRAL_MODE;
904 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
907 #if 0
909 * similar to the above, but sets the bits in the bitmap for any non-ref field
910 * and ignores static fields
912 static gsize*
913 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
915 MonoClassField *field;
916 MonoClass *p;
917 guint32 pos, pos2;
918 int max_size, wordsize;
920 wordsize = TARGET_SIZEOF_VOID_P;
922 max_size = class->instance_size / wordsize;
923 if (max_size >= size)
924 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
926 for (p = class; p != NULL; p = p->parent) {
927 gpointer iter = NULL;
928 while ((field = mono_class_get_fields_internal (p, &iter))) {
929 MonoType *type;
931 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
932 continue;
933 /* FIXME: should not happen, flag as type load error */
934 if (field->type->byref)
935 break;
937 pos = field->offset / wordsize;
938 pos += offset;
940 type = mono_type_get_underlying_type (field->type);
941 switch (type->type) {
942 #if SIZEOF_VOID_P == 8
943 case MONO_TYPE_I:
944 case MONO_TYPE_U:
945 case MONO_TYPE_PTR:
946 case MONO_TYPE_FNPTR:
947 #endif
948 case MONO_TYPE_I8:
949 case MONO_TYPE_U8:
950 case MONO_TYPE_R8:
951 if ((((field->offset + 7) / wordsize) + offset) != pos) {
952 pos2 = ((field->offset + 7) / wordsize) + offset;
953 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
955 /* fall through */
956 #if SIZEOF_VOID_P == 4
957 case MONO_TYPE_I:
958 case MONO_TYPE_U:
959 case MONO_TYPE_PTR:
960 case MONO_TYPE_FNPTR:
961 #endif
962 case MONO_TYPE_I4:
963 case MONO_TYPE_U4:
964 case MONO_TYPE_R4:
965 if ((((field->offset + 3) / wordsize) + offset) != pos) {
966 pos2 = ((field->offset + 3) / wordsize) + offset;
967 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
969 /* fall through */
970 case MONO_TYPE_CHAR:
971 case MONO_TYPE_I2:
972 case MONO_TYPE_U2:
973 if ((((field->offset + 1) / wordsize) + offset) != pos) {
974 pos2 = ((field->offset + 1) / wordsize) + offset;
975 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
977 /* fall through */
978 case MONO_TYPE_BOOLEAN:
979 case MONO_TYPE_I1:
980 case MONO_TYPE_U1:
981 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
982 break;
983 case MONO_TYPE_STRING:
984 case MONO_TYPE_SZARRAY:
985 case MONO_TYPE_CLASS:
986 case MONO_TYPE_OBJECT:
987 case MONO_TYPE_ARRAY:
988 break;
989 case MONO_TYPE_GENERICINST:
990 if (!mono_type_generic_inst_is_valuetype (type)) {
991 break;
992 } else {
993 /* fall through */
995 case MONO_TYPE_VALUETYPE: {
996 MonoClass *fclass = mono_class_from_mono_type (field->type);
997 /* remove the object header */
998 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS);
999 break;
1001 default:
1002 g_assert_not_reached ();
1003 break;
1007 return bitmap;
1011 * mono_class_insecure_overlapping:
1012 * check if a class with explicit layout has references and non-references
1013 * fields overlapping.
1015 * Returns: TRUE if it is insecure to load the type.
1017 gboolean
1018 mono_class_insecure_overlapping (MonoClass *klass)
1020 int max_set = 0;
1021 gsize *bitmap;
1022 gsize default_bitmap [4] = {0};
1023 gsize *nrbitmap;
1024 gsize default_nrbitmap [4] = {0};
1025 int i, insecure = FALSE;
1026 return FALSE;
1028 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1029 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
1031 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
1032 int idx = i % (sizeof (bitmap [0]) * 8);
1033 if (bitmap [idx] & nrbitmap [idx]) {
1034 insecure = TRUE;
1035 break;
1038 if (bitmap != default_bitmap)
1039 g_free (bitmap);
1040 if (nrbitmap != default_nrbitmap)
1041 g_free (nrbitmap);
1042 if (insecure) {
1043 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1044 return FALSE;
1046 return insecure;
1048 #endif
1050 MonoString*
1051 ves_icall_string_alloc (int length)
1053 ERROR_DECL (error);
1054 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, error);
1055 mono_error_set_pending_exception (error);
1057 return str;
1060 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
1062 /* LOCKING: Acquires the loader lock */
1064 * Sets the following fields in KLASS:
1065 * - gc_desc
1066 * - gc_descr_inited
1068 void
1069 mono_class_compute_gc_descriptor (MonoClass *klass)
1071 MONO_REQ_GC_NEUTRAL_MODE;
1073 int max_set = 0;
1074 gsize *bitmap;
1075 gsize default_bitmap [4] = {0};
1076 MonoGCDescriptor gc_descr;
1078 if (!m_class_is_inited (klass))
1079 mono_class_init (klass);
1081 if (m_class_is_gc_descr_inited (klass))
1082 return;
1084 bitmap = default_bitmap;
1085 if (klass == mono_defaults.string_class) {
1086 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1087 } else if (m_class_get_rank (klass)) {
1088 MonoClass *klass_element_class = m_class_get_element_class (klass);
1089 mono_class_compute_gc_descriptor (klass_element_class);
1090 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass_element_class))) {
1091 gsize abm = 1;
1092 gc_descr = mono_gc_make_descr_for_array (m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1093 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1094 class->name_space, class->name);*/
1095 } else {
1096 /* remove the object header */
1097 bitmap = mono_class_compute_bitmap (klass_element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(MONO_OBJECT_HEADER_BITS), &max_set, FALSE);
1098 gc_descr = mono_gc_make_descr_for_array (m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1099 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1100 class->name_space, class->name);*/
1102 } else {
1103 /*static int count = 0;
1104 if (count++ > 58)
1105 return;*/
1106 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1108 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1109 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1111 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1113 if (m_class_has_weak_fields (klass)) {
1114 gsize *weak_bitmap = NULL;
1115 int weak_bitmap_nbits = 0;
1117 weak_bitmap = (gsize *)mono_class_alloc0 (klass, m_class_get_instance_size (klass) / sizeof (gsize));
1118 if (mono_class_has_static_metadata (klass)) {
1119 for (MonoClass *p = klass; p != NULL; p = m_class_get_parent (p)) {
1120 gpointer iter = NULL;
1121 guint32 first_field_idx = mono_class_get_first_field_idx (p);
1122 MonoClassField *field;
1124 MonoClassField *p_fields = m_class_get_fields (p);
1125 MonoImage *p_image = m_class_get_image (p);
1126 while ((field = mono_class_get_fields_internal (p, &iter))) {
1127 guint32 field_idx = first_field_idx + (field - p_fields);
1128 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p_image, field_idx + 1)) {
1129 int pos = field->offset / sizeof (gpointer);
1130 if (pos + 1 > weak_bitmap_nbits)
1131 weak_bitmap_nbits = pos + 1;
1132 weak_bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
1138 for (int pos = 0; pos < weak_bitmap_nbits; ++pos) {
1139 if (weak_bitmap [pos / BITMAP_EL_SIZE] & ((gsize)1) << (pos % BITMAP_EL_SIZE)) {
1140 /* Clear the normal bitmap so these refs don't keep an object alive */
1141 bitmap [pos / BITMAP_EL_SIZE] &= ~(((gsize)1) << (pos % BITMAP_EL_SIZE));
1145 mono_loader_lock ();
1146 mono_class_set_weak_bitmap (klass, weak_bitmap_nbits, weak_bitmap);
1147 mono_loader_unlock ();
1150 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, m_class_get_instance_size (klass));
1153 if (bitmap != default_bitmap)
1154 g_free (bitmap);
1156 /* Publish the data */
1157 mono_class_publish_gc_descriptor (klass, gc_descr);
1161 * field_is_special_static:
1162 * @fklass: The MonoClass to look up.
1163 * @field: The MonoClassField describing the field.
1165 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1166 * SPECIAL_STATIC_NONE otherwise.
1168 static gint32
1169 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1171 MONO_REQ_GC_NEUTRAL_MODE;
1173 ERROR_DECL (error);
1174 MonoCustomAttrInfo *ainfo;
1175 int i;
1176 ainfo = mono_custom_attrs_from_field_checked (fklass, field, error);
1177 mono_error_cleanup (error); /* FIXME don't swallow the error? */
1178 if (!ainfo)
1179 return FALSE;
1180 for (i = 0; i < ainfo->num_attrs; ++i) {
1181 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1182 if (m_class_get_image (klass) == mono_defaults.corlib) {
1183 const char *klass_name = m_class_get_name (klass);
1184 if (strcmp (klass_name, "ThreadStaticAttribute") == 0) {
1185 mono_custom_attrs_free (ainfo);
1186 return SPECIAL_STATIC_THREAD;
1188 else if (strcmp (klass_name, "ContextStaticAttribute") == 0) {
1189 mono_custom_attrs_free (ainfo);
1190 return SPECIAL_STATIC_CONTEXT;
1194 mono_custom_attrs_free (ainfo);
1195 return SPECIAL_STATIC_NONE;
1198 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1199 #define mix(a,b,c) { \
1200 a -= c; a ^= rot(c, 4); c += b; \
1201 b -= a; b ^= rot(a, 6); a += c; \
1202 c -= b; c ^= rot(b, 8); b += a; \
1203 a -= c; a ^= rot(c,16); c += b; \
1204 b -= a; b ^= rot(a,19); a += c; \
1205 c -= b; c ^= rot(b, 4); b += a; \
1207 #define mono_final(a,b,c) { \
1208 c ^= b; c -= rot(b,14); \
1209 a ^= c; a -= rot(c,11); \
1210 b ^= a; b -= rot(a,25); \
1211 c ^= b; c -= rot(b,16); \
1212 a ^= c; a -= rot(c,4); \
1213 b ^= a; b -= rot(a,14); \
1214 c ^= b; c -= rot(b,24); \
1218 * mono_method_get_imt_slot:
1220 * The IMT slot is embedded into AOTed code, so this must return the same value
1221 * for the same method across all executions. This means:
1222 * - pointers shouldn't be used as hash values.
1223 * - mono_metadata_str_hash () should be used for hashing strings.
1225 guint32
1226 mono_method_get_imt_slot (MonoMethod *method)
1228 MONO_REQ_GC_NEUTRAL_MODE;
1230 MonoMethodSignature *sig;
1231 int hashes_count;
1232 guint32 *hashes_start, *hashes;
1233 guint32 a, b, c;
1234 int i;
1236 /* This can be used to stress tests the collision code */
1237 //return 0;
1240 * We do this to simplify generic sharing. It will hurt
1241 * performance in cases where a class implements two different
1242 * instantiations of the same generic interface.
1243 * The code in build_imt_slots () depends on this.
1245 if (method->is_inflated)
1246 method = ((MonoMethodInflated*)method)->declaring;
1248 sig = mono_method_signature (method);
1249 hashes_count = sig->param_count + 4;
1250 hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1251 hashes = hashes_start;
1253 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1254 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1255 m_class_get_name_space (method->klass), m_class_get_name (method->klass), method->name);
1258 /* Initialize hashes */
1259 hashes [0] = mono_metadata_str_hash (m_class_get_name (method->klass));
1260 hashes [1] = mono_metadata_str_hash (m_class_get_name_space (method->klass));
1261 hashes [2] = mono_metadata_str_hash (method->name);
1262 hashes [3] = mono_metadata_type_hash (sig->ret);
1263 for (i = 0; i < sig->param_count; i++) {
1264 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1267 /* Setup internal state */
1268 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1270 /* Handle most of the hashes */
1271 while (hashes_count > 3) {
1272 a += hashes [0];
1273 b += hashes [1];
1274 c += hashes [2];
1275 mix (a,b,c);
1276 hashes_count -= 3;
1277 hashes += 3;
1280 /* Handle the last 3 hashes (all the case statements fall through) */
1281 switch (hashes_count) {
1282 case 3 : c += hashes [2];
1283 case 2 : b += hashes [1];
1284 case 1 : a += hashes [0];
1285 mono_final (a,b,c);
1286 case 0: /* nothing left to add */
1287 break;
1290 g_free (hashes_start);
1291 /* Report the result */
1292 return c % MONO_IMT_SIZE;
1294 #undef rot
1295 #undef mix
1296 #undef mono_final
1298 #define DEBUG_IMT 0
1300 static void
1301 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1302 MONO_REQ_GC_NEUTRAL_MODE;
1304 guint32 imt_slot = mono_method_get_imt_slot (method);
1305 MonoImtBuilderEntry *entry;
1307 if (slot_num >= 0 && imt_slot != slot_num) {
1308 /* we build just a single imt slot and this is not it */
1309 return;
1312 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1313 entry->key = method;
1314 entry->value.vtable_slot = vtable_slot;
1315 entry->next = imt_builder [imt_slot];
1316 if (imt_builder [imt_slot] != NULL) {
1317 entry->children = imt_builder [imt_slot]->children + 1;
1318 if (entry->children == 1) {
1319 UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1320 *imt_collisions_bitmap |= (1 << imt_slot);
1322 } else {
1323 entry->children = 0;
1324 UnlockedIncrement (&mono_stats.imt_used_slots);
1326 imt_builder [imt_slot] = entry;
1327 #if DEBUG_IMT
1329 char *method_name = mono_method_full_name (method, TRUE);
1330 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1331 method, method_name, imt_slot, vtable_slot, entry->children);
1332 g_free (method_name);
1334 #endif
1337 #if DEBUG_IMT
1338 static void
1339 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1340 if (e != NULL) {
1341 MonoMethod *method = e->key;
1342 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1343 message,
1344 num,
1345 method,
1346 method->klass->name_space,
1347 method->klass->name,
1348 method->name);
1349 } else {
1350 printf (" * %s: NULL\n", message);
1353 #endif
1355 static int
1356 compare_imt_builder_entries (const void *p1, const void *p2) {
1357 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1358 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1360 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1363 static int
1364 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1366 MONO_REQ_GC_NEUTRAL_MODE;
1368 int count = end - start;
1369 int chunk_start = out_array->len;
1370 if (count < 4) {
1371 int i;
1372 for (i = start; i < end; ++i) {
1373 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1374 item->key = sorted_array [i]->key;
1375 item->value = sorted_array [i]->value;
1376 item->has_target_code = sorted_array [i]->has_target_code;
1377 item->is_equals = TRUE;
1378 if (i < end - 1)
1379 item->check_target_idx = out_array->len + 1;
1380 else
1381 item->check_target_idx = 0;
1382 g_ptr_array_add (out_array, item);
1384 } else {
1385 int middle = start + count / 2;
1386 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1388 item->key = sorted_array [middle]->key;
1389 item->is_equals = FALSE;
1390 g_ptr_array_add (out_array, item);
1391 imt_emit_ir (sorted_array, start, middle, out_array);
1392 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1394 return chunk_start;
1397 static GPtrArray*
1398 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1399 MONO_REQ_GC_NEUTRAL_MODE;
1401 int number_of_entries = entries->children + 1;
1402 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1403 GPtrArray *result = g_ptr_array_new ();
1404 MonoImtBuilderEntry *current_entry;
1405 int i;
1407 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1408 sorted_array [i] = current_entry;
1410 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1412 /*for (i = 0; i < number_of_entries; i++) {
1413 print_imt_entry (" sorted array:", sorted_array [i], i);
1416 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1418 g_free (sorted_array);
1419 return result;
1422 static gpointer
1423 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1425 MONO_REQ_GC_NEUTRAL_MODE;
1427 if (imt_builder_entry != NULL) {
1428 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1429 /* No collision, return the vtable slot contents */
1430 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1431 } else {
1432 /* Collision, build the trampoline */
1433 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1434 gpointer result;
1435 int i;
1436 result = imt_trampoline_builder (vtable, domain,
1437 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1438 for (i = 0; i < imt_ir->len; ++i)
1439 g_free (g_ptr_array_index (imt_ir, i));
1440 g_ptr_array_free (imt_ir, TRUE);
1441 return result;
1443 } else {
1444 if (fail_tramp)
1445 return fail_tramp;
1446 else
1447 /* Empty slot */
1448 return NULL;
1452 static MonoImtBuilderEntry*
1453 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1456 * LOCKING: requires the loader and domain locks.
1459 static void
1460 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1462 MONO_REQ_GC_NEUTRAL_MODE;
1464 int i;
1465 GSList *list_item;
1466 guint32 imt_collisions_bitmap = 0;
1467 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1468 int method_count = 0;
1469 gboolean record_method_count_for_max_collisions = FALSE;
1470 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1472 #if DEBUG_IMT
1473 printf ("Building IMT for class %s.%s slot %d\n", m_class_get_name_space (klass), m_class_get_name (klass), slot_num);
1474 #endif
1475 int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass);
1476 MonoClass **klass_interfaces_packed = m_class_get_interfaces_packed (klass);
1477 guint16 *klass_interface_offsets_packed = m_class_get_interface_offsets_packed (klass);
1478 for (i = 0; i < klass_interface_offsets_count; ++i) {
1479 MonoClass *iface = klass_interfaces_packed [i];
1480 int interface_offset = klass_interface_offsets_packed [i];
1481 int method_slot_in_interface, vt_slot;
1483 if (mono_class_has_variant_generic_params (iface))
1484 has_variant_iface = TRUE;
1486 mono_class_setup_methods (iface);
1487 vt_slot = interface_offset;
1488 int mcount = mono_class_get_method_count (iface);
1489 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1490 MonoMethod *method;
1492 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1494 * The imt slot of the method is the same as for its declaring method,
1495 * see the comment in mono_method_get_imt_slot (), so we can
1496 * avoid inflating methods which will be discarded by
1497 * add_imt_builder_entry anyway.
1499 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1500 if (mono_method_get_imt_slot (method) != slot_num) {
1501 vt_slot ++;
1502 continue;
1505 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1506 if (method->is_generic) {
1507 has_generic_virtual = TRUE;
1508 vt_slot ++;
1509 continue;
1512 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1513 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1514 vt_slot ++;
1518 if (extra_interfaces) {
1519 int interface_offset = m_class_get_vtable_size (klass);
1521 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1522 MonoClass* iface = (MonoClass *)list_item->data;
1523 int method_slot_in_interface;
1524 int mcount = mono_class_get_method_count (iface);
1525 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1526 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1528 if (method->is_generic)
1529 has_generic_virtual = TRUE;
1530 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1532 interface_offset += mcount;
1535 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1536 /* overwrite the imt slot only if we're building all the entries or if
1537 * we're building this specific one
1539 if (slot_num < 0 || i == slot_num) {
1540 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1542 if (entries) {
1543 if (imt_builder [i]) {
1544 MonoImtBuilderEntry *entry;
1546 /* Link entries with imt_builder [i] */
1547 for (entry = entries; entry->next; entry = entry->next) {
1548 #if DEBUG_IMT
1549 MonoMethod *method = (MonoMethod*)entry->key;
1550 char *method_name = mono_method_full_name (method, TRUE);
1551 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1552 g_free (method_name);
1553 #endif
1555 entry->next = imt_builder [i];
1556 entries->children += imt_builder [i]->children + 1;
1558 imt_builder [i] = entries;
1561 if (has_generic_virtual || has_variant_iface) {
1563 * There might be collisions later when the the trampoline is expanded.
1565 imt_collisions_bitmap |= (1 << i);
1568 * The IMT trampoline might be called with an instance of one of the
1569 * generic virtual methods, so has to fallback to the IMT trampoline.
1571 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1572 } else {
1573 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1575 #if DEBUG_IMT
1576 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1577 #endif
1580 if (imt_builder [i] != NULL) {
1581 int methods_in_slot = imt_builder [i]->children + 1;
1582 if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1583 UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1584 record_method_count_for_max_collisions = TRUE;
1586 method_count += methods_in_slot;
1590 UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1591 if (record_method_count_for_max_collisions) {
1592 UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1595 for (i = 0; i < MONO_IMT_SIZE; i++) {
1596 MonoImtBuilderEntry* entry = imt_builder [i];
1597 while (entry != NULL) {
1598 MonoImtBuilderEntry* next = entry->next;
1599 g_free (entry);
1600 entry = next;
1603 g_free (imt_builder);
1604 /* we OR the bitmap since we may build just a single imt slot at a time */
1605 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1608 static void
1609 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1610 MONO_REQ_GC_NEUTRAL_MODE;
1612 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1616 * mono_vtable_build_imt_slot:
1617 * \param vtable virtual object table struct
1618 * \param imt_slot slot in the IMT table
1619 * Fill the given \p imt_slot in the IMT table of \p vtable with
1620 * a trampoline or a trampoline for the case of collisions.
1621 * This is part of the internal mono API.
1622 * LOCKING: Take the domain lock.
1624 void
1625 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1627 MONO_REQ_GC_NEUTRAL_MODE;
1629 gpointer *imt = (gpointer*)vtable;
1630 imt -= MONO_IMT_SIZE;
1631 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1633 /* no support for extra interfaces: the proxy objects will need
1634 * to build the complete IMT
1635 * Update and heck needs to ahppen inside the proper domain lock, as all
1636 * the changes made to a MonoVTable.
1638 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1639 mono_domain_lock (vtable->domain);
1640 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1641 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1642 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1643 mono_domain_unlock (vtable->domain);
1644 mono_loader_unlock ();
1647 #define THUNK_THRESHOLD 10
1650 * mono_method_alloc_generic_virtual_trampoline:
1651 * \param domain a domain
1652 * \param size size in bytes
1653 * Allocs \p size bytes to be used for the code of a generic virtual
1654 * trampoline. It's either allocated from the domain's code manager or
1655 * reused from a previously invalidated piece.
1656 * LOCKING: The domain lock must be held.
1658 gpointer
1659 (mono_method_alloc_generic_virtual_trampoline) (MonoDomain *domain, int size)
1661 MONO_REQ_GC_NEUTRAL_MODE;
1663 static gboolean inited = FALSE;
1664 static int generic_virtual_trampolines_size = 0;
1666 if (!inited) {
1667 mono_counters_register ("Generic virtual trampoline bytes",
1668 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1669 inited = TRUE;
1671 generic_virtual_trampolines_size += size;
1673 return mono_domain_code_reserve (domain, size);
1676 typedef struct _GenericVirtualCase {
1677 MonoMethod *method;
1678 gpointer code;
1679 int count;
1680 struct _GenericVirtualCase *next;
1681 } GenericVirtualCase;
1684 * get_generic_virtual_entries:
1686 * Return IMT entries for the generic virtual method instances and
1687 * variant interface methods for vtable slot
1688 * VTABLE_SLOT.
1690 static MonoImtBuilderEntry*
1691 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1693 MONO_REQ_GC_NEUTRAL_MODE;
1695 GenericVirtualCase *list;
1696 MonoImtBuilderEntry *entries;
1698 mono_domain_lock (domain);
1699 if (!domain->generic_virtual_cases)
1700 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1702 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1704 entries = NULL;
1705 for (; list; list = list->next) {
1706 MonoImtBuilderEntry *entry;
1708 if (list->count < THUNK_THRESHOLD)
1709 continue;
1711 entry = g_new0 (MonoImtBuilderEntry, 1);
1712 entry->key = list->method;
1713 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1714 entry->has_target_code = 1;
1715 if (entries)
1716 entry->children = entries->children + 1;
1717 entry->next = entries;
1718 entries = entry;
1721 mono_domain_unlock (domain);
1723 /* FIXME: Leaking memory ? */
1724 return entries;
1728 * \param domain a domain
1729 * \param vtable_slot pointer to the vtable slot
1730 * \param method the inflated generic virtual method
1731 * \param code the method's code
1733 * Registers a call via unmanaged code to a generic virtual method
1734 * instantiation or variant interface method. If the number of calls reaches a threshold
1735 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1736 * virtual method trampoline.
1738 void
1739 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1740 gpointer *vtable_slot,
1741 MonoMethod *method, gpointer code)
1743 MONO_REQ_GC_NEUTRAL_MODE;
1745 static gboolean inited = FALSE;
1746 static int num_added = 0;
1747 static int num_freed = 0;
1749 GenericVirtualCase *gvc, *list;
1750 MonoImtBuilderEntry *entries;
1751 int i;
1752 GPtrArray *sorted;
1754 mono_domain_lock (domain);
1755 if (!domain->generic_virtual_cases)
1756 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1758 if (!inited) {
1759 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1760 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1761 inited = TRUE;
1764 /* Check whether the case was already added */
1765 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1766 gvc = list;
1767 while (gvc) {
1768 if (gvc->method == method)
1769 break;
1770 gvc = gvc->next;
1773 /* If not found, make a new one */
1774 if (!gvc) {
1775 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1776 gvc->method = method;
1777 gvc->code = code;
1778 gvc->count = 0;
1779 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1781 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1783 num_added++;
1786 if (++gvc->count == THUNK_THRESHOLD) {
1787 gpointer *old_thunk = (void **)*vtable_slot;
1788 gpointer vtable_trampoline = NULL;
1789 gpointer imt_trampoline = NULL;
1791 if ((gpointer)vtable_slot < (gpointer)vtable) {
1792 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1793 int imt_slot = MONO_IMT_SIZE + displacement;
1795 /* Force the rebuild of the trampoline at the next call */
1796 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1797 *vtable_slot = imt_trampoline;
1798 } else {
1799 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1801 entries = get_generic_virtual_entries (domain, vtable_slot);
1803 sorted = imt_sort_slot_entries (entries);
1805 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1806 vtable_trampoline);
1808 while (entries) {
1809 MonoImtBuilderEntry *next = entries->next;
1810 g_free (entries);
1811 entries = next;
1814 for (i = 0; i < sorted->len; ++i)
1815 g_free (g_ptr_array_index (sorted, i));
1816 g_ptr_array_free (sorted, TRUE);
1818 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1819 num_freed ++;
1823 mono_domain_unlock (domain);
1826 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1829 * mono_class_vtable:
1830 * \param domain the application domain
1831 * \param class the class to initialize
1832 * VTables are domain specific because we create domain specific code, and
1833 * they contain the domain specific static class data.
1834 * On failure, NULL is returned, and \c class->exception_type is set.
1836 MonoVTable *
1837 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1839 MonoVTable* vtable;
1840 MONO_ENTER_GC_UNSAFE;
1841 ERROR_DECL (error);
1842 vtable = mono_class_vtable_checked (domain, klass, error);
1843 mono_error_cleanup (error);
1844 MONO_EXIT_GC_UNSAFE;
1845 return vtable;
1849 * mono_class_vtable_checked:
1850 * \param domain the application domain
1851 * \param class the class to initialize
1852 * \param error set on failure.
1853 * VTables are domain specific because we create domain specific code, and
1854 * they contain the domain specific static class data.
1856 MonoVTable *
1857 mono_class_vtable_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
1859 MONO_REQ_GC_UNSAFE_MODE;
1861 MonoClassRuntimeInfo *runtime_info;
1863 error_init (error);
1865 g_assert (klass);
1867 if (mono_class_has_failure (klass)) {
1868 mono_error_set_for_class_failure (error, klass);
1869 return NULL;
1872 /* this check can be inlined in jitted code, too */
1873 runtime_info = m_class_get_runtime_info (klass);
1874 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1875 return runtime_info->domain_vtables [domain->domain_id];
1876 return mono_class_create_runtime_vtable (domain, klass, error);
1880 * mono_class_try_get_vtable:
1881 * \param domain the application domain
1882 * \param class the class to initialize
1883 * This function tries to get the associated vtable from \p class if
1884 * it was already created.
1886 MonoVTable *
1887 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1889 MONO_REQ_GC_NEUTRAL_MODE;
1891 MonoClassRuntimeInfo *runtime_info;
1893 g_assert (klass);
1895 runtime_info = m_class_get_runtime_info (klass);
1896 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1897 return runtime_info->domain_vtables [domain->domain_id];
1898 return NULL;
1901 static gpointer*
1902 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1904 MONO_REQ_GC_NEUTRAL_MODE;
1906 size_t alloc_offset;
1909 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1910 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1911 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1913 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1914 g_assert ((imt_table_bytes & 7) == 4);
1915 vtable_size += 4;
1916 alloc_offset = 4;
1917 } else {
1918 alloc_offset = 0;
1921 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1924 static MonoVTable *
1925 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1927 MONO_REQ_GC_UNSAFE_MODE;
1929 HANDLE_FUNCTION_ENTER ();
1931 MonoVTable *vt;
1932 MonoClassRuntimeInfo *runtime_info;
1933 MonoClassField *field;
1934 char *t;
1935 int i, vtable_slots;
1936 size_t imt_table_bytes;
1937 int gc_bits;
1938 guint32 vtable_size, class_size;
1939 gpointer iter;
1940 gpointer *interface_offsets;
1942 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1943 mono_domain_lock (domain);
1945 runtime_info = m_class_get_runtime_info (klass);
1946 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1947 mono_domain_unlock (domain);
1948 mono_loader_unlock ();
1949 vt = runtime_info->domain_vtables [domain->domain_id];
1950 goto exit;
1952 if (!m_class_is_inited (klass) || mono_class_has_failure (klass)) {
1953 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1954 mono_domain_unlock (domain);
1955 mono_loader_unlock ();
1956 mono_error_set_for_class_failure (error, klass);
1957 goto return_null;
1961 /* Array types require that their element type be valid*/
1962 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_ARRAY || m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
1963 MonoClass *element_class = m_class_get_element_class (klass);
1964 if (!m_class_is_inited (element_class))
1965 mono_class_init (element_class);
1967 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1968 if (!mono_class_has_failure (element_class) && !m_class_get_vtable_size (element_class))
1969 mono_class_setup_vtable (element_class);
1971 if (mono_class_has_failure (element_class)) {
1972 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1973 if (!mono_class_has_failure (klass))
1974 mono_class_set_type_load_failure (klass, "");
1975 mono_domain_unlock (domain);
1976 mono_loader_unlock ();
1977 mono_error_set_for_class_failure (error, klass);
1978 goto return_null;
1983 * For some classes, mono_class_init () already computed klass->vtable_size, and
1984 * that is all that is needed because of the vtable trampolines.
1986 if (!m_class_get_vtable_size (klass))
1987 mono_class_setup_vtable (klass);
1989 if (mono_class_is_ginst (klass) && !m_class_get_vtable (klass))
1990 mono_class_check_vtable_constraints (klass, NULL);
1992 /* Initialize klass->has_finalize */
1993 mono_class_has_finalizer (klass);
1995 if (mono_class_has_failure (klass)) {
1996 mono_domain_unlock (domain);
1997 mono_loader_unlock ();
1998 mono_error_set_for_class_failure (error, klass);
1999 goto return_null;
2002 vtable_slots = m_class_get_vtable_size (klass);
2003 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2004 class_size = mono_class_data_size (klass);
2005 if (class_size)
2006 vtable_slots++;
2008 if (m_class_get_interface_offsets_count (klass)) {
2009 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2010 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2011 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2012 } else {
2013 imt_table_bytes = 0;
2016 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2018 UnlockedIncrement (&mono_stats.used_class_count);
2019 UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
2021 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2022 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2023 g_assert (!((gsize)vt & 7));
2025 vt->klass = klass;
2026 vt->rank = m_class_get_rank (klass);
2027 vt->domain = domain;
2029 MONO_PROFILER_RAISE (vtable_loading, (vt));
2031 mono_class_compute_gc_descriptor (klass);
2033 * For Boehm:
2034 * We can't use typed allocation in the non-root domains, since the
2035 * collector needs the GC descriptor stored in the vtable even after
2036 * the mempool containing the vtable is destroyed when the domain is
2037 * unloaded. An alternative might be to allocate vtables in the GC
2038 * heap, but this does not seem to work (it leads to crashes inside
2039 * libgc). If that approach is tried, two gc descriptors need to be
2040 * allocated for each class: one for the root domain, and one for all
2041 * other domains. The second descriptor should contain a bit for the
2042 * vtable field in MonoObject, since we can no longer assume the
2043 * vtable is reachable by other roots after the appdomain is unloaded.
2045 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
2046 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2047 else
2048 vt->gc_descr = m_class_get_gc_descr (klass);
2050 gc_bits = mono_gc_get_vtable_bits (klass);
2051 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2053 vt->gc_bits = gc_bits;
2055 if (class_size) {
2056 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2057 if (m_class_has_static_refs (klass)) {
2058 MonoGCDescriptor statics_gc_descr;
2059 int max_set = 0;
2060 gsize default_bitmap [4] = {0};
2061 gsize *bitmap;
2063 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2064 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2065 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2066 vt->vtable [m_class_get_vtable_size (klass)] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, vt, "Static Fields");
2068 if (bitmap != default_bitmap)
2069 g_free (bitmap);
2070 } else {
2071 vt->vtable [m_class_get_vtable_size (klass)] = mono_domain_alloc0 (domain, class_size);
2073 vt->has_static_fields = TRUE;
2074 UnlockedAdd (&mono_stats.class_static_data_size, class_size);
2077 iter = NULL;
2078 while ((field = mono_class_get_fields_internal (klass, &iter))) {
2079 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2080 continue;
2081 if (mono_field_is_deleted (field))
2082 continue;
2083 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2084 gint32 special_static = m_class_has_no_special_static_fields (klass) ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2085 if (special_static != SPECIAL_STATIC_NONE) {
2086 guint32 size, offset;
2087 gint32 align;
2088 gsize default_bitmap [4] = {0};
2089 gsize *bitmap;
2090 int max_set = 0;
2091 int numbits;
2092 MonoClass *fclass;
2093 if (mono_type_is_reference (field->type)) {
2094 default_bitmap [0] = 1;
2095 numbits = 1;
2096 bitmap = default_bitmap;
2097 } else if (mono_type_is_struct (field->type)) {
2098 fclass = mono_class_from_mono_type (field->type);
2099 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(MONO_OBJECT_HEADER_BITS), &max_set, FALSE);
2100 numbits = max_set + 1;
2101 } else {
2102 default_bitmap [0] = 0;
2103 numbits = 0;
2104 bitmap = default_bitmap;
2106 size = mono_type_size (field->type, &align);
2107 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2108 if (!domain->special_static_fields)
2109 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2110 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2111 if (bitmap != default_bitmap)
2112 g_free (bitmap);
2114 * This marks the field as special static to speed up the
2115 * checks in mono_field_static_get/set_value ().
2117 field->offset = -1;
2118 continue;
2121 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2122 MonoClass *fklass = mono_class_from_mono_type (field->type);
2123 const char *data = mono_field_get_data (field);
2125 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2126 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2127 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2128 if (!data)
2129 continue;
2130 if (m_class_is_valuetype (fklass)) {
2131 memcpy (t, data, mono_class_value_size (fklass, NULL));
2132 } else {
2133 /* it's a pointer type: add check */
2134 g_assert ((m_class_get_byval_arg (fklass)->type == MONO_TYPE_PTR) || (m_class_get_byval_arg (fklass)->type == MONO_TYPE_FNPTR));
2135 *t = *(char *)data;
2137 continue;
2141 vt->max_interface_id = m_class_get_max_interface_id (klass);
2142 vt->interface_bitmap = m_class_get_interface_bitmap (klass);
2144 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2145 // class->name, klass->interface_offsets_count);
2147 /* Initialize vtable */
2148 if (callbacks.get_vtable_trampoline) {
2149 // This also covers the AOT case
2150 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2151 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2153 } else {
2154 mono_class_setup_vtable (klass);
2156 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2157 MonoMethod *cm;
2159 cm = m_class_get_vtable (klass) [i];
2160 if (cm) {
2161 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2162 if (!is_ok (error)) {
2163 mono_domain_unlock (domain);
2164 mono_loader_unlock ();
2165 MONO_PROFILER_RAISE (vtable_failed, (vt));
2166 goto return_null;
2172 if (imt_table_bytes) {
2173 /* Now that the vtable is full, we can actually fill up the IMT */
2174 for (i = 0; i < MONO_IMT_SIZE; ++i)
2175 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2179 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2180 * re-acquire them and check if another thread has created the vtable in the meantime.
2182 /* Special case System.MonoType to avoid infinite recursion */
2183 if (klass != mono_defaults.runtimetype_class) {
2184 MonoReflectionTypeHandle vt_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
2185 vt->type = MONO_HANDLE_RAW (vt_type);
2186 if (!is_ok (error)) {
2187 mono_domain_unlock (domain);
2188 mono_loader_unlock ();
2189 MONO_PROFILER_RAISE (vtable_failed, (vt));
2190 goto return_null;
2192 if (mono_handle_class (vt_type) != mono_defaults.runtimetype_class)
2193 /* This is unregistered in
2194 unregister_vtable_reflection_type() in
2195 domain.c. */
2196 MONO_GC_REGISTER_ROOT_IF_MOVING (vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object");
2199 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2201 /* class_vtable_array keeps an array of created vtables
2203 g_ptr_array_add (domain->class_vtable_array, vt);
2204 /* klass->runtime_info is protected by the loader lock, both when
2205 * it it enlarged and when it is stored info.
2209 * Store the vtable in klass->runtime_info.
2210 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2212 mono_memory_barrier ();
2214 mono_class_setup_runtime_info (klass, domain, vt);
2216 if (klass == mono_defaults.runtimetype_class) {
2217 MonoReflectionTypeHandle vt_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
2218 vt->type = MONO_HANDLE_RAW (vt_type);
2219 if (!is_ok (error)) {
2220 mono_domain_unlock (domain);
2221 mono_loader_unlock ();
2222 MONO_PROFILER_RAISE (vtable_failed, (vt));
2223 goto return_null;
2226 if (mono_handle_class (vt_type) != mono_defaults.runtimetype_class)
2227 /* This is unregistered in
2228 unregister_vtable_reflection_type() in
2229 domain.c. */
2230 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object");
2233 mono_domain_unlock (domain);
2234 mono_loader_unlock ();
2236 /* make sure the parent is initialized */
2237 /*FIXME shouldn't this fail the current type?*/
2238 if (m_class_get_parent (klass))
2239 mono_class_vtable_checked (domain, m_class_get_parent (klass), error);
2241 MONO_PROFILER_RAISE (vtable_loaded, (vt));
2243 goto exit;
2244 return_null:
2245 vt = NULL;
2246 exit:
2247 HANDLE_FUNCTION_RETURN_VAL (vt);
2250 #ifndef DISABLE_REMOTING
2252 * mono_remote_class_is_interface_proxy:
2253 * \param remote_class
2255 * Returns TRUE if the given remote class is a proxying an interface (as
2256 * opposed to a class deriving from MarshalByRefObject).
2258 gboolean
2259 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2261 /* This if condition is taking advantage of how mono_remote_class ()
2262 * works: if that code changes, this needs to change too. */
2263 return (remote_class->interface_count >= 1 &&
2264 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2268 * mono_class_proxy_vtable:
2269 * \param domain the application domain
2270 * \param remove_class the remote class
2271 * \param error set on error
2272 * Creates a vtable for transparent proxies. It is basically
2273 * a copy of the real vtable of the class wrapped in \p remote_class,
2274 * but all function pointers invoke the remoting functions, and
2275 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2277 * On failure returns NULL and sets \p error
2279 static MonoVTable *
2280 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2282 MONO_REQ_GC_UNSAFE_MODE;
2284 MonoVTable *vt, *pvt;
2285 int i, j, vtsize, extra_interface_vtsize = 0;
2286 guint32 max_interface_id;
2287 MonoClass *k;
2288 GSList *extra_interfaces = NULL;
2289 MonoClass *klass = remote_class->proxy_class;
2290 gpointer *interface_offsets;
2291 uint8_t *bitmap = NULL;
2292 int bsize;
2293 size_t imt_table_bytes;
2295 #ifdef COMPRESSED_INTERFACE_BITMAP
2296 int bcsize;
2297 #endif
2299 error_init (error);
2301 vt = mono_class_vtable_checked (domain, klass, error);
2302 if (!is_ok (error))
2303 return NULL;
2304 max_interface_id = vt->max_interface_id;
2306 /* Calculate vtable space for extra interfaces */
2307 for (j = 0; j < remote_class->interface_count; j++) {
2308 MonoClass* iclass = remote_class->interfaces[j];
2309 GPtrArray *ifaces;
2310 int method_count;
2312 /*FIXME test for interfaces with variant generic arguments*/
2313 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (iclass)))
2314 continue; /* interface implemented by the class */
2315 if (g_slist_find (extra_interfaces, iclass))
2316 continue;
2318 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2320 method_count = mono_class_num_methods (iclass);
2322 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2323 goto_if_nok (error, failure);
2324 if (ifaces) {
2325 for (i = 0; i < ifaces->len; ++i) {
2326 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2327 /*FIXME test for interfaces with variant generic arguments*/
2328 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (ic)))
2329 continue; /* interface implemented by the class */
2330 if (g_slist_find (extra_interfaces, ic))
2331 continue;
2332 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2333 method_count += mono_class_num_methods (ic);
2335 g_ptr_array_free (ifaces, TRUE);
2336 ifaces = NULL;
2339 extra_interface_vtsize += method_count * sizeof (gpointer);
2340 if (m_class_get_max_interface_id (iclass) > max_interface_id) max_interface_id = m_class_get_max_interface_id (iclass);
2343 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2344 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2345 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2347 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + m_class_get_vtable_size (klass) * sizeof (gpointer);
2349 UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2351 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2352 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2353 g_assert (!((gsize)pvt & 7));
2355 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + m_class_get_vtable_size (klass) * sizeof (gpointer));
2357 pvt->klass = mono_defaults.transparent_proxy_class;
2359 MONO_PROFILER_RAISE (vtable_loading, (pvt));
2361 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2362 pvt->gc_descr = m_class_get_gc_descr (mono_defaults.transparent_proxy_class);
2364 if (mono_remote_class_is_interface_proxy (remote_class)) {
2365 /* If it's a transparent proxy for an interface, set the
2366 * MonoVTable:type to the interface type, not the placeholder
2367 * MarshalByRefObject class. This is used when mini JITs calls
2368 * to Object.GetType ()
2370 MonoType *itf_proxy_type = m_class_get_byval_arg (remote_class->interfaces[0]);
2371 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2372 goto_if_nok (error, failure);
2375 /* initialize vtable */
2376 mono_class_setup_vtable (klass);
2377 MonoMethod **klass_vtable;
2378 klass_vtable = m_class_get_vtable (klass);
2379 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2380 MonoMethod *cm;
2382 if ((cm = klass_vtable [i])) {
2383 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2384 goto_if_nok (error, failure);
2385 } else
2386 pvt->vtable [i] = NULL;
2389 if (mono_class_is_abstract (klass)) {
2390 /* create trampolines for abstract methods */
2391 for (k = klass; k; k = m_class_get_parent (k)) {
2392 MonoMethod* m;
2393 gpointer iter = NULL;
2394 while ((m = mono_class_get_methods (k, &iter)))
2395 if (!pvt->vtable [m->slot]) {
2396 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2397 goto_if_nok (error, failure);
2402 pvt->max_interface_id = max_interface_id;
2403 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2404 #ifdef COMPRESSED_INTERFACE_BITMAP
2405 bitmap = (uint8_t *)g_malloc0 (bsize);
2406 #else
2407 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2408 #endif
2410 for (i = 0; i < m_class_get_interface_offsets_count (klass); ++i) {
2411 int interface_id = m_class_get_interface_id (m_class_get_interfaces_packed (klass) [i]);
2412 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2415 if (extra_interfaces) {
2416 int slot = m_class_get_vtable_size (klass);
2417 MonoClass* interf;
2418 gpointer iter;
2419 MonoMethod* cm;
2420 GSList *list_item;
2422 /* Create trampolines for the methods of the interfaces */
2423 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2424 interf = (MonoClass *)list_item->data;
2426 guint32 interf_interface_id = m_class_get_interface_id (interf);
2427 bitmap [interf_interface_id >> 3] |= (1 << (interf_interface_id & 7));
2429 iter = NULL;
2430 j = 0;
2431 while ((cm = mono_class_get_methods (interf, &iter))) {
2432 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2433 goto_if_nok (error, failure);
2436 slot += mono_class_num_methods (interf);
2440 /* Now that the vtable is full, we can actually fill up the IMT */
2441 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2442 if (extra_interfaces) {
2443 g_slist_free (extra_interfaces);
2446 #ifdef COMPRESSED_INTERFACE_BITMAP
2447 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2448 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2449 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2450 g_free (bitmap);
2451 #else
2452 pvt->interface_bitmap = bitmap;
2453 #endif
2454 MONO_PROFILER_RAISE (vtable_loaded, (pvt));
2455 return pvt;
2456 failure:
2457 if (extra_interfaces)
2458 g_slist_free (extra_interfaces);
2459 #ifdef COMPRESSED_INTERFACE_BITMAP
2460 g_free (bitmap);
2461 #endif
2462 MONO_PROFILER_RAISE (vtable_failed, (pvt));
2463 return NULL;
2466 #endif /* DISABLE_REMOTING */
2469 * mono_class_field_is_special_static:
2470 * \returns whether \p field is a thread/context static field.
2472 gboolean
2473 mono_class_field_is_special_static (MonoClassField *field)
2475 MONO_REQ_GC_NEUTRAL_MODE
2477 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2478 return FALSE;
2479 if (mono_field_is_deleted (field))
2480 return FALSE;
2481 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2482 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2483 return TRUE;
2485 return FALSE;
2489 * mono_class_field_get_special_static_type:
2490 * \param field The \c MonoClassField describing the field.
2491 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2492 * \c SPECIAL_STATIC_NONE otherwise.
2494 guint32
2495 mono_class_field_get_special_static_type (MonoClassField *field)
2497 MONO_REQ_GC_NEUTRAL_MODE
2499 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2500 return SPECIAL_STATIC_NONE;
2501 if (mono_field_is_deleted (field))
2502 return SPECIAL_STATIC_NONE;
2503 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2504 return field_is_special_static (field->parent, field);
2505 return SPECIAL_STATIC_NONE;
2509 * mono_class_has_special_static_fields:
2510 * \returns whether \p klass has any thread/context static fields.
2512 gboolean
2513 mono_class_has_special_static_fields (MonoClass *klass)
2515 MONO_REQ_GC_NEUTRAL_MODE
2517 MonoClassField *field;
2518 gpointer iter;
2520 iter = NULL;
2521 while ((field = mono_class_get_fields_internal (klass, &iter))) {
2522 g_assert (field->parent == klass);
2523 if (mono_class_field_is_special_static (field))
2524 return TRUE;
2527 return FALSE;
2530 #ifndef DISABLE_REMOTING
2532 * create_remote_class_key:
2533 * Creates an array of pointers that can be used as a hash key for a remote class.
2534 * The first element of the array is the number of pointers.
2536 static gpointer*
2537 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2539 MONO_REQ_GC_NEUTRAL_MODE;
2541 gpointer *key;
2542 int i, j;
2544 if (remote_class == NULL) {
2545 if (mono_class_is_interface (extra_class)) {
2546 key = (void **)g_malloc (sizeof(gpointer) * 3);
2547 key [0] = GINT_TO_POINTER (2);
2548 key [1] = mono_defaults.marshalbyrefobject_class;
2549 key [2] = extra_class;
2550 } else {
2551 key = (void **)g_malloc (sizeof(gpointer) * 2);
2552 key [0] = GINT_TO_POINTER (1);
2553 key [1] = extra_class;
2555 } else {
2556 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2557 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2558 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2559 key [1] = remote_class->proxy_class;
2561 // Keep the list of interfaces sorted
2562 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2563 if (extra_class && remote_class->interfaces [i] > extra_class) {
2564 key [j++] = extra_class;
2565 extra_class = NULL;
2567 key [j] = remote_class->interfaces [i];
2569 if (extra_class)
2570 key [j] = extra_class;
2571 } else {
2572 // Replace the old class. The interface list is the same
2573 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2574 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2575 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2576 for (i = 0; i < remote_class->interface_count; i++)
2577 key [2 + i] = remote_class->interfaces [i];
2581 return key;
2585 * copy_remote_class_key:
2587 * Make a copy of KEY in the domain and return the copy.
2589 static gpointer*
2590 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2592 MONO_REQ_GC_NEUTRAL_MODE
2594 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2595 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2597 memcpy (mp_key, key, key_size);
2599 return mp_key;
2603 * mono_remote_class:
2604 * \param domain the application domain
2605 * \param class_name name of the remote class
2606 * \param error set on error
2607 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2608 * On failure returns NULL and sets \p error
2610 MonoRemoteClass*
2611 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2613 MONO_REQ_GC_UNSAFE_MODE;
2615 MonoRemoteClass *rc;
2616 gpointer* key, *mp_key;
2617 char *name;
2619 error_init (error);
2621 key = create_remote_class_key (NULL, proxy_class);
2623 mono_domain_lock (domain);
2624 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2626 if (rc) {
2627 g_free (key);
2628 mono_domain_unlock (domain);
2629 return rc;
2632 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2633 if (!is_ok (error)) {
2634 g_free (key);
2635 mono_domain_unlock (domain);
2636 return NULL;
2639 mp_key = copy_remote_class_key (domain, key);
2640 g_free (key);
2641 key = mp_key;
2643 if (mono_class_is_interface (proxy_class)) {
2644 /* If we need to proxy an interface, we use this stylized
2645 * representation (interface_count >= 1, proxy_class is
2646 * MarshalByRefObject). The code in
2647 * mono_remote_class_is_interface_proxy () depends on being
2648 * able to detect that we're doing this, so if this
2649 * representation changes, change GetType, too. */
2650 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2651 rc->interface_count = 1;
2652 rc->interfaces [0] = proxy_class;
2653 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2654 } else {
2655 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2656 rc->interface_count = 0;
2657 rc->proxy_class = proxy_class;
2660 rc->default_vtable = NULL;
2661 rc->xdomain_vtable = NULL;
2662 rc->proxy_class_name = name;
2663 #ifndef DISABLE_PERFCOUNTERS
2664 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, mono_string_length (MONO_HANDLE_RAW (class_name)) + 1);
2665 #endif
2667 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2669 mono_domain_unlock (domain);
2670 return rc;
2674 * clone_remote_class:
2675 * Creates a copy of the remote_class, adding the provided class or interface
2677 static MonoRemoteClass*
2678 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2680 MONO_REQ_GC_NEUTRAL_MODE;
2682 MonoRemoteClass *rc;
2683 gpointer* key, *mp_key;
2685 key = create_remote_class_key (remote_class, extra_class);
2686 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2687 if (rc != NULL) {
2688 g_free (key);
2689 return rc;
2692 mp_key = copy_remote_class_key (domain, key);
2693 g_free (key);
2694 key = mp_key;
2696 if (mono_class_is_interface (extra_class)) {
2697 int i,j;
2698 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2699 rc->proxy_class = remote_class->proxy_class;
2700 rc->interface_count = remote_class->interface_count + 1;
2702 // Keep the list of interfaces sorted, since the hash key of
2703 // the remote class depends on this
2704 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2705 if (remote_class->interfaces [i] > extra_class && i == j)
2706 rc->interfaces [j++] = extra_class;
2707 rc->interfaces [j] = remote_class->interfaces [i];
2709 if (i == j)
2710 rc->interfaces [j] = extra_class;
2711 } else {
2712 // Replace the old class. The interface array is the same
2713 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2714 rc->proxy_class = extra_class;
2715 rc->interface_count = remote_class->interface_count;
2716 if (rc->interface_count > 0)
2717 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2720 rc->default_vtable = NULL;
2721 rc->xdomain_vtable = NULL;
2722 rc->proxy_class_name = remote_class->proxy_class_name;
2724 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2726 return rc;
2729 gpointer
2730 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2732 MONO_REQ_GC_UNSAFE_MODE;
2734 gpointer result = NULL;
2735 error_init (error);
2737 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2738 mono_domain_lock (domain);
2739 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2740 if (target_domain_id != -1) {
2741 if (remote_class->xdomain_vtable == NULL)
2742 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2743 goto_if_nok (error, leave);
2744 result = remote_class->xdomain_vtable;
2745 goto leave;
2747 if (remote_class->default_vtable == NULL) {
2748 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2749 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2751 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2752 MonoClass *klass = mono_class_from_mono_type (type);
2753 #ifndef DISABLE_COM
2754 gboolean target_is_com = FALSE;
2755 if (mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) {
2756 MonoVTable *klass_vtable = mono_class_vtable_checked (mono_domain_get (), klass, error);
2757 goto_if_nok (error, leave);
2758 if (!mono_vtable_is_remote (klass_vtable))
2759 target_is_com = TRUE;
2761 if (target_is_com)
2762 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2763 else
2764 #endif
2765 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2766 /* N.B. both branches of the if modify error */
2767 goto_if_nok (error, leave);
2771 result = remote_class->default_vtable;
2772 leave:
2773 mono_domain_unlock (domain);
2774 mono_loader_unlock ();
2775 return result;
2779 * mono_upgrade_remote_class:
2780 * \param domain the application domain
2781 * \param tproxy the proxy whose remote class has to be upgraded.
2782 * \param klass class to which the remote class can be casted.
2783 * \param error set on error
2784 * Updates the vtable of the remote class by adding the necessary method slots
2785 * and interface offsets so it can be safely casted to klass. klass can be a
2786 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2788 gboolean
2789 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2791 MONO_REQ_GC_UNSAFE_MODE;
2793 error_init (error);
2795 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2796 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2798 gboolean redo_vtable;
2799 if (mono_class_is_interface (klass)) {
2800 int i;
2801 redo_vtable = TRUE;
2802 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2803 if (remote_class->interfaces [i] == klass)
2804 redo_vtable = FALSE;
2806 else {
2807 redo_vtable = (remote_class->proxy_class != klass);
2810 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2811 mono_domain_lock (domain);
2812 if (redo_vtable) {
2813 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2814 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2815 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2816 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2817 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, (MonoVTable*)mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2818 goto_if_nok (error, leave);
2821 leave:
2822 mono_domain_unlock (domain);
2823 mono_loader_unlock ();
2824 return is_ok (error);
2826 #endif /* DISABLE_REMOTING */
2830 * mono_object_get_virtual_method:
2831 * \param obj object to operate on.
2832 * \param method method
2833 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2834 * the instance of a callvirt of \p method.
2836 MonoMethod*
2837 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2839 HANDLE_FUNCTION_ENTER ();
2840 MonoMethod *result;
2841 MONO_ENTER_GC_UNSAFE;
2842 ERROR_DECL (error);
2843 MONO_HANDLE_DCL (MonoObject, obj);
2844 result = mono_object_handle_get_virtual_method (obj, method, error);
2845 mono_error_assert_ok (error);
2846 MONO_EXIT_GC_UNSAFE;
2847 HANDLE_FUNCTION_RETURN_VAL (result);
2851 * mono_object_handle_get_virtual_method:
2852 * \param obj object to operate on.
2853 * \param method method
2854 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2855 * the instance of a callvirt of \p method.
2857 MonoMethod*
2858 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2860 error_init (error);
2862 gboolean is_proxy = FALSE;
2863 MonoClass *klass = mono_handle_class (obj);
2864 if (mono_class_is_transparent_proxy (klass)) {
2865 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2866 klass = remote_class->proxy_class;
2867 is_proxy = TRUE;
2869 return mono_class_get_virtual_method (klass, method, is_proxy, error);
2872 MonoMethod*
2873 mono_class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2875 MONO_REQ_GC_NEUTRAL_MODE;
2876 error_init (error);
2878 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2879 return method;
2881 mono_class_setup_vtable (klass);
2882 MonoMethod **vtable = m_class_get_vtable (klass);
2884 if (method->slot == -1) {
2885 /* method->slot might not be set for instances of generic methods */
2886 if (method->is_inflated) {
2887 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2888 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2889 } else {
2890 if (!is_proxy)
2891 g_assert_not_reached ();
2895 MonoMethod *res = NULL;
2896 /* check method->slot is a valid index: perform isinstance? */
2897 if (method->slot != -1) {
2898 if (mono_class_is_interface (method->klass)) {
2899 if (!is_proxy) {
2900 gboolean variance_used = FALSE;
2901 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2902 g_assert (iface_offset > 0);
2903 res = vtable [iface_offset + method->slot];
2905 } else {
2906 res = vtable [method->slot];
2910 #ifndef DISABLE_REMOTING
2911 if (is_proxy) {
2912 /* It may be an interface, abstract class method or generic method */
2913 if (!res || mono_method_signature (res)->generic_param_count)
2914 res = method;
2916 /* generic methods demand invoke_with_check */
2917 if (mono_method_signature (res)->generic_param_count)
2918 res = mono_marshal_get_remoting_invoke_with_check (res, error);
2919 else {
2920 #ifndef DISABLE_COM
2921 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2922 res = mono_cominterop_get_invoke (res);
2923 else
2924 #endif
2925 res = mono_marshal_get_remoting_invoke (res, error);
2927 } else
2928 #endif
2930 if (method->is_inflated) {
2931 /* Have to inflate the result */
2932 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2936 return res;
2939 static MonoObject*
2940 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2942 MONO_REQ_GC_UNSAFE_MODE;
2944 MonoObject *result = NULL;
2946 g_assert (callbacks.runtime_invoke);
2948 error_init (error);
2950 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2952 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2954 MONO_PROFILER_RAISE (method_end_invoke, (method));
2956 if (!mono_error_ok (error))
2957 return NULL;
2959 return result;
2963 * mono_runtime_invoke:
2964 * \param method method to invoke
2965 * \param obj object instance
2966 * \param params arguments to the method
2967 * \param exc exception information.
2968 * Invokes the method represented by \p method on the object \p obj.
2969 * \p obj is the \c this pointer, it should be NULL for static
2970 * methods, a \c MonoObject* for object instances and a pointer to
2971 * the value type for value types.
2973 * The params array contains the arguments to the method with the
2974 * same convention: \c MonoObject* pointers for object instances and
2975 * pointers to the value type otherwise.
2977 * From unmanaged code you'll usually use the
2978 * \c mono_runtime_invoke variant.
2980 * Note that this function doesn't handle virtual methods for
2981 * you, it will exec the exact method you pass: we still need to
2982 * expose a function to lookup the derived class implementation
2983 * of a virtual method (there are examples of this in the code,
2984 * though).
2986 * You can pass NULL as the \p exc argument if you don't want to
2987 * catch exceptions, otherwise, \c *exc will be set to the exception
2988 * thrown, if any. if an exception is thrown, you can't use the
2989 * \c MonoObject* result from the function.
2991 * If the method returns a value type, it is boxed in an object
2992 * reference.
2994 MonoObject*
2995 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2997 MonoObject *res;
2998 MONO_ENTER_GC_UNSAFE;
2999 ERROR_DECL (error);
3000 if (exc) {
3001 res = mono_runtime_try_invoke (method, obj, params, exc, error);
3002 if (*exc == NULL && !mono_error_ok(error)) {
3003 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3004 } else
3005 mono_error_cleanup (error);
3006 } else {
3007 res = mono_runtime_invoke_checked (method, obj, params, error);
3008 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
3010 MONO_EXIT_GC_UNSAFE;
3011 return res;
3015 * mono_runtime_try_invoke:
3016 * \param method method to invoke
3017 * \param obj object instance
3018 * \param params arguments to the method
3019 * \param exc exception information.
3020 * \param error set on error
3021 * Invokes the method represented by \p method on the object \p obj.
3023 * \p obj is the \c this pointer, it should be NULL for static
3024 * methods, a \c MonoObject* for object instances and a pointer to
3025 * the value type for value types.
3027 * The params array contains the arguments to the method with the
3028 * same convention: \c MonoObject* pointers for object instances and
3029 * pointers to the value type otherwise.
3031 * From unmanaged code you'll usually use the
3032 * mono_runtime_invoke() variant.
3034 * Note that this function doesn't handle virtual methods for
3035 * you, it will exec the exact method you pass: we still need to
3036 * expose a function to lookup the derived class implementation
3037 * of a virtual method (there are examples of this in the code,
3038 * though).
3040 * For this function, you must not pass NULL as the \p exc argument if
3041 * you don't want to catch exceptions, use
3042 * mono_runtime_invoke_checked(). If an exception is thrown, you
3043 * can't use the \c MonoObject* result from the function.
3045 * If this method cannot be invoked, \p error will be set and \p exc and
3046 * the return value must not be used.
3048 * If the method returns a value type, it is boxed in an object
3049 * reference.
3051 MonoObject*
3052 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3054 MONO_REQ_GC_UNSAFE_MODE;
3056 g_assert (exc != NULL);
3058 if (mono_runtime_get_no_exec ())
3059 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3061 return do_runtime_invoke (method, obj, params, exc, error);
3064 MonoObjectHandle
3065 mono_runtime_try_invoke_handle (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3067 // FIXME? typing of params
3068 MonoException *exc = NULL;
3069 MonoObject *obj_raw = mono_runtime_try_invoke (method, MONO_HANDLE_RAW (obj), params, (MonoObject**)&exc, error);
3071 if (exc && is_ok (error))
3072 mono_error_set_exception_instance (error, exc);
3074 return MONO_HANDLE_NEW (MonoObject, obj_raw);
3078 * mono_runtime_invoke_checked:
3079 * \param method method to invoke
3080 * \param obj object instance
3081 * \param params arguments to the method
3082 * \param error set on error
3083 * Invokes the method represented by \p method on the object \p obj.
3085 * \p obj is the \c this pointer, it should be NULL for static
3086 * methods, a \c MonoObject* for object instances and a pointer to
3087 * the value type for value types.
3089 * The \p params array contains the arguments to the method with the
3090 * same convention: \c MonoObject* pointers for object instances and
3091 * pointers to the value type otherwise.
3093 * From unmanaged code you'll usually use the
3094 * mono_runtime_invoke() variant.
3096 * Note that this function doesn't handle virtual methods for
3097 * you, it will exec the exact method you pass: we still need to
3098 * expose a function to lookup the derived class implementation
3099 * of a virtual method (there are examples of this in the code,
3100 * though).
3102 * If an exception is thrown, you can't use the \c MonoObject* result
3103 * from the function.
3105 * If this method cannot be invoked, \p error will be set. If the
3106 * method throws an exception (and we're in coop mode) the exception
3107 * will be set in \p error.
3109 * If the method returns a value type, it is boxed in an object
3110 * reference.
3112 MonoObject*
3113 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3115 MONO_REQ_GC_UNSAFE_MODE;
3117 if (mono_runtime_get_no_exec ())
3118 g_error ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3120 return do_runtime_invoke (method, obj, params, NULL, error);
3123 MonoObjectHandle
3124 mono_runtime_invoke_handle (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3126 return MONO_HANDLE_NEW (MonoObject, mono_runtime_invoke_checked (method, MONO_HANDLE_RAW (obj), params, error));
3130 * mono_method_get_unmanaged_thunk:
3131 * \param method method to generate a thunk for.
3133 * Returns an \c unmanaged->managed thunk that can be used to call
3134 * a managed method directly from C.
3136 * The thunk's C signature closely matches the managed signature:
3138 * C#: <code>public bool Equals (object obj);</code>
3140 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3142 * The 1st (<code>this</code>) parameter must not be used with static methods:
3144 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3146 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3148 * The last argument must be a non-null \c MonoException* pointer.
3149 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3150 * exception has been thrown in managed code. Otherwise it will point
3151 * to the \c MonoException* caught by the thunk. In this case, the result of
3152 * the thunk is undefined:
3154 * <pre>
3155 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3157 * MonoException *ex = NULL;
3159 * Equals func = mono_method_get_unmanaged_thunk (method);
3161 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3163 * if (ex) {
3165 * // handle exception
3168 * </pre>
3170 * The calling convention of the thunk matches the platform's default
3171 * convention. This means that under Windows, C declarations must
3172 * contain the \c __stdcall attribute:
3174 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3176 * LIMITATIONS
3178 * Value type arguments and return values are treated as they were objects:
3180 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3181 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3183 * Arguments must be properly boxed upon trunk's invocation, while return
3184 * values must be unboxed.
3186 gpointer
3187 mono_method_get_unmanaged_thunk (MonoMethod *method)
3189 MONO_REQ_GC_NEUTRAL_MODE;
3190 MONO_REQ_API_ENTRYPOINT;
3192 ERROR_DECL (error);
3193 gpointer res;
3195 MONO_ENTER_GC_UNSAFE;
3196 method = mono_marshal_get_thunk_invoke_wrapper (method);
3197 res = mono_compile_method_checked (method, error);
3198 mono_error_cleanup (error);
3199 MONO_EXIT_GC_UNSAFE;
3201 return res;
3204 void
3205 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3207 MONO_REQ_GC_UNSAFE_MODE;
3209 int t;
3210 if (type->byref) {
3211 /* object fields cannot be byref, so we don't need a
3212 wbarrier here */
3213 gpointer *p = (gpointer*)dest;
3214 *p = value;
3215 return;
3217 t = type->type;
3218 handle_enum:
3219 switch (t) {
3220 case MONO_TYPE_BOOLEAN:
3221 case MONO_TYPE_I1:
3222 case MONO_TYPE_U1: {
3223 guint8 *p = (guint8*)dest;
3224 *p = value ? *(guint8*)value : 0;
3225 return;
3227 case MONO_TYPE_I2:
3228 case MONO_TYPE_U2:
3229 case MONO_TYPE_CHAR: {
3230 guint16 *p = (guint16*)dest;
3231 *p = value ? *(guint16*)value : 0;
3232 return;
3234 #if SIZEOF_VOID_P == 4
3235 case MONO_TYPE_I:
3236 case MONO_TYPE_U:
3237 #endif
3238 case MONO_TYPE_I4:
3239 case MONO_TYPE_U4: {
3240 gint32 *p = (gint32*)dest;
3241 *p = value ? *(gint32*)value : 0;
3242 return;
3244 #if SIZEOF_VOID_P == 8
3245 case MONO_TYPE_I:
3246 case MONO_TYPE_U:
3247 #endif
3248 case MONO_TYPE_I8:
3249 case MONO_TYPE_U8: {
3250 gint64 *p = (gint64*)dest;
3251 *p = value ? *(gint64*)value : 0;
3252 return;
3254 case MONO_TYPE_R4: {
3255 float *p = (float*)dest;
3256 *p = value ? *(float*)value : 0;
3257 return;
3259 case MONO_TYPE_R8: {
3260 double *p = (double*)dest;
3261 *p = value ? *(double*)value : 0;
3262 return;
3264 case MONO_TYPE_STRING:
3265 case MONO_TYPE_SZARRAY:
3266 case MONO_TYPE_CLASS:
3267 case MONO_TYPE_OBJECT:
3268 case MONO_TYPE_ARRAY:
3269 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3270 return;
3271 case MONO_TYPE_FNPTR:
3272 case MONO_TYPE_PTR: {
3273 gpointer *p = (gpointer*)dest;
3274 *p = deref_pointer? *(gpointer*)value: value;
3275 return;
3277 case MONO_TYPE_VALUETYPE:
3278 /* note that 't' and 'type->type' can be different */
3279 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass)) {
3280 t = mono_class_enum_basetype_internal (type->data.klass)->type;
3281 goto handle_enum;
3282 } else {
3283 MonoClass *klass = mono_class_from_mono_type (type);
3284 int size = mono_class_value_size (klass, NULL);
3285 if (value == NULL)
3286 mono_gc_bzero_atomic (dest, size);
3287 else
3288 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3290 return;
3291 case MONO_TYPE_GENERICINST:
3292 t = m_class_get_byval_arg (type->data.generic_class->container_class)->type;
3293 goto handle_enum;
3294 default:
3295 g_error ("got type %x", type->type);
3300 * mono_field_set_value:
3301 * \param obj Instance object
3302 * \param field \c MonoClassField describing the field to set
3303 * \param value The value to be set
3305 * Sets the value of the field described by \p field in the object instance \p obj
3306 * to the value passed in \p value. This method should only be used for instance
3307 * fields. For static fields, use \c mono_field_static_set_value.
3309 * The value must be in the native format of the field type.
3311 void
3312 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3314 MONO_ENTER_GC_UNSAFE;
3316 void *dest;
3318 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3319 goto leave;
3321 dest = (char*)obj + field->offset;
3322 mono_copy_value (field->type, dest, value, FALSE);
3323 leave:
3324 MONO_EXIT_GC_UNSAFE;
3328 * mono_field_static_set_value:
3329 * \param field \c MonoClassField describing the field to set
3330 * \param value The value to be set
3331 * Sets the value of the static field described by \p field
3332 * to the value passed in \p value.
3333 * The value must be in the native format of the field type.
3335 void
3336 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3338 MONO_ENTER_GC_UNSAFE;
3340 void *dest;
3342 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC) == 0)
3343 goto leave;
3344 /* you cant set a constant! */
3345 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
3346 goto leave;
3348 if (field->offset == -1) {
3349 /* Special static */
3350 gpointer addr;
3352 mono_domain_lock (vt->domain);
3353 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3354 mono_domain_unlock (vt->domain);
3355 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3356 } else {
3357 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3359 mono_copy_value (field->type, dest, value, FALSE);
3360 leave:
3361 MONO_EXIT_GC_UNSAFE;
3365 * mono_vtable_get_static_field_data:
3367 * Internal use function: return a pointer to the memory holding the static fields
3368 * for a class or NULL if there are no static fields.
3369 * This is exported only for use by the debugger.
3371 void *
3372 mono_vtable_get_static_field_data (MonoVTable *vt)
3374 MONO_REQ_GC_NEUTRAL_MODE
3376 if (!vt->has_static_fields)
3377 return NULL;
3378 return vt->vtable [m_class_get_vtable_size (vt->klass)];
3381 static guint8*
3382 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3384 MONO_REQ_GC_UNSAFE_MODE;
3386 guint8 *src;
3388 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3389 if (field->offset == -1) {
3390 /* Special static */
3391 gpointer addr;
3393 mono_domain_lock (vt->domain);
3394 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3395 mono_domain_unlock (vt->domain);
3396 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3397 } else {
3398 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3400 } else {
3401 src = (guint8*)obj + field->offset;
3404 return src;
3408 * mono_field_get_value:
3409 * \param obj Object instance
3410 * \param field \c MonoClassField describing the field to fetch information from
3411 * \param value pointer to the location where the value will be stored
3412 * Use this routine to get the value of the field \p field in the object
3413 * passed.
3415 * The pointer provided by value must be of the field type, for reference
3416 * types this is a \c MonoObject*, for value types its the actual pointer to
3417 * the value type.
3419 * For example:
3421 * <pre>
3422 * int i;
3424 * mono_field_get_value (obj, int_field, &i);
3425 * </pre>
3427 void
3428 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3430 MONO_ENTER_GC_UNSAFE;
3431 mono_field_get_value_internal (obj, field, value);
3432 MONO_EXIT_GC_UNSAFE;
3435 void
3436 mono_field_get_value_internal (MonoObject *obj, MonoClassField *field, void *value)
3438 MONO_REQ_GC_UNSAFE_MODE;
3440 void *src;
3442 g_assert (obj);
3444 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3446 src = (char*)obj + field->offset;
3447 mono_copy_value (field->type, value, src, TRUE);
3451 * mono_field_get_value_object:
3452 * \param domain domain where the object will be created (if boxing)
3453 * \param field \c MonoClassField describing the field to fetch information from
3454 * \param obj The object instance for the field.
3455 * \returns a new \c MonoObject with the value from the given field. If the
3456 * field represents a value type, the value is boxed.
3458 MonoObject *
3459 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3461 MonoObject* result;
3462 MONO_ENTER_GC_UNSAFE;
3463 ERROR_DECL (error);
3464 result = mono_field_get_value_object_checked (domain, field, obj, error);
3465 mono_error_assert_ok (error);
3466 MONO_EXIT_GC_UNSAFE;
3467 return result;
3470 MonoObjectHandle
3471 mono_static_field_get_value_handle (MonoDomain *domain, MonoClassField *field, MonoError *error)
3472 // FIXMEcoop invert
3474 HANDLE_FUNCTION_ENTER ();
3475 HANDLE_FUNCTION_RETURN_REF (MonoObject, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (domain, field, NULL, error)));
3479 * mono_field_get_value_object_checked:
3480 * \param domain domain where the object will be created (if boxing)
3481 * \param field \c MonoClassField describing the field to fetch information from
3482 * \param obj The object instance for the field.
3483 * \param error Set on error.
3484 * \returns a new \c MonoObject with the value from the given field. If the
3485 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3487 MonoObject *
3488 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3490 MONO_REQ_GC_UNSAFE_MODE;
3492 error_init (error);
3494 MonoObject *o;
3495 MonoClass *klass;
3496 MonoVTable *vtable = NULL;
3497 gpointer v;
3498 gboolean is_static = FALSE;
3499 gboolean is_ref = FALSE;
3500 gboolean is_literal = FALSE;
3501 gboolean is_ptr = FALSE;
3502 MonoType *type = mono_field_get_type_checked (field, error);
3504 return_val_if_nok (error, NULL);
3506 switch (type->type) {
3507 case MONO_TYPE_STRING:
3508 case MONO_TYPE_OBJECT:
3509 case MONO_TYPE_CLASS:
3510 case MONO_TYPE_ARRAY:
3511 case MONO_TYPE_SZARRAY:
3512 is_ref = TRUE;
3513 break;
3514 case MONO_TYPE_U1:
3515 case MONO_TYPE_I1:
3516 case MONO_TYPE_BOOLEAN:
3517 case MONO_TYPE_U2:
3518 case MONO_TYPE_I2:
3519 case MONO_TYPE_CHAR:
3520 case MONO_TYPE_U:
3521 case MONO_TYPE_I:
3522 case MONO_TYPE_U4:
3523 case MONO_TYPE_I4:
3524 case MONO_TYPE_R4:
3525 case MONO_TYPE_U8:
3526 case MONO_TYPE_I8:
3527 case MONO_TYPE_R8:
3528 case MONO_TYPE_VALUETYPE:
3529 is_ref = type->byref;
3530 break;
3531 case MONO_TYPE_GENERICINST:
3532 is_ref = !mono_type_generic_inst_is_valuetype (type);
3533 break;
3534 case MONO_TYPE_PTR:
3535 is_ptr = TRUE;
3536 break;
3537 default:
3538 g_error ("type 0x%x not handled in "
3539 "mono_field_get_value_object", type->type);
3540 return NULL;
3543 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3544 is_literal = TRUE;
3546 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3547 is_static = TRUE;
3549 if (!is_literal) {
3550 vtable = mono_class_vtable_checked (domain, field->parent, error);
3551 return_val_if_nok (error, NULL);
3553 if (!vtable->initialized) {
3554 mono_runtime_class_init_full (vtable, error);
3555 return_val_if_nok (error, NULL);
3558 } else {
3559 g_assert (obj);
3562 if (is_ref) {
3563 if (is_literal) {
3564 get_default_field_value (domain, field, &o, error);
3565 return_val_if_nok (error, NULL);
3566 } else if (is_static) {
3567 mono_field_static_get_value_checked (vtable, field, &o, error);
3568 return_val_if_nok (error, NULL);
3569 } else {
3570 mono_field_get_value (obj, field, &o);
3572 return o;
3575 if (is_ptr) {
3576 static MonoMethod *m;
3577 gpointer args [2];
3578 gpointer *ptr;
3580 if (!m) {
3581 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3582 m = mono_class_get_method_from_name_checked (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC, error);
3583 return_val_if_nok (error, NULL);
3584 g_assert (m);
3587 v = &ptr;
3588 if (is_literal) {
3589 get_default_field_value (domain, field, v, error);
3590 return_val_if_nok (error, NULL);
3591 } else if (is_static) {
3592 mono_field_static_get_value_checked (vtable, field, v, error);
3593 return_val_if_nok (error, NULL);
3594 } else {
3595 mono_field_get_value (obj, field, v);
3598 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3599 args [0] = ptr ? *ptr : NULL;
3600 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3601 return_val_if_nok (error, NULL);
3603 o = mono_runtime_invoke_checked (m, NULL, args, error);
3604 return_val_if_nok (error, NULL);
3606 return o;
3609 /* boxed value type */
3610 klass = mono_class_from_mono_type (type);
3612 if (mono_class_is_nullable (klass))
3613 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3615 o = mono_object_new_checked (domain, klass, error);
3616 return_val_if_nok (error, NULL);
3617 v = mono_object_get_data (o);
3619 if (is_literal) {
3620 get_default_field_value (domain, field, v, error);
3621 return_val_if_nok (error, NULL);
3622 } else if (is_static) {
3623 mono_field_static_get_value_checked (vtable, field, v, error);
3624 return_val_if_nok (error, NULL);
3625 } else {
3626 mono_field_get_value (obj, field, v);
3629 return o;
3633 * Important detail, if type is MONO_TYPE_STRING we return a blob encoded string (ie, utf16 + leb128 prefixed size)
3635 gboolean
3636 mono_metadata_read_constant_value (const char *blob, MonoTypeEnum type, void *value, MonoError *error)
3639 error_init (error);
3640 gboolean retval = TRUE;
3641 const char *p = blob;
3642 mono_metadata_decode_blob_size (p, &p);
3644 switch (type) {
3645 case MONO_TYPE_BOOLEAN:
3646 case MONO_TYPE_U1:
3647 case MONO_TYPE_I1:
3648 *(guint8 *) value = *p;
3649 break;
3650 case MONO_TYPE_CHAR:
3651 case MONO_TYPE_U2:
3652 case MONO_TYPE_I2:
3653 *(guint16*) value = read16 (p);
3654 break;
3655 case MONO_TYPE_U4:
3656 case MONO_TYPE_I4:
3657 *(guint32*) value = read32 (p);
3658 break;
3659 case MONO_TYPE_U8:
3660 case MONO_TYPE_I8:
3661 *(guint64*) value = read64 (p);
3662 break;
3663 case MONO_TYPE_R4:
3664 readr4 (p, (float*) value);
3665 break;
3666 case MONO_TYPE_R8:
3667 readr8 (p, (double*) value);
3668 break;
3669 case MONO_TYPE_STRING:
3670 *(const char**) value = blob;
3671 break;
3672 case MONO_TYPE_CLASS:
3673 *(gpointer*) value = NULL;
3674 break;
3675 default:
3676 retval = FALSE;
3677 mono_error_set_execution_engine (error, "Type 0x%02x should not be in constant table", type);
3679 return retval;
3683 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3685 MONO_REQ_GC_UNSAFE_MODE
3687 if (!mono_metadata_read_constant_value (blob, type, value, error))
3688 return -1;
3690 if (type == MONO_TYPE_STRING)
3691 *(gpointer*)value = mono_ldstr_metadata_sig (domain, *(const char**)value, error);
3693 return 0;
3696 static void
3697 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3699 MONO_REQ_GC_NEUTRAL_MODE;
3701 MonoTypeEnum def_type;
3702 const char* data;
3704 error_init (error);
3706 data = mono_class_get_field_default_value (field, &def_type);
3707 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3710 void
3711 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3713 MONO_REQ_GC_UNSAFE_MODE;
3715 void *src;
3717 error_init (error);
3719 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3721 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3722 get_default_field_value (vt->domain, field, value, error);
3723 return;
3726 if (field->offset == -1) {
3727 /* Special static */
3728 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3729 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3730 } else {
3731 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3733 mono_copy_value (field->type, value, src, TRUE);
3737 * mono_field_static_get_value:
3738 * \param vt vtable to the object
3739 * \param field \c MonoClassField describing the field to fetch information from
3740 * \param value where the value is returned
3741 * Use this routine to get the value of the static field \p field value.
3743 * The pointer provided by value must be of the field type, for reference
3744 * types this is a \c MonoObject*, for value types its the actual pointer to
3745 * the value type.
3747 * For example:
3749 * <pre>
3750 * int i;
3752 * mono_field_static_get_value (vt, int_field, &i);
3753 * </pre>
3755 void
3756 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3758 MONO_REQ_GC_NEUTRAL_MODE;
3760 ERROR_DECL (error);
3761 mono_field_static_get_value_checked (vt, field, value, error);
3762 mono_error_cleanup (error);
3766 * mono_field_static_get_value_checked:
3767 * \param vt vtable to the object
3768 * \param field \c MonoClassField describing the field to fetch information from
3769 * \param value where the value is returned
3770 * \param error set on error
3771 * Use this routine to get the value of the static field \p field value.
3773 * The pointer provided by value must be of the field type, for reference
3774 * types this is a \c MonoObject*, for value types its the actual pointer to
3775 * the value type.
3777 * For example:
3778 * int i;
3779 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3780 * if (!is_ok (error)) { ... }
3782 * On failure sets \p error.
3784 void
3785 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3787 MONO_REQ_GC_NEUTRAL_MODE;
3789 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3793 * mono_property_set_value:
3794 * \param prop MonoProperty to set
3795 * \param obj instance object on which to act
3796 * \param params parameters to pass to the propery
3797 * \param exc optional exception
3798 * Invokes the property's set method with the given arguments on the
3799 * object instance obj (or NULL for static properties).
3801 * You can pass NULL as the exc argument if you don't want to
3802 * catch exceptions, otherwise, \c *exc will be set to the exception
3803 * thrown, if any. if an exception is thrown, you can't use the
3804 * \c MonoObject* result from the function.
3806 void
3807 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3809 MONO_ENTER_GC_UNSAFE;
3811 ERROR_DECL (error);
3812 do_runtime_invoke (prop->set, obj, params, exc, error);
3813 if (exc && *exc == NULL && !mono_error_ok (error)) {
3814 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3815 } else {
3816 mono_error_cleanup (error);
3818 MONO_EXIT_GC_UNSAFE;
3822 * mono_property_set_value_handle:
3823 * \param prop \c MonoProperty to set
3824 * \param obj instance object on which to act
3825 * \param params parameters to pass to the propery
3826 * \param error set on error
3827 * Invokes the property's set method with the given arguments on the
3828 * object instance \p obj (or NULL for static properties).
3829 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3830 * If an exception is thrown, it will be caught and returned via \p error.
3832 gboolean
3833 mono_property_set_value_handle (MonoProperty *prop, MonoObjectHandle obj, void **params, MonoError *error)
3835 MONO_REQ_GC_UNSAFE_MODE;
3837 MonoObject *exc;
3839 error_init (error);
3840 do_runtime_invoke (prop->set, MONO_HANDLE_RAW (obj), params, &exc, error);
3841 if (exc != NULL && is_ok (error))
3842 mono_error_set_exception_instance (error, (MonoException*)exc);
3843 return is_ok (error);
3847 * mono_property_get_value:
3848 * \param prop \c MonoProperty to fetch
3849 * \param obj instance object on which to act
3850 * \param params parameters to pass to the propery
3851 * \param exc optional exception
3852 * Invokes the property's \c get method with the given arguments on the
3853 * object instance \p obj (or NULL for static properties).
3855 * You can pass NULL as the \p exc argument if you don't want to
3856 * catch exceptions, otherwise, \c *exc will be set to the exception
3857 * thrown, if any. if an exception is thrown, you can't use the
3858 * \c MonoObject* result from the function.
3860 * \returns the value from invoking the \c get method on the property.
3862 MonoObject*
3863 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3865 MONO_REQ_GC_UNSAFE_MODE;
3867 ERROR_DECL (error);
3868 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, error);
3869 if (exc && *exc == NULL && !mono_error_ok (error)) {
3870 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3871 } else {
3872 mono_error_cleanup (error); /* FIXME don't raise here */
3875 return val;
3879 * mono_property_get_value_checked:
3880 * \param prop \c MonoProperty to fetch
3881 * \param obj instance object on which to act
3882 * \param params parameters to pass to the propery
3883 * \param error set on error
3884 * Invokes the property's \c get method with the given arguments on the
3885 * object instance obj (or NULL for static properties).
3887 * If an exception is thrown, you can't use the
3888 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3890 * \returns the value from invoking the get method on the property. On
3891 * failure returns NULL and sets \p error.
3893 MonoObject*
3894 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3896 MONO_REQ_GC_UNSAFE_MODE;
3898 MonoObject *exc;
3899 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3900 if (exc != NULL && !is_ok (error))
3901 mono_error_set_exception_instance (error, (MonoException*) exc);
3902 if (!is_ok (error))
3903 val = NULL;
3904 return val;
3907 static MonoClassField*
3908 nullable_class_get_value_field (MonoClass *klass)
3910 mono_class_setup_fields (klass);
3911 g_assert (m_class_is_fields_inited (klass));
3913 MonoClassField *klass_fields = m_class_get_fields (klass);
3914 return &klass_fields [1];
3917 static MonoClassField*
3918 nullable_class_get_has_value_field (MonoClass *klass)
3920 mono_class_setup_fields (klass);
3921 g_assert (m_class_is_fields_inited (klass));
3923 MonoClassField *klass_fields = m_class_get_fields (klass);
3924 return &klass_fields [0];
3927 static gpointer
3928 nullable_get_has_value_field_addr (guint8 *nullable, MonoClass *klass)
3930 MonoClassField *has_value_field = nullable_class_get_has_value_field (klass);
3932 return mono_vtype_get_field_addr (nullable, has_value_field);
3935 static gpointer
3936 nullable_get_value_field_addr (guint8 *nullable, MonoClass *klass)
3938 MonoClassField *has_value_field = nullable_class_get_value_field (klass);
3940 return mono_vtype_get_field_addr (nullable, has_value_field);
3944 * mono_nullable_init:
3945 * @buf: The nullable structure to initialize.
3946 * @value: the value to initialize from
3947 * @klass: the type for the object
3949 * Initialize the nullable structure pointed to by @buf from @value which
3950 * should be a boxed value type. The size of @buf should be able to hold
3951 * as much data as the @klass->instance_size (which is the number of bytes
3952 * that will be copies).
3954 * Since Nullables have variable structure, we can not define a C
3955 * structure for them.
3957 void
3958 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3960 MONO_REQ_GC_UNSAFE_MODE;
3962 MonoClass *param_class = m_class_get_cast_class (klass);
3963 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
3964 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
3966 *(guint8*)(has_value_field_addr) = value ? 1 : 0;
3967 if (value) {
3968 if (m_class_has_references (param_class))
3969 mono_gc_wbarrier_value_copy (value_field_addr, mono_object_unbox (value), 1, param_class);
3970 else
3971 mono_gc_memmove_atomic (value_field_addr, mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3972 } else {
3973 mono_gc_bzero_atomic (value_field_addr, mono_class_value_size (param_class, NULL));
3978 * mono_nullable_init_from_handle:
3979 * @buf: The nullable structure to initialize.
3980 * @value: the value to initialize from
3981 * @klass: the type for the object
3983 * Initialize the nullable structure pointed to by @buf from @value which
3984 * should be a boxed value type. The size of @buf should be able to hold
3985 * as much data as the @klass->instance_size (which is the number of bytes
3986 * that will be copies).
3988 * Since Nullables have variable structure, we can not define a C
3989 * structure for them.
3991 void
3992 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3994 MONO_REQ_GC_UNSAFE_MODE;
3996 MonoClass *param_class = m_class_get_cast_class (klass);
3997 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
3998 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4000 *(guint8*)(has_value_field_addr) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
4001 if (!MONO_HANDLE_IS_NULL (value)) {
4002 uint32_t value_gchandle = 0;
4003 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
4004 if (m_class_has_references (param_class))
4005 mono_gc_wbarrier_value_copy (value_field_addr, src, 1, param_class);
4006 else
4007 mono_gc_memmove_atomic (value_field_addr, src, mono_class_value_size (param_class, NULL));
4008 mono_gchandle_free (value_gchandle);
4009 } else {
4010 mono_gc_bzero_atomic (value_field_addr, mono_class_value_size (param_class, NULL));
4015 * mono_nullable_box:
4016 * \param buf The buffer representing the data to be boxed
4017 * \param klass the type to box it as.
4018 * \param error set on error
4020 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
4021 * \p buf. On failure returns NULL and sets \p error.
4023 MonoObject*
4024 mono_nullable_box (gpointer vbuf, MonoClass *klass, MonoError *error)
4026 guint8 *buf = (guint8*)vbuf;
4027 MONO_REQ_GC_UNSAFE_MODE;
4029 error_init (error);
4030 MonoClass *param_class = m_class_get_cast_class (klass);
4031 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
4032 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4034 if (*(guint8*)(has_value_field_addr)) {
4035 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
4036 return_val_if_nok (error, NULL);
4037 if (m_class_has_references (param_class))
4038 mono_gc_wbarrier_value_copy (mono_object_unbox (o), value_field_addr, 1, param_class);
4039 else
4040 mono_gc_memmove_atomic (mono_object_unbox (o), value_field_addr, mono_class_value_size (param_class, NULL));
4041 return o;
4043 else
4044 return NULL;
4047 MonoObjectHandle
4048 mono_nullable_box_handle (gpointer buf, MonoClass *klass, MonoError *error)
4050 // FIXMEcoop gpointer buf needs more attention
4051 return MONO_HANDLE_NEW (MonoObject, mono_nullable_box (buf, klass, error));
4055 * mono_get_delegate_invoke:
4056 * \param klass The delegate class
4057 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
4059 MonoMethod *
4060 mono_get_delegate_invoke (MonoClass *klass)
4062 MonoMethod *result;
4063 ERROR_DECL (error);
4064 result = mono_get_delegate_invoke_checked (klass, error);
4065 /* FIXME: better external API that doesn't swallow the error */
4066 mono_error_cleanup (error);
4067 return result;
4071 * mono_get_delegate_invoke_checked:
4072 * \param klass The delegate class
4073 * \param error set on error
4074 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type or not a delegate class.
4076 * Sets \p error on error
4078 MonoMethod *
4079 mono_get_delegate_invoke_checked (MonoClass *klass, MonoError *error)
4081 MONO_REQ_GC_NEUTRAL_MODE;
4083 MonoMethod *im;
4085 /* This is called at runtime, so avoid the slower search in metadata */
4086 mono_class_setup_methods (klass);
4087 if (mono_class_has_failure (klass))
4088 return NULL;
4089 im = mono_class_get_method_from_name_checked (klass, "Invoke", -1, 0, error);
4090 return im;
4094 * mono_get_delegate_begin_invoke:
4095 * \param klass The delegate class
4096 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4098 MonoMethod *
4099 mono_get_delegate_begin_invoke (MonoClass *klass)
4101 MonoMethod *result;
4102 ERROR_DECL (error);
4103 result = mono_get_delegate_begin_invoke_checked (klass, error);
4104 /* FIXME: better external API that doesn't swallow the error */
4105 mono_error_cleanup (error);
4106 return result;
4110 * mono_get_delegate_begin_invoke_checked:
4111 * \param klass The delegate class
4112 * \param error set on error
4113 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type or not a delegate class.
4115 * Sets \p error on error
4117 MonoMethod *
4118 mono_get_delegate_begin_invoke_checked (MonoClass *klass, MonoError *error)
4120 MONO_REQ_GC_NEUTRAL_MODE;
4122 MonoMethod *im;
4124 /* This is called at runtime, so avoid the slower search in metadata */
4125 mono_class_setup_methods (klass);
4126 if (mono_class_has_failure (klass))
4127 return NULL;
4128 im = mono_class_get_method_from_name_checked (klass, "BeginInvoke", -1, 0, error);
4129 return im;
4133 * mono_get_delegate_end_invoke:
4134 * \param klass The delegate class
4135 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4137 MonoMethod *
4138 mono_get_delegate_end_invoke (MonoClass *klass)
4140 MonoMethod *result;
4141 ERROR_DECL (error);
4142 result = mono_get_delegate_end_invoke_checked (klass, error);
4143 /* FIXME: better external API that doesn't swallow the error */
4144 mono_error_cleanup (error);
4145 return result;
4149 * mono_get_delegate_end_invoke_checked:
4150 * \param klass The delegate class
4151 * \param error set on error
4152 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type or not a delegate class.
4154 * Sets \p error on error
4156 MonoMethod *
4157 mono_get_delegate_end_invoke_checked (MonoClass *klass, MonoError *error)
4159 MONO_REQ_GC_NEUTRAL_MODE;
4161 MonoMethod *im;
4163 /* This is called at runtime, so avoid the slower search in metadata */
4164 mono_class_setup_methods (klass);
4165 if (mono_class_has_failure (klass))
4166 return NULL;
4167 im = mono_class_get_method_from_name_checked (klass, "EndInvoke", -1, 0, error);
4168 return im;
4172 * mono_runtime_delegate_invoke:
4173 * \param delegate pointer to a delegate object.
4174 * \param params parameters for the delegate.
4175 * \param exc Pointer to the exception result.
4177 * Invokes the delegate method \p delegate with the parameters provided.
4179 * You can pass NULL as the \p exc argument if you don't want to
4180 * catch exceptions, otherwise, \c *exc will be set to the exception
4181 * thrown, if any. if an exception is thrown, you can't use the
4182 * \c MonoObject* result from the function.
4184 MonoObject*
4185 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4187 MONO_REQ_GC_UNSAFE_MODE;
4189 ERROR_DECL (error);
4190 if (exc) {
4191 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, error);
4192 if (*exc) {
4193 mono_error_cleanup (error);
4194 return NULL;
4195 } else {
4196 if (!is_ok (error))
4197 *exc = (MonoObject*)mono_error_convert_to_exception (error);
4198 return result;
4200 } else {
4201 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, error);
4202 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
4203 return result;
4208 * mono_runtime_delegate_try_invoke:
4209 * \param delegate pointer to a delegate object.
4210 * \param params parameters for the delegate.
4211 * \param exc Pointer to the exception result.
4212 * \param error set on error
4213 * Invokes the delegate method \p delegate with the parameters provided.
4215 * You can pass NULL as the \p exc argument if you don't want to
4216 * catch exceptions, otherwise, \c *exc will be set to the exception
4217 * thrown, if any. On failure to execute, \p error will be set.
4218 * if an exception is thrown, you can't use the
4219 * \c MonoObject* result from the function.
4221 MonoObject*
4222 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4224 MONO_REQ_GC_UNSAFE_MODE;
4226 error_init (error);
4227 MonoMethod *im;
4228 MonoClass *klass = delegate->vtable->klass;
4229 MonoObject *o;
4231 im = mono_get_delegate_invoke (klass);
4232 g_assertf (im, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4234 if (exc) {
4235 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4236 } else {
4237 o = mono_runtime_invoke_checked (im, delegate, params, error);
4240 return o;
4243 static MonoObjectHandle
4244 mono_runtime_delegate_try_invoke_handle (MonoObjectHandle delegate, void **params, MonoError *error)
4246 MONO_REQ_GC_UNSAFE_MODE;
4248 MonoClass* const klass = MONO_HANDLE_GETVAL (delegate, vtable)->klass;
4249 MonoMethod* const im = mono_get_delegate_invoke (klass);
4250 g_assertf (im, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4252 return mono_runtime_try_invoke_handle (im, delegate, params, error);
4256 * mono_runtime_delegate_invoke_checked:
4257 * \param delegate pointer to a delegate object.
4258 * \param params parameters for the delegate.
4259 * \param error set on error
4260 * Invokes the delegate method \p delegate with the parameters provided.
4261 * On failure \p error will be set and you can't use the \c MonoObject*
4262 * result from the function.
4264 MonoObject*
4265 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4267 error_init (error);
4268 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4271 static char **main_args = NULL;
4272 static int num_main_args = 0;
4275 * mono_runtime_get_main_args:
4276 * \returns A \c MonoArray with the arguments passed to the main program
4278 MonoArray*
4279 mono_runtime_get_main_args (void)
4281 HANDLE_FUNCTION_ENTER ();
4282 MONO_REQ_GC_UNSAFE_MODE;
4283 ERROR_DECL (error);
4284 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
4285 error_init (error);
4286 MonoArrayHandle arg_array = mono_runtime_get_main_args_handle (error);
4287 goto_if_nok (error, leave);
4288 MONO_HANDLE_ASSIGN (result, arg_array);
4289 leave:
4290 /* FIXME: better external API that doesn't swallow the error */
4291 mono_error_cleanup (error);
4292 HANDLE_FUNCTION_RETURN_OBJ (result);
4295 static gboolean
4296 handle_main_arg_array_set (MonoDomain *domain, int idx, MonoArrayHandle dest, MonoError *error)
4298 HANDLE_FUNCTION_ENTER ();
4299 error_init (error);
4300 MonoStringHandle value = mono_string_new_handle (domain, main_args [idx], error);
4301 goto_if_nok (error, leave);
4302 MONO_HANDLE_ARRAY_SETREF (dest, idx, value);
4303 leave:
4304 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
4308 * mono_runtime_get_main_args_handle:
4309 * \param error set on error
4310 * \returns a \c MonoArray with the arguments passed to the main
4311 * program. On failure returns NULL and sets \p error.
4313 MonoArrayHandle
4314 mono_runtime_get_main_args_handle (MonoError *error)
4316 HANDLE_FUNCTION_ENTER ();
4317 MonoArrayHandle array;
4318 int i;
4319 MonoDomain *domain = mono_domain_get ();
4320 error_init (error);
4322 array = mono_array_new_handle (domain, mono_defaults.string_class, num_main_args, error);
4323 if (!is_ok (error)) {
4324 array = MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
4325 goto leave;
4327 for (i = 0; i < num_main_args; ++i) {
4328 if (!handle_main_arg_array_set (domain, i, array, error))
4329 goto leave;
4331 leave:
4332 HANDLE_FUNCTION_RETURN_REF (MonoArray, array);
4335 static void
4336 free_main_args (void)
4338 MONO_REQ_GC_NEUTRAL_MODE;
4340 int i;
4342 for (i = 0; i < num_main_args; ++i)
4343 g_free (main_args [i]);
4344 g_free (main_args);
4345 num_main_args = 0;
4346 main_args = NULL;
4350 * mono_runtime_set_main_args:
4351 * \param argc number of arguments from the command line
4352 * \param argv array of strings from the command line
4353 * Set the command line arguments from an embedding application that doesn't otherwise call
4354 * \c mono_runtime_run_main.
4357 mono_runtime_set_main_args (int argc, char* argv[])
4359 MONO_REQ_GC_NEUTRAL_MODE;
4361 int i;
4363 free_main_args ();
4364 main_args = g_new0 (char*, argc);
4365 num_main_args = argc;
4367 for (i = 0; i < argc; ++i) {
4368 gchar *utf8_arg;
4370 utf8_arg = mono_utf8_from_external (argv[i]);
4371 if (utf8_arg == NULL) {
4372 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4373 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4374 exit (-1);
4377 main_args [i] = utf8_arg;
4380 return 0;
4384 * Prepare an array of arguments in order to execute a standard Main()
4385 * method (argc/argv contains the executable name). This method also
4386 * sets the command line argument value needed by System.Environment.
4389 static MonoArray*
4390 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4392 MONO_REQ_GC_UNSAFE_MODE;
4394 ERROR_DECL (error);
4395 int i;
4396 MonoArray *args = NULL;
4397 MonoDomain *domain = mono_domain_get ();
4398 gchar *utf8_fullpath;
4399 MonoMethodSignature *sig;
4401 g_assert (method != NULL);
4403 mono_thread_set_main (mono_thread_current ());
4405 main_args = g_new0 (char*, argc);
4406 num_main_args = argc;
4408 if (!g_path_is_absolute (argv [0])) {
4409 gchar *basename = g_path_get_basename (argv [0]);
4410 gchar *fullpath = g_build_filename (m_class_get_image (method->klass)->assembly->basedir,
4411 basename,
4412 NULL);
4414 utf8_fullpath = mono_utf8_from_external (fullpath);
4415 if(utf8_fullpath == NULL) {
4416 /* Printing the arg text will cause glib to
4417 * whinge about "Invalid UTF-8", but at least
4418 * its relevant, and shows the problem text
4419 * string.
4421 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4422 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4423 exit (-1);
4426 g_free (fullpath);
4427 g_free (basename);
4428 } else {
4429 utf8_fullpath = mono_utf8_from_external (argv[0]);
4430 if(utf8_fullpath == NULL) {
4431 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4432 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4433 exit (-1);
4437 main_args [0] = utf8_fullpath;
4439 for (i = 1; i < argc; ++i) {
4440 gchar *utf8_arg;
4442 utf8_arg=mono_utf8_from_external (argv[i]);
4443 if(utf8_arg==NULL) {
4444 /* Ditto the comment about Invalid UTF-8 here */
4445 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4446 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4447 exit (-1);
4450 main_args [i] = utf8_arg;
4452 argc--;
4453 argv++;
4455 sig = mono_method_signature (method);
4456 if (!sig) {
4457 g_print ("Unable to load Main method.\n");
4458 exit (-1);
4461 if (sig->param_count) {
4462 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, error);
4463 mono_error_assert_ok (error);
4464 for (i = 0; i < argc; ++i) {
4465 /* The encodings should all work, given that
4466 * we've checked all these args for the
4467 * main_args array.
4469 gchar *str = mono_utf8_from_external (argv [i]);
4470 MonoString *arg = mono_string_new_checked (domain, str, error);
4471 mono_error_assert_ok (error);
4472 mono_array_setref (args, i, arg);
4473 g_free (str);
4475 } else {
4476 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, error);
4477 mono_error_assert_ok (error);
4480 mono_assembly_set_main (m_class_get_image (method->klass)->assembly);
4482 return args;
4486 * mono_runtime_run_main:
4487 * \param method the method to start the application with (usually <code>Main</code>)
4488 * \param argc number of arguments from the command line
4489 * \param argv array of strings from the command line
4490 * \param exc excetption results
4491 * Execute a standard \c Main method (\p argc / \p argv contains the
4492 * executable name). This method also sets the command line argument value
4493 * needed by \c System.Environment.
4496 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4497 MonoObject **exc)
4499 MONO_REQ_GC_UNSAFE_MODE;
4501 ERROR_DECL (error);
4502 MonoArray *args = prepare_run_main (method, argc, argv);
4503 int res;
4504 if (exc) {
4505 res = mono_runtime_try_exec_main (method, args, exc);
4506 } else {
4507 res = mono_runtime_exec_main_checked (method, args, error);
4508 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a better alternative */
4510 return res;
4514 * mono_runtime_run_main_checked:
4515 * \param method the method to start the application with (usually \c Main)
4516 * \param argc number of arguments from the command line
4517 * \param argv array of strings from the command line
4518 * \param error set on error
4520 * Execute a standard \c Main method (\p argc / \p argv contains the
4521 * executable name). This method also sets the command line argument value
4522 * needed by \c System.Environment. On failure sets \p error.
4525 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4526 MonoError *error)
4528 error_init (error);
4529 MonoArray *args = prepare_run_main (method, argc, argv);
4530 return mono_runtime_exec_main_checked (method, args, error);
4534 * mono_runtime_try_run_main:
4535 * \param method the method to start the application with (usually \c Main)
4536 * \param argc number of arguments from the command line
4537 * \param argv array of strings from the command line
4538 * \param exc set if \c Main throws an exception
4539 * \param error set if \c Main can't be executed
4540 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4541 * name). This method also sets the command line argument value needed
4542 * by \c System.Environment. On failure sets \p error if Main can't be
4543 * executed or \p exc if it threw an exception.
4546 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4547 MonoObject **exc)
4549 g_assert (exc);
4550 MonoArray *args = prepare_run_main (method, argc, argv);
4551 return mono_runtime_try_exec_main (method, args, exc);
4554 MonoObjectHandle
4555 mono_new_null (void) // A code size optimization (source and object).
4557 return MONO_HANDLE_NEW (MonoObject, NULL);
4560 static MonoObjectHandle
4561 serialize_or_deserialize_object (MonoObjectHandle obj, const gchar *method_name, MonoMethod **method, MonoError *error)
4563 if (!*method) {
4564 MonoClass *klass = mono_class_get_remoting_services_class ();
4565 *method = mono_class_get_method_from_name_checked (klass, method_name, -1, 0, error);
4566 return_val_if_nok (error, mono_new_null ());
4569 if (!*method) {
4570 mono_error_set_exception_instance (error, NULL);
4571 return mono_new_null ();
4574 void *params [ ] = { MONO_HANDLE_RAW (obj) };
4575 return mono_runtime_try_invoke_handle (*method, NULL_HANDLE, params, error);
4578 static MonoMethod *serialize_method;
4580 static MonoObjectHandle
4581 serialize_object (MonoObjectHandle obj, MonoError *error)
4583 g_assert (!mono_class_is_marshalbyref (mono_handle_class (obj)));
4584 return serialize_or_deserialize_object (obj, "SerializeCallData", &serialize_method, error);
4587 static MonoMethod *deserialize_method;
4589 static MonoObjectHandle
4590 deserialize_object (MonoObjectHandle obj, MonoError *error)
4592 MONO_REQ_GC_UNSAFE_MODE;
4593 return serialize_or_deserialize_object (obj, "DeserializeCallData", &deserialize_method, error);
4596 #ifndef DISABLE_REMOTING
4597 static MonoObjectHandle
4598 make_transparent_proxy (MonoObjectHandle obj, MonoError *error)
4600 MONO_REQ_GC_UNSAFE_MODE;
4602 static MonoMethod *get_proxy_method;
4604 if (!get_proxy_method) {
4605 get_proxy_method = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "GetTransparentProxy", 0, 0, error);
4606 mono_error_assert_ok (error);
4609 g_assert (mono_class_is_marshalbyref (MONO_HANDLE_GETVAL (obj, vtable)->klass));
4611 MonoDomain *domain = mono_domain_get ();
4612 MonoRealProxyHandle real_proxy = MONO_HANDLE_CAST (MonoRealProxy, mono_object_new_handle (domain, mono_defaults.real_proxy_class, error));
4613 goto_if_nok (error, return_null);
4614 MonoReflectionTypeHandle reflection_type;
4615 reflection_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (mono_handle_class (obj)), error);
4616 goto_if_nok (error, return_null);
4618 MONO_HANDLE_SET (real_proxy, class_to_proxy, reflection_type);
4619 MONO_HANDLE_SET (real_proxy, unwrapped_server, obj);
4621 return mono_runtime_try_invoke_handle (get_proxy_method, MONO_HANDLE_CAST (MonoObject, real_proxy), NULL, error);
4622 return_null:
4623 return mono_new_null ();
4625 #endif /* DISABLE_REMOTING */
4628 * mono_object_xdomain_representation
4629 * \param obj an object
4630 * \param target_domain a domain
4631 * \param error set on error.
4632 * Creates a representation of obj in the domain \p target_domain. This
4633 * is either a copy of \p obj arrived through via serialization and
4634 * deserialization or a proxy, depending on whether the object is
4635 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4636 * If the object cannot be represented in \p target_domain, NULL is
4637 * returned and \p error is set appropriately.
4639 MonoObjectHandle
4640 mono_object_xdomain_representation (MonoObjectHandle obj, MonoDomain *target_domain, MonoError *error)
4642 HANDLE_FUNCTION_ENTER ();
4644 MONO_REQ_GC_UNSAFE_MODE;
4646 MonoObjectHandle deserialized;
4648 #ifndef DISABLE_REMOTING
4649 if (mono_class_is_marshalbyref (mono_handle_class (obj))) {
4650 deserialized = make_transparent_proxy (obj, error);
4652 else
4653 #endif
4655 MonoDomain *domain = mono_domain_get ();
4657 mono_domain_set_internal_with_options (MONO_HANDLE_DOMAIN (obj), FALSE);
4658 MonoObjectHandle serialized = serialize_object (obj, error);
4659 mono_domain_set_internal_with_options (target_domain, FALSE);
4660 if (is_ok (error))
4661 deserialized = deserialize_object (serialized, error);
4662 else
4663 deserialized = mono_new_null ();
4665 if (domain != target_domain)
4666 mono_domain_set_internal_with_options (domain, FALSE);
4669 HANDLE_FUNCTION_RETURN_REF (MonoObject, deserialized);
4672 /* Used in call_unhandled_exception_delegate */
4673 static MonoObjectHandle
4674 create_unhandled_exception_eventargs (MonoObjectHandle exc, MonoError *error)
4676 MONO_REQ_GC_UNSAFE_MODE;
4678 MonoClass * const klass = mono_class_get_unhandled_exception_event_args_class ();
4679 mono_class_init (klass);
4681 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4682 MonoMethod * const method = mono_class_get_method_from_name_checked (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC, error);
4683 goto_if_nok (error, return_null);
4684 g_assert (method);
4686 MonoBoolean is_terminating;
4687 is_terminating = TRUE;
4688 gpointer args [2];
4689 args [0] = MONO_HANDLE_RAW (exc); // FIXMEcoop
4690 args [1] = &is_terminating;
4692 MonoObjectHandle obj;
4693 obj = mono_object_new_handle (mono_domain_get (), klass, error);
4694 goto_if_nok (error, return_null);
4696 mono_runtime_invoke_handle (method, obj, args, error);
4697 goto_if_nok (error, return_null);
4698 return obj;
4700 return_null:
4701 return MONO_HANDLE_NEW (MonoObject, NULL);
4704 /* Used in mono_unhandled_exception */
4705 static void
4706 call_unhandled_exception_delegate (MonoDomain *domain, MonoObjectHandle delegate, MonoObjectHandle exc)
4708 MONO_REQ_GC_UNSAFE_MODE;
4710 ERROR_DECL (error);
4711 MonoDomain *current_domain = mono_domain_get ();
4713 if (domain != current_domain)
4714 mono_domain_set_internal_with_options (domain, FALSE);
4716 g_assert (domain == mono_object_domain (domain->domain));
4718 if (MONO_HANDLE_DOMAIN (exc) != domain) {
4720 exc = mono_object_xdomain_representation (exc, domain, error);
4721 if (MONO_HANDLE_IS_NULL (exc)) {
4722 ERROR_DECL (inner_error);
4723 if (!is_ok (error)) {
4724 MonoExceptionHandle serialization_exc = mono_error_convert_to_exception_handle (error);
4725 exc = mono_object_xdomain_representation (MONO_HANDLE_CAST (MonoObject, serialization_exc), domain, inner_error);
4726 } else {
4727 exc = MONO_HANDLE_CAST (MonoObject, mono_exception_new_serialization ("Could not serialize unhandled exception.", inner_error));
4729 mono_error_assert_ok (inner_error);
4732 g_assert (MONO_HANDLE_DOMAIN (exc) == domain);
4734 gpointer pa [ ] = {
4735 domain->domain,
4736 MONO_HANDLE_RAW (create_unhandled_exception_eventargs (exc, error)) // FIXMEcoop
4738 mono_error_assert_ok (error);
4739 mono_runtime_delegate_try_invoke_handle (delegate, pa, error);
4741 if (domain != current_domain)
4742 mono_domain_set_internal_with_options (current_domain, FALSE);
4744 if (!is_ok (error)) {
4745 g_warning ("exception inside UnhandledException handler: %s\n", mono_error_get_message (error));
4746 mono_error_cleanup (error);
4750 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4753 * mono_runtime_unhandled_exception_policy_set:
4754 * \param policy the new policy
4755 * This is a VM internal routine.
4756 * Sets the runtime policy for handling unhandled exceptions.
4758 void
4759 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy)
4761 runtime_unhandled_exception_policy = policy;
4765 * mono_runtime_unhandled_exception_policy_get:
4767 * This is a VM internal routine.
4769 * Gets the runtime policy for handling unhandled exceptions.
4771 MonoRuntimeUnhandledExceptionPolicy
4772 mono_runtime_unhandled_exception_policy_get (void)
4774 return runtime_unhandled_exception_policy;
4778 * mono_unhandled_exception:
4779 * \param exc exception thrown
4780 * This is a VM internal routine.
4782 * We call this function when we detect an unhandled exception
4783 * in the default domain.
4785 * It invokes the \c UnhandledException event in \c AppDomain or prints
4786 * a warning to the console
4788 void
4789 mono_unhandled_exception (MonoObject *exc_raw)
4791 ERROR_DECL (error);
4792 HANDLE_FUNCTION_ENTER ();
4793 MONO_HANDLE_DCL (MonoObject, exc);
4794 mono_unhandled_exception_checked (exc, error);
4795 mono_error_assert_ok (error);
4796 HANDLE_FUNCTION_RETURN ();
4800 * mono_unhandled_exception:
4801 * @exc: exception thrown
4803 * This is a VM internal routine.
4805 * We call this function when we detect an unhandled exception
4806 * in the default domain.
4808 * It invokes the * UnhandledException event in AppDomain or prints
4809 * a warning to the console
4811 void
4812 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4814 MONO_REQ_GC_UNSAFE_MODE;
4816 MonoClassField *field;
4817 MonoDomain *current_domain, *root_domain;
4818 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4820 MonoClass *klass = mono_handle_class (exc);
4822 * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
4823 * a thread started in unmanaged world.
4824 * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
4826 if (klass == mono_defaults.threadabortexception_class ||
4827 (klass == mono_class_get_appdomain_unloaded_exception_class () &&
4828 mono_thread_info_current ()->runtime_thread))
4829 return;
4831 field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "UnhandledException", NULL);
4832 g_assert (field);
4834 current_domain = mono_domain_get ();
4835 root_domain = mono_get_root_domain ();
4837 MonoObjectHandle root_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, error)); /* FIXME use handles for mono_field_get_value_object_checked */
4838 return_if_nok (error);
4839 if (current_domain != root_domain) {
4840 MONO_HANDLE_ASSIGN (current_appdomain_delegate, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, error))); /* FIXME use handles for mono_field_get_value_object_checked */
4841 return_if_nok (error);
4844 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4845 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4846 } else {
4847 /* unhandled exception callbacks must not be aborted */
4848 mono_threads_begin_abort_protected_block ();
4849 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4850 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4851 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4852 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4853 mono_threads_end_abort_protected_block ();
4856 /* set exitcode only if we will abort the process */
4857 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4858 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4860 mono_environment_exitcode_set (1);
4865 * mono_runtime_exec_managed_code:
4866 * \param domain Application domain
4867 * \param main_func function to invoke from the execution thread
4868 * \param main_args parameter to the main_func
4869 * Launch a new thread to execute a function
4871 * \p main_func is called back from the thread with main_args as the
4872 * parameter. The callback function is expected to start \c Main
4873 * eventually. This function then waits for all managed threads to
4874 * finish.
4875 * It is not necessary anymore to execute managed code in a subthread,
4876 * so this function should not be used anymore by default: just
4877 * execute the code and then call mono_thread_manage().
4879 void
4880 mono_runtime_exec_managed_code (MonoDomain *domain,
4881 MonoMainThreadFunc main_func,
4882 gpointer main_args)
4884 ERROR_DECL (error);
4885 mono_thread_create_checked (domain, main_func, main_args, error);
4886 mono_error_assert_ok (error);
4888 mono_thread_manage ();
4891 static void
4892 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4894 MONO_REQ_GC_UNSAFE_MODE;
4895 MonoInternalThread* thread = mono_thread_internal_current ();
4896 MonoCustomAttrInfo* cinfo;
4897 gboolean has_stathread_attribute;
4899 if (!domain->entry_assembly) {
4900 gchar *str;
4901 ERROR_DECL (error);
4902 MonoAssembly *assembly;
4904 assembly = m_class_get_image (method->klass)->assembly;
4905 domain->entry_assembly = assembly;
4906 /* Domains created from another domain already have application_base and configuration_file set */
4907 if (domain->setup->application_base == NULL) {
4908 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, error);
4909 mono_error_assert_ok (error);
4910 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4913 if (domain->setup->configuration_file == NULL) {
4914 str = g_strconcat (assembly->image->name, ".config", NULL);
4915 MonoString *config_file = mono_string_new_checked (domain, str, error);
4916 mono_error_assert_ok (error);
4917 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4918 g_free (str);
4919 mono_domain_set_options_from_config (domain);
4923 ERROR_DECL_VALUE (cattr_error);
4924 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4925 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4926 if (cinfo) {
4927 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4928 if (!cinfo->cached)
4929 mono_custom_attrs_free (cinfo);
4930 } else {
4931 has_stathread_attribute = FALSE;
4933 if (has_stathread_attribute) {
4934 thread->apartment_state = ThreadApartmentState_STA;
4935 } else {
4936 thread->apartment_state = ThreadApartmentState_MTA;
4938 mono_thread_init_apartment_state ();
4942 static int
4943 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4945 MONO_REQ_GC_UNSAFE_MODE;
4947 gpointer pa [1];
4948 int rval;
4950 error_init (error);
4951 g_assert (args);
4953 pa [0] = args;
4955 /* FIXME: check signature of method */
4956 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4957 MonoObject *res;
4958 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4959 if (is_ok (error))
4960 rval = *(guint32 *)(mono_object_get_data (res));
4961 else
4962 rval = -1;
4963 mono_environment_exitcode_set (rval);
4964 } else {
4965 mono_runtime_invoke_checked (method, NULL, pa, error);
4967 if (is_ok (error))
4968 rval = 0;
4969 else {
4970 rval = -1;
4973 return rval;
4976 static int
4977 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4979 MONO_REQ_GC_UNSAFE_MODE;
4981 gpointer pa [1];
4982 int rval;
4984 g_assert (args);
4985 g_assert (exc);
4987 pa [0] = args;
4989 /* FIXME: check signature of method */
4990 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4991 ERROR_DECL_VALUE (inner_error);
4992 MonoObject *res;
4993 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4994 if (*exc == NULL && !mono_error_ok (&inner_error))
4995 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4996 else
4997 mono_error_cleanup (&inner_error);
4999 if (*exc == NULL)
5000 rval = *(guint32 *)(mono_object_get_data (res));
5001 else
5002 rval = -1;
5004 mono_environment_exitcode_set (rval);
5005 } else {
5006 ERROR_DECL_VALUE (inner_error);
5007 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
5008 if (*exc == NULL && !mono_error_ok (&inner_error))
5009 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
5010 else
5011 mono_error_cleanup (&inner_error);
5013 if (*exc == NULL)
5014 rval = 0;
5015 else {
5016 /* If the return type of Main is void, only
5017 * set the exitcode if an exception was thrown
5018 * (we don't want to blow away an
5019 * explicitly-set exit code)
5021 rval = -1;
5022 mono_environment_exitcode_set (rval);
5026 return rval;
5030 * Execute a standard Main() method (args doesn't contain the
5031 * executable name).
5034 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5036 int rval;
5037 MONO_ENTER_GC_UNSAFE;
5038 ERROR_DECL (error);
5039 prepare_thread_to_exec_main (mono_object_domain (args), method);
5040 if (exc) {
5041 rval = do_try_exec_main (method, args, exc);
5042 } else {
5043 rval = do_exec_main_checked (method, args, error);
5044 mono_error_raise_exception_deprecated (error); /* OK to throw, external only with no better option */
5046 MONO_EXIT_GC_UNSAFE;
5047 return rval;
5051 * Execute a standard Main() method (args doesn't contain the
5052 * executable name).
5054 * On failure sets @error
5057 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
5059 error_init (error);
5060 prepare_thread_to_exec_main (mono_object_domain (args), method);
5061 return do_exec_main_checked (method, args, error);
5065 * Execute a standard Main() method (args doesn't contain the
5066 * executable name).
5068 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
5071 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5073 prepare_thread_to_exec_main (mono_object_domain (args), method);
5074 return do_try_exec_main (method, args, exc);
5079 /** invoke_array_extract_argument:
5080 * @params: array of arguments to the method.
5081 * @i: the index of the argument to extract.
5082 * @t: ith type from the method signature.
5083 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
5084 * @error: set on error.
5086 * Given an array of method arguments, return the ith one using the corresponding type
5087 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
5089 * On failure sets @error and returns NULL.
5091 static gpointer
5092 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
5094 MonoType *t_orig = t;
5095 gpointer result = NULL;
5096 error_init (error);
5097 again:
5098 switch (t->type) {
5099 case MONO_TYPE_U1:
5100 case MONO_TYPE_I1:
5101 case MONO_TYPE_BOOLEAN:
5102 case MONO_TYPE_U2:
5103 case MONO_TYPE_I2:
5104 case MONO_TYPE_CHAR:
5105 case MONO_TYPE_U:
5106 case MONO_TYPE_I:
5107 case MONO_TYPE_U4:
5108 case MONO_TYPE_I4:
5109 case MONO_TYPE_U8:
5110 case MONO_TYPE_I8:
5111 case MONO_TYPE_R4:
5112 case MONO_TYPE_R8:
5113 case MONO_TYPE_VALUETYPE:
5114 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
5115 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
5116 result = mono_array_get (params, MonoObject*, i);
5117 if (t->byref)
5118 *has_byref_nullables = TRUE;
5119 } else {
5120 /* MS seems to create the objects if a null is passed in */
5121 gboolean was_null = FALSE;
5122 if (!mono_array_get (params, MonoObject*, i)) {
5123 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
5124 return_val_if_nok (error, NULL);
5125 mono_array_setref (params, i, o);
5126 was_null = TRUE;
5129 if (t->byref) {
5131 * We can't pass the unboxed vtype byref to the callee, since
5132 * that would mean the callee would be able to modify boxed
5133 * primitive types. So we (and MS) make a copy of the boxed
5134 * object, pass that to the callee, and replace the original
5135 * boxed object in the arg array with the copy.
5137 MonoObject *orig = mono_array_get (params, MonoObject*, i);
5138 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
5139 return_val_if_nok (error, NULL);
5140 mono_array_setref (params, i, copy);
5143 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
5144 if (!t->byref && was_null)
5145 mono_array_setref (params, i, NULL);
5147 break;
5148 case MONO_TYPE_STRING:
5149 case MONO_TYPE_OBJECT:
5150 case MONO_TYPE_CLASS:
5151 case MONO_TYPE_ARRAY:
5152 case MONO_TYPE_SZARRAY:
5153 if (t->byref)
5154 result = mono_array_addr (params, MonoObject*, i);
5155 // FIXME: I need to check this code path
5156 else
5157 result = mono_array_get (params, MonoObject*, i);
5158 break;
5159 case MONO_TYPE_GENERICINST:
5160 if (t->byref)
5161 t = m_class_get_this_arg (t->data.generic_class->container_class);
5162 else
5163 t = m_class_get_byval_arg (t->data.generic_class->container_class);
5164 goto again;
5165 case MONO_TYPE_PTR: {
5166 MonoObject *arg;
5168 /* The argument should be an IntPtr */
5169 arg = mono_array_get (params, MonoObject*, i);
5170 if (arg == NULL) {
5171 result = NULL;
5172 } else {
5173 g_assert (arg->vtable->klass == mono_defaults.int_class);
5174 result = ((MonoIntPtr*)arg)->m_value;
5176 break;
5178 default:
5179 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
5181 return result;
5184 * mono_runtime_invoke_array:
5185 * \param method method to invoke
5186 * \param obj object instance
5187 * \param params arguments to the method
5188 * \param exc exception information.
5189 * Invokes the method represented by \p method on the object \p obj.
5191 * \p obj is the \c this pointer, it should be NULL for static
5192 * methods, a \c MonoObject* for object instances and a pointer to
5193 * the value type for value types.
5195 * The \p params array contains the arguments to the method with the
5196 * same convention: \c MonoObject* pointers for object instances and
5197 * pointers to the value type otherwise. The \c _invoke_array
5198 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5199 * in this case the value types are boxed inside the
5200 * respective reference representation.
5202 * From unmanaged code you'll usually use the
5203 * mono_runtime_invoke_checked() variant.
5205 * Note that this function doesn't handle virtual methods for
5206 * you, it will exec the exact method you pass: we still need to
5207 * expose a function to lookup the derived class implementation
5208 * of a virtual method (there are examples of this in the code,
5209 * though).
5211 * You can pass NULL as the \p exc argument if you don't want to
5212 * catch exceptions, otherwise, \c *exc will be set to the exception
5213 * thrown, if any. if an exception is thrown, you can't use the
5214 * \c MonoObject* result from the function.
5216 * If the method returns a value type, it is boxed in an object
5217 * reference.
5219 MonoObject*
5220 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5221 MonoObject **exc)
5223 ERROR_DECL (error);
5224 if (exc) {
5225 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, error);
5226 if (*exc) {
5227 mono_error_cleanup (error);
5228 return NULL;
5229 } else {
5230 if (!is_ok (error))
5231 *exc = (MonoObject*)mono_error_convert_to_exception (error);
5232 return result;
5234 } else {
5235 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5236 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
5237 return result;
5242 * mono_runtime_invoke_array_checked:
5243 * \param method method to invoke
5244 * \param obj object instance
5245 * \param params arguments to the method
5246 * \param error set on failure.
5247 * Invokes the method represented by \p method on the object \p obj.
5249 * \p obj is the \c this pointer, it should be NULL for static
5250 * methods, a \c MonoObject* for object instances and a pointer to
5251 * the value type for value types.
5253 * The \p params array contains the arguments to the method with the
5254 * same convention: \c MonoObject* pointers for object instances and
5255 * pointers to the value type otherwise. The \c _invoke_array
5256 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5257 * in this case the value types are boxed inside the
5258 * respective reference representation.
5260 * From unmanaged code you'll usually use the
5261 * mono_runtime_invoke_checked() variant.
5263 * Note that this function doesn't handle virtual methods for
5264 * you, it will exec the exact method you pass: we still need to
5265 * expose a function to lookup the derived class implementation
5266 * of a virtual method (there are examples of this in the code,
5267 * though).
5269 * On failure or exception, \p error will be set. In that case, you
5270 * can't use the \c MonoObject* result from the function.
5272 * If the method returns a value type, it is boxed in an object
5273 * reference.
5275 MonoObject*
5276 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5277 MonoError *error)
5279 error_init (error);
5280 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5284 * mono_runtime_try_invoke_array:
5285 * \param method method to invoke
5286 * \param obj object instance
5287 * \param params arguments to the method
5288 * \param exc exception information.
5289 * \param error set on failure.
5290 * Invokes the method represented by \p method on the object \p obj.
5292 * \p obj is the \c this pointer, it should be NULL for static
5293 * methods, a \c MonoObject* for object instances and a pointer to
5294 * the value type for value types.
5296 * The \p params array contains the arguments to the method with the
5297 * same convention: \c MonoObject* pointers for object instances and
5298 * pointers to the value type otherwise. The \c _invoke_array
5299 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5300 * in this case the value types are boxed inside the
5301 * respective reference representation.
5303 * From unmanaged code you'll usually use the
5304 * mono_runtime_invoke_checked() variant.
5306 * Note that this function doesn't handle virtual methods for
5307 * you, it will exec the exact method you pass: we still need to
5308 * expose a function to lookup the derived class implementation
5309 * of a virtual method (there are examples of this in the code,
5310 * though).
5312 * You can pass NULL as the \p exc argument if you don't want to catch
5313 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5314 * any. On other failures, \p error will be set. If an exception is
5315 * thrown or there's an error, you can't use the \c MonoObject* result
5316 * from the function.
5318 * If the method returns a value type, it is boxed in an object
5319 * reference.
5321 MonoObject*
5322 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5323 MonoObject **exc, MonoError *error)
5325 MONO_REQ_GC_UNSAFE_MODE;
5327 error_init (error);
5329 MonoMethodSignature *sig = mono_method_signature (method);
5330 gpointer *pa = NULL;
5331 MonoObject *res;
5332 int i;
5333 gboolean has_byref_nullables = FALSE;
5335 if (NULL != params) {
5336 pa = g_newa (gpointer, mono_array_length (params));
5337 for (i = 0; i < mono_array_length (params); i++) {
5338 MonoType *t = sig->params [i];
5339 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5340 return_val_if_nok (error, NULL);
5344 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5345 void *o = obj;
5347 if (mono_class_is_nullable (method->klass)) {
5348 /* Need to create a boxed vtype instead */
5349 g_assert (!obj);
5351 if (!params)
5352 return NULL;
5353 else {
5354 return mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method->klass), pa [0], error);
5358 if (!obj) {
5359 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5360 mono_error_assert_ok (error);
5361 g_assert (obj); /*maybe we should raise a TLE instead?*/
5362 #ifndef DISABLE_REMOTING
5363 if (mono_object_is_transparent_proxy (obj)) {
5364 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : m_class_get_vtable (method->klass) [method->slot], error);
5365 return_val_if_nok (error, NULL);
5367 #endif
5368 if (m_class_is_valuetype (method->klass))
5369 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5370 else
5371 o = obj;
5372 } else if (m_class_is_valuetype (method->klass)) {
5373 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5374 return_val_if_nok (error, NULL);
5377 if (exc) {
5378 mono_runtime_try_invoke (method, o, pa, exc, error);
5379 } else {
5380 mono_runtime_invoke_checked (method, o, pa, error);
5383 return (MonoObject *)obj;
5384 } else {
5385 if (mono_class_is_nullable (method->klass)) {
5386 MonoObject *nullable;
5388 /* Convert the unboxed vtype into a Nullable structure */
5389 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5390 return_val_if_nok (error, NULL);
5392 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method->klass), obj, error);
5393 return_val_if_nok (error, NULL);
5394 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5395 obj = mono_object_unbox (nullable);
5398 /* obj must be already unboxed if needed */
5399 if (exc) {
5400 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5401 } else {
5402 res = mono_runtime_invoke_checked (method, obj, pa, error);
5404 return_val_if_nok (error, NULL);
5406 if (sig->ret->type == MONO_TYPE_PTR) {
5407 MonoClass *pointer_class;
5408 static MonoMethod *box_method;
5409 void *box_args [2];
5410 MonoObject *box_exc;
5413 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5414 * convert it to a Pointer object.
5416 pointer_class = mono_class_get_pointer_class ();
5417 if (!box_method) {
5418 box_method = mono_class_get_method_from_name_checked (pointer_class, "Box", -1, 0, error);
5419 mono_error_assert_ok (error);
5422 g_assert (res->vtable->klass == mono_defaults.int_class);
5423 box_args [0] = ((MonoIntPtr*)res)->m_value;
5424 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5425 return_val_if_nok (error, NULL);
5427 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5428 g_assert (box_exc == NULL);
5429 mono_error_assert_ok (error);
5432 if (has_byref_nullables) {
5434 * The runtime invoke wrapper already converted byref nullables back,
5435 * and stored them in pa, we just need to copy them back to the
5436 * managed array.
5438 for (i = 0; i < mono_array_length (params); i++) {
5439 MonoType *t = sig->params [i];
5441 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5442 mono_array_setref (params, i, pa [i]);
5446 return res;
5450 // FIXME these will move to header soon
5451 static MonoObjectHandle
5452 mono_object_new_by_vtable (MonoVTable *vtable, MonoError *error);
5455 * object_new_common_tail:
5457 * This function centralizes post-processing of objects upon creation.
5458 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields,
5459 * and setting error.
5461 static MonoObject*
5462 object_new_common_tail (MonoObject *o, MonoClass *klass, MonoError *error)
5464 error_init (error);
5466 if (G_UNLIKELY (!o)) {
5467 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (klass));
5468 return o;
5471 if (G_UNLIKELY (m_class_has_finalize (klass)))
5472 mono_object_register_finalizer (o);
5474 if (G_UNLIKELY (m_class_has_weak_fields (klass)))
5475 mono_gc_register_obj_with_weak_fields (o);
5477 return o;
5481 * object_new_handle_tail:
5483 * This function centralizes post-processing of objects upon creation.
5484 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields.
5486 static MonoObjectHandle
5487 object_new_handle_common_tail (MonoObjectHandle o, MonoClass *klass, MonoError *error)
5489 error_init (error);
5491 if (G_UNLIKELY (MONO_HANDLE_IS_NULL (o))) {
5492 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (klass));
5493 return o;
5496 if (G_UNLIKELY (m_class_has_finalize (klass)))
5497 mono_object_register_finalizer_handle (o);
5499 if (G_UNLIKELY (m_class_has_weak_fields (klass)))
5500 mono_gc_register_object_with_weak_fields (o);
5502 return o;
5506 * mono_object_new:
5507 * \param klass the class of the object that we want to create
5508 * \returns a newly created object whose definition is
5509 * looked up using \p klass. This will not invoke any constructors,
5510 * so the consumer of this routine has to invoke any constructors on
5511 * its own to initialize the object.
5513 * It returns NULL on failure.
5515 MonoObject *
5516 mono_object_new (MonoDomain *domain, MonoClass *klass)
5518 MonoObject * result;
5519 MONO_ENTER_GC_UNSAFE;
5520 ERROR_DECL (error);
5521 result = mono_object_new_checked (domain, klass, error);
5522 mono_error_cleanup (error);
5523 MONO_EXIT_GC_UNSAFE;
5524 return result;
5527 MonoObject *
5528 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5530 MONO_REQ_GC_UNSAFE_MODE;
5532 ERROR_DECL (error);
5534 MonoObject * result = mono_object_new_checked (domain, klass, error);
5536 mono_error_set_pending_exception (error);
5537 return result;
5541 * mono_object_new_checked:
5542 * \param klass the class of the object that we want to create
5543 * \param error set on error
5544 * \returns a newly created object whose definition is
5545 * looked up using \p klass. This will not invoke any constructors,
5546 * so the consumer of this routine has to invoke any constructors on
5547 * its own to initialize the object.
5549 * It returns NULL on failure and sets \p error.
5551 MonoObject *
5552 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5554 MONO_REQ_GC_UNSAFE_MODE;
5556 MonoVTable *vtable;
5558 vtable = mono_class_vtable_checked (domain, klass, error);
5559 if (!is_ok (error))
5560 return NULL;
5562 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5563 return o;
5567 * mono_object_new_handle:
5568 * \param klass the class of the object that we want to create
5569 * \param error set on error
5570 * \returns a newly created object whose definition is
5571 * looked up using \p klass. This will not invoke any constructors,
5572 * so the consumer of this routine has to invoke any constructors on
5573 * its own to initialize the object.
5575 * It returns NULL on failure and sets \p error.
5577 MonoObjectHandle
5578 mono_object_new_handle (MonoDomain *domain, MonoClass *klass, MonoError *error)
5580 MONO_REQ_GC_UNSAFE_MODE;
5582 MonoVTable* const vtable = mono_class_vtable_checked (domain, klass, error);
5584 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5586 return mono_object_new_by_vtable (vtable, error);
5590 * mono_object_new_pinned:
5592 * Same as mono_object_new, but the returned object will be pinned.
5593 * For SGEN, these objects will only be freed at appdomain unload.
5595 MonoObjectHandle
5596 mono_object_new_pinned_handle (MonoDomain *domain, MonoClass *klass, MonoError *error)
5598 MONO_REQ_GC_UNSAFE_MODE;
5600 MonoVTable* const vtable = mono_class_vtable_checked (domain, klass, error);
5601 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5603 g_assert (vtable->klass == klass);
5605 int const size = mono_class_instance_size (klass);
5607 MonoObjectHandle o = mono_gc_alloc_handle_pinned_obj (vtable, size);
5609 return object_new_handle_common_tail (o, klass, error);
5612 MonoObject *
5613 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5615 MONO_REQ_GC_UNSAFE_MODE;
5617 MonoVTable *vtable;
5619 vtable = mono_class_vtable_checked (domain, klass, error);
5620 return_val_if_nok (error, NULL);
5622 MonoObject *o = mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5624 return object_new_common_tail (o, klass, error);
5628 * mono_object_new_specific:
5629 * \param vtable the vtable of the object that we want to create
5630 * \returns A newly created object with class and domain specified
5631 * by \p vtable
5633 MonoObject *
5634 mono_object_new_specific (MonoVTable *vtable)
5636 ERROR_DECL (error);
5637 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5638 mono_error_cleanup (error);
5640 return o;
5643 MonoObject *
5644 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5646 MONO_REQ_GC_UNSAFE_MODE;
5648 MonoObject *o;
5650 error_init (error);
5652 /* check for is_com_object for COM Interop */
5653 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5655 gpointer pa [1];
5656 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5658 if (im == NULL) {
5659 MonoClass *klass = mono_class_get_activation_services_class ();
5661 if (!m_class_is_inited (klass))
5662 mono_class_init (klass);
5664 im = mono_class_get_method_from_name_checked (klass, "CreateProxyForType", 1, 0, error);
5665 return_val_if_nok (error, NULL);
5666 if (!im) {
5667 mono_error_set_not_supported (error, "Linked away.");
5668 return NULL;
5670 vtable->domain->create_proxy_for_type_method = im;
5673 pa [0] = mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable->klass), error);
5674 if (!mono_error_ok (error))
5675 return NULL;
5677 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5678 if (!mono_error_ok (error))
5679 return NULL;
5681 if (o != NULL)
5682 return o;
5685 return mono_object_new_alloc_specific_checked (vtable, error);
5688 static MonoObjectHandle
5689 mono_object_new_by_vtable (MonoVTable *vtable, MonoError *error)
5691 // This function handles remoting and COM.
5692 // mono_object_new_alloc_by_vtable does not.
5694 MONO_REQ_GC_UNSAFE_MODE;
5696 MonoObjectHandle o = MONO_HANDLE_NEW (MonoObject, NULL);
5698 error_init (error);
5700 /* check for is_com_object for COM Interop */
5701 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5703 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5705 if (im == NULL) {
5706 MonoClass *klass = mono_class_get_activation_services_class ();
5708 if (!m_class_is_inited (klass))
5709 mono_class_init (klass);
5711 im = mono_class_get_method_from_name_checked (klass, "CreateProxyForType", 1, 0, error);
5712 return_val_if_nok (error, mono_new_null ());
5713 if (!im) {
5714 mono_error_set_not_supported (error, "Linked away.");
5715 return MONO_HANDLE_NEW (MonoObject, NULL);
5717 vtable->domain->create_proxy_for_type_method = im;
5720 // FIXMEcoop
5721 gpointer pa[ ] = { mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable->klass), error) };
5722 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5724 // FIXMEcoop
5725 o = MONO_HANDLE_NEW (MonoObject, mono_runtime_invoke_checked (im, NULL, pa, error));
5726 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5728 if (!MONO_HANDLE_IS_NULL (o))
5729 return o;
5732 return mono_object_new_alloc_by_vtable (vtable, error);
5735 MonoObject *
5736 ves_icall_object_new_specific (MonoVTable *vtable)
5738 ERROR_DECL (error);
5739 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5740 mono_error_set_pending_exception (error);
5742 return o;
5746 * mono_object_new_alloc_specific:
5747 * \param vtable virtual table for the object.
5748 * This function allocates a new \c MonoObject with the type derived
5749 * from the \p vtable information. If the class of this object has a
5750 * finalizer, then the object will be tracked for finalization.
5752 * This method might raise an exception on errors. Use the
5753 * \c mono_object_new_fast_checked method if you want to manually raise
5754 * the exception.
5756 * \returns the allocated object.
5758 MonoObject *
5759 mono_object_new_alloc_specific (MonoVTable *vtable)
5761 ERROR_DECL (error);
5762 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, error);
5763 mono_error_cleanup (error);
5765 return o;
5769 * mono_object_new_alloc_specific_checked:
5770 * \param vtable virtual table for the object.
5771 * \param error holds the error return value.
5773 * This function allocates a new \c MonoObject with the type derived
5774 * from the \p vtable information. If the class of this object has a
5775 * finalizer, then the object will be tracked for finalization.
5777 * If there is not enough memory, the \p error parameter will be set
5778 * and will contain a user-visible message with the amount of bytes
5779 * that were requested.
5781 * \returns the allocated object, or NULL if there is not enough memory
5783 MonoObject *
5784 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5786 MONO_REQ_GC_UNSAFE_MODE;
5788 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5790 return object_new_common_tail (o, vtable->klass, error);
5793 MonoObjectHandle
5794 mono_object_new_alloc_by_vtable (MonoVTable *vtable, MonoError *error)
5796 MONO_REQ_GC_UNSAFE_MODE;
5798 MonoClass* const klass = vtable->klass;
5799 int const size = m_class_get_instance_size (klass);
5801 MonoObjectHandle o = mono_gc_alloc_handle_obj (vtable, size);
5803 return object_new_handle_common_tail (o, klass, error);
5807 * mono_object_new_fast:
5808 * \param vtable virtual table for the object.
5810 * This function allocates a new \c MonoObject with the type derived
5811 * from the \p vtable information. The returned object is not tracked
5812 * for finalization. If your object implements a finalizer, you should
5813 * use \c mono_object_new_alloc_specific instead.
5815 * This method might raise an exception on errors. Use the
5816 * \c mono_object_new_fast_checked method if you want to manually raise
5817 * the exception.
5819 * \returns the allocated object.
5821 MonoObject*
5822 mono_object_new_fast (MonoVTable *vtable)
5824 ERROR_DECL (error);
5826 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5828 // This deliberately skips object_new_common_tail.
5830 if (G_UNLIKELY (!o))
5831 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
5833 mono_error_cleanup (error);
5835 return o;
5838 MonoObject*
5839 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5841 MONO_REQ_GC_UNSAFE_MODE;
5843 int size;
5845 size = m_class_get_instance_size (vtable->klass);
5847 #if MONO_CROSS_COMPILE
5848 /* In cross compile mode, we should only allocate thread objects */
5849 /* The instance size refers to the target arch, this should be safe enough */
5850 size *= 2;
5851 #endif
5853 MonoObject *o = mono_gc_alloc_mature (vtable, size);
5855 return object_new_common_tail (o, vtable->klass, error);
5858 MonoObjectHandle
5859 mono_object_new_handle_mature (MonoVTable *vtable, MonoError *error)
5861 MONO_REQ_GC_UNSAFE_MODE;
5863 MonoClass* const klass = vtable->klass;
5864 int const size = m_class_get_instance_size (klass);
5866 MonoObjectHandle o = mono_gc_alloc_handle_mature (vtable, size);
5868 return object_new_handle_common_tail (o, klass, error);
5872 * mono_object_new_from_token:
5873 * \param image Context where the type_token is hosted
5874 * \param token a token of the type that we want to create
5875 * \returns A newly created object whose definition is
5876 * looked up using \p token in the \p image image
5878 MonoObject *
5879 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5881 MONO_REQ_GC_UNSAFE_MODE;
5883 HANDLE_FUNCTION_ENTER ();
5885 ERROR_DECL (error);
5886 MonoClass *klass;
5888 klass = mono_class_get_checked (image, token, error);
5889 mono_error_assert_ok (error);
5891 MonoObjectHandle result = mono_object_new_handle (domain, klass, error);
5893 mono_error_cleanup (error);
5895 HANDLE_FUNCTION_RETURN_OBJ (result);
5899 * mono_object_clone:
5900 * \param obj the object to clone
5901 * \returns A newly created object who is a shallow copy of \p obj
5903 MonoObject *
5904 mono_object_clone (MonoObject *obj)
5906 ERROR_DECL (error);
5907 MonoObject *o = mono_object_clone_checked (obj, error);
5908 mono_error_cleanup (error);
5910 return o;
5913 MonoObject *
5914 mono_object_clone_checked (MonoObject *obj_raw, MonoError *error)
5916 MONO_REQ_GC_UNSAFE_MODE;
5917 HANDLE_FUNCTION_ENTER ();
5918 MONO_HANDLE_DCL (MonoObject, obj);
5919 HANDLE_FUNCTION_RETURN_OBJ (mono_object_clone_handle (obj, error));
5922 MonoObjectHandle
5923 mono_object_clone_handle (MonoObjectHandle obj, MonoError *error)
5925 MONO_REQ_GC_UNSAFE_MODE;
5927 MonoVTable* const vtable = MONO_HANDLE_GETVAL (obj, vtable);
5928 MonoClass* const klass = vtable->klass;
5930 if (m_class_get_rank (klass))
5931 return MONO_HANDLE_CAST (MonoObject, mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (obj),
5932 MONO_HANDLE_CAST (MonoArray, obj), error));
5934 int const size = m_class_get_instance_size (klass);
5936 MonoObjectHandle o = mono_gc_alloc_handle_obj (vtable, size);
5938 if (G_LIKELY (!MONO_HANDLE_IS_NULL (o))) {
5939 /* If the object doesn't contain references this will do a simple memmove. */
5940 mono_gc_wbarrier_object_copy_handle (o, obj);
5943 return object_new_handle_common_tail (o, klass, error);
5947 * mono_array_full_copy:
5948 * \param src source array to copy
5949 * \param dest destination array
5950 * Copies the content of one array to another with exactly the same type and size.
5952 void
5953 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5955 MONO_REQ_GC_UNSAFE_MODE;
5957 uintptr_t size;
5958 MonoClass *klass = mono_object_class (&src->obj);
5960 g_assert (klass == mono_object_class (&dest->obj));
5962 size = mono_array_length (src);
5963 g_assert (size == mono_array_length (dest));
5964 size *= mono_array_element_size (klass);
5966 array_full_copy_unchecked_size (src, dest, klass, size);
5969 static void
5970 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5972 if (mono_gc_is_moving ()) {
5973 MonoClass *element_class = m_class_get_element_class (klass);
5974 if (m_class_is_valuetype (element_class)) {
5975 if (m_class_has_references (element_class))
5976 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5977 else
5978 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5979 } else {
5980 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5982 } else {
5983 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5988 * mono_array_clone_in_domain:
5989 * \param domain the domain in which the array will be cloned into
5990 * \param array the array to clone
5991 * \param error set on error
5992 * This routine returns a copy of the array that is hosted on the
5993 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5995 MonoArrayHandle
5996 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5998 MONO_REQ_GC_UNSAFE_MODE;
6000 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
6001 uintptr_t size = 0;
6002 MonoClass *klass = mono_handle_class (array_handle);
6004 error_init (error);
6006 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
6007 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
6009 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
6010 MonoArrayHandle o;
6011 if (array_bounds == NULL) {
6012 size = mono_array_handle_length (array_handle);
6013 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
6014 goto_if_nok (error, leave);
6015 size *= mono_array_element_size (klass);
6016 } else {
6017 guint8 klass_rank = m_class_get_rank (klass);
6018 uintptr_t *sizes = g_newa (uintptr_t, klass_rank);
6019 intptr_t *lower_bounds = g_newa (intptr_t, klass_rank);
6020 size = mono_array_element_size (klass);
6021 for (int i = 0; i < klass_rank; ++i) {
6022 sizes [i] = array_bounds [i].length;
6023 size *= array_bounds [i].length;
6024 lower_bounds [i] = array_bounds [i].lower_bound;
6026 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
6027 goto_if_nok (error, leave);
6030 uint32_t dst_handle;
6031 dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
6032 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
6033 mono_gchandle_free (dst_handle);
6035 MONO_HANDLE_ASSIGN (result, o);
6037 leave:
6038 mono_gchandle_free (src_handle);
6039 return result;
6043 * mono_array_clone:
6044 * \param array the array to clone
6045 * \returns A newly created array who is a shallow copy of \p array
6047 MonoArray*
6048 mono_array_clone (MonoArray *array)
6050 MONO_REQ_GC_UNSAFE_MODE;
6052 ERROR_DECL (error);
6053 MonoArray *result = mono_array_clone_checked (array, error);
6054 mono_error_cleanup (error);
6055 return result;
6059 * mono_array_clone_checked:
6060 * \param array the array to clone
6061 * \param error set on error
6062 * \returns A newly created array who is a shallow copy of \p array. On
6063 * failure returns NULL and sets \p error.
6065 MonoArray*
6066 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
6068 MONO_REQ_GC_UNSAFE_MODE;
6069 HANDLE_FUNCTION_ENTER ();
6070 /* FIXME: callers of mono_array_clone_checked should use handles */
6071 error_init (error);
6072 MONO_HANDLE_DCL (MonoArray, array);
6073 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
6074 HANDLE_FUNCTION_RETURN_OBJ (result);
6077 /* helper macros to check for overflow when calculating the size of arrays */
6078 #ifdef MONO_BIG_ARRAYS
6079 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
6080 #define MYGUINT_MAX MYGUINT64_MAX
6081 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6082 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
6083 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6084 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
6085 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
6086 #else
6087 #define MYGUINT32_MAX 4294967295U
6088 #define MYGUINT_MAX MYGUINT32_MAX
6089 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6090 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
6091 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6092 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
6093 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
6094 #endif
6096 gboolean
6097 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
6099 MONO_REQ_GC_NEUTRAL_MODE;
6101 uintptr_t byte_len;
6103 byte_len = mono_array_element_size (klass);
6104 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
6105 return FALSE;
6106 byte_len *= len;
6107 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
6108 return FALSE;
6109 byte_len += MONO_SIZEOF_MONO_ARRAY;
6111 *res = byte_len;
6113 return TRUE;
6117 * mono_array_new_full:
6118 * \param domain domain where the object is created
6119 * \param array_class array class
6120 * \param lengths lengths for each dimension in the array
6121 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
6122 * This routine creates a new array object with the given dimensions,
6123 * lower bounds and type.
6125 MonoArray*
6126 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
6128 ERROR_DECL (error);
6129 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, error);
6130 mono_error_cleanup (error);
6132 return array;
6135 MonoArray*
6136 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
6138 MONO_REQ_GC_UNSAFE_MODE;
6140 uintptr_t byte_len = 0, len, bounds_size;
6141 MonoObject *o;
6142 MonoArray *array;
6143 MonoArrayBounds *bounds;
6144 MonoVTable *vtable;
6145 int i;
6147 error_init (error);
6149 if (!m_class_is_inited (array_class))
6150 mono_class_init (array_class);
6152 len = 1;
6154 guint8 array_class_rank = m_class_get_rank (array_class);
6155 /* A single dimensional array with a 0 lower bound is the same as an szarray */
6156 if (array_class_rank == 1 && ((m_class_get_byval_arg (array_class)->type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
6157 len = lengths [0];
6158 if (len > MONO_ARRAY_MAX_INDEX) {
6159 mono_error_set_generic_error (error, "System", "OverflowException", "");
6160 return NULL;
6162 bounds_size = 0;
6163 } else {
6164 bounds_size = sizeof (MonoArrayBounds) * array_class_rank;
6166 for (i = 0; i < array_class_rank; ++i) {
6167 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
6168 mono_error_set_generic_error (error, "System", "OverflowException", "");
6169 return NULL;
6171 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
6172 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6173 return NULL;
6175 len *= lengths [i];
6179 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
6180 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6181 return NULL;
6184 if (bounds_size) {
6185 /* align */
6186 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
6187 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6188 return NULL;
6190 byte_len = (byte_len + 3) & ~3;
6191 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
6192 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6193 return NULL;
6195 byte_len += bounds_size;
6198 * Following three lines almost taken from mono_object_new ():
6199 * they need to be kept in sync.
6201 vtable = mono_class_vtable_checked (domain, array_class, error);
6202 return_val_if_nok (error, NULL);
6204 if (bounds_size)
6205 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
6206 else
6207 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
6209 if (G_UNLIKELY (!o)) {
6210 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
6211 return NULL;
6214 array = (MonoArray*)o;
6216 bounds = array->bounds;
6218 if (bounds_size) {
6219 for (i = 0; i < array_class_rank; ++i) {
6220 bounds [i].length = lengths [i];
6221 if (lower_bounds)
6222 bounds [i].lower_bound = lower_bounds [i];
6226 return array;
6230 * mono_array_new:
6231 * \param domain domain where the object is created
6232 * \param eclass element class
6233 * \param n number of array elements
6234 * This routine creates a new szarray with \p n elements of type \p eclass.
6236 MonoArray *
6237 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6239 MonoArray *result;
6240 MONO_ENTER_GC_UNSAFE;
6242 ERROR_DECL (error);
6243 result = mono_array_new_checked (domain, eclass, n, error);
6244 mono_error_cleanup (error);
6245 MONO_EXIT_GC_UNSAFE;
6246 return result;
6250 * mono_array_new_checked:
6251 * \param domain domain where the object is created
6252 * \param eclass element class
6253 * \param n number of array elements
6254 * \param error set on error
6255 * This routine creates a new szarray with \p n elements of type \p eclass.
6256 * On failure returns NULL and sets \p error.
6258 MonoArray *
6259 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
6261 MonoClass *ac;
6263 error_init (error);
6265 ac = mono_class_create_array (eclass, 1);
6266 g_assert (ac);
6268 MonoVTable *vtable = mono_class_vtable_checked (domain, ac, error);
6269 return_val_if_nok (error, NULL);
6271 return mono_array_new_specific_checked (vtable, n, error);
6274 MonoArray*
6275 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6277 ERROR_DECL (error);
6278 MonoArray *arr = mono_array_new_checked (domain, eclass, n, error);
6279 mono_error_set_pending_exception (error);
6281 return arr;
6285 * mono_array_new_specific:
6286 * \param vtable a vtable in the appropriate domain for an initialized class
6287 * \param n number of array elements
6288 * This routine is a fast alternative to \c mono_array_new for code which
6289 * can be sure about the domain it operates in.
6291 MonoArray *
6292 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
6294 ERROR_DECL (error);
6295 MonoArray *arr = mono_array_new_specific_checked (vtable, n, error);
6296 mono_error_cleanup (error);
6298 return arr;
6301 MonoArray*
6302 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
6304 MONO_REQ_GC_UNSAFE_MODE;
6306 MonoObject *o;
6307 uintptr_t byte_len;
6309 error_init (error);
6311 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6312 mono_error_set_generic_error (error, "System", "OverflowException", "");
6313 return NULL;
6316 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6317 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6318 return NULL;
6320 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6322 if (G_UNLIKELY (!o)) {
6323 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
6324 return NULL;
6327 return (MonoArray*)o;
6331 MonoArrayHandle
6332 mono_array_new_specific_handle (MonoVTable *vtable, uintptr_t n, MonoError *error)
6334 // FIXMEcoop invert relationship with mono_array_new_specific_checked
6335 return MONO_HANDLE_NEW (MonoArray, mono_array_new_specific_checked (vtable, n, error));
6338 MonoArray*
6339 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6341 ERROR_DECL (error);
6342 MonoArray *arr = mono_array_new_specific_checked (vtable, n, error);
6343 mono_error_set_pending_exception (error);
6345 return arr;
6349 * mono_string_empty_wrapper:
6351 * Returns: The same empty string instance as the managed string.Empty
6353 MonoString*
6354 mono_string_empty_wrapper (void)
6356 MonoDomain *domain = mono_domain_get ();
6357 return mono_string_empty (domain);
6361 * mono_string_empty:
6363 * Returns: The same empty string instance as the managed string.Empty
6365 MonoString*
6366 mono_string_empty (MonoDomain *domain)
6368 g_assert (domain);
6369 g_assert (domain->empty_string);
6370 return domain->empty_string;
6373 MonoStringHandle
6374 mono_string_empty_handle (MonoDomain *domain)
6376 return MONO_HANDLE_NEW (MonoString, mono_string_empty (domain));
6380 * mono_string_new_utf16:
6381 * \param text a pointer to an utf16 string
6382 * \param len the length of the string
6383 * \returns A newly created string object which contains \p text.
6385 MonoString *
6386 mono_string_new_utf16 (MonoDomain *domain, const mono_unichar2 *text, gint32 len)
6388 MONO_REQ_GC_UNSAFE_MODE;
6390 ERROR_DECL (error);
6391 MonoString *res = NULL;
6392 res = mono_string_new_utf16_checked (domain, text, len, error);
6393 mono_error_cleanup (error);
6395 return res;
6399 * mono_string_new_utf16_checked:
6400 * \param text a pointer to an utf16 string
6401 * \param len the length of the string
6402 * \param error written on error.
6403 * \returns A newly created string object which contains \p text.
6404 * On error, returns NULL and sets \p error.
6406 MonoString *
6407 mono_string_new_utf16_checked (MonoDomain *domain, const gunichar2 *text, gint32 len, MonoError *error)
6409 MONO_REQ_GC_UNSAFE_MODE;
6411 MonoString *s;
6413 error_init (error);
6415 s = mono_string_new_size_checked (domain, len, error);
6416 if (s != NULL)
6417 memcpy (mono_string_chars (s), text, len * 2);
6419 return s;
6423 * mono_string_new_utf16_handle:
6424 * \param text a pointer to an utf16 string
6425 * \param len the length of the string
6426 * \param error written on error.
6427 * \returns A newly created string object which contains \p text.
6428 * On error, returns NULL and sets \p error.
6430 MonoStringHandle
6431 mono_string_new_utf16_handle (MonoDomain *domain, const gunichar2 *text, gint32 len, MonoError *error)
6433 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6437 * mono_string_new_utf32_checked:
6438 * \param text a pointer to an utf32 string
6439 * \param len the length of the string
6440 * \param error set on failure.
6441 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6443 static MonoString *
6444 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6446 MONO_REQ_GC_UNSAFE_MODE;
6448 MonoString *s;
6449 mono_unichar2 *utf16_output = NULL;
6450 gint32 utf16_len = 0;
6452 error_init (error);
6453 utf16_output = g_ucs4_to_utf16 (text, len, NULL, NULL, NULL);
6455 while (utf16_output [utf16_len]) utf16_len++;
6457 s = mono_string_new_size_checked (domain, utf16_len, error);
6458 goto_if_nok (error, exit);
6460 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6462 exit:
6463 g_free (utf16_output);
6465 return s;
6469 * mono_string_new_utf32:
6470 * \param text a pointer to a UTF-32 string
6471 * \param len the length of the string
6472 * \returns A newly created string object which contains \p text.
6474 MonoString *
6475 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6477 ERROR_DECL (error);
6478 MonoString *result = mono_string_new_utf32_checked (domain, text, len, error);
6479 mono_error_cleanup (error);
6480 return result;
6484 * mono_string_new_size:
6485 * \param text a pointer to a UTF-16 string
6486 * \param len the length of the string
6487 * \returns A newly created string object of \p len
6489 MonoString *
6490 mono_string_new_size (MonoDomain *domain, gint32 len)
6492 ERROR_DECL (error);
6493 MonoString *str = mono_string_new_size_checked (domain, len, error);
6494 mono_error_cleanup (error);
6496 return str;
6499 MonoString *
6500 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6502 MONO_REQ_GC_UNSAFE_MODE;
6504 MonoString *s;
6505 MonoVTable *vtable;
6506 size_t size;
6508 error_init (error);
6510 /* check for overflow */
6511 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6512 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6513 return NULL;
6516 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6517 g_assert (size > 0);
6519 vtable = mono_class_vtable_checked (domain, mono_defaults.string_class, error);
6520 return_val_if_nok (error, NULL);
6522 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6524 if (G_UNLIKELY (!s)) {
6525 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6526 return NULL;
6529 return s;
6533 * mono_string_new_len:
6534 * \param text a pointer to an utf8 string
6535 * \param length number of bytes in \p text to consider
6536 * \returns A newly created string object which contains \p text.
6538 MonoString*
6539 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6541 MONO_REQ_GC_UNSAFE_MODE;
6543 ERROR_DECL (error);
6544 MonoString *result = mono_string_new_len_checked (domain, text, length, error);
6545 mono_error_cleanup (error);
6546 return result;
6550 * mono_string_new_len_checked:
6551 * \param text a pointer to an utf8 string
6552 * \param length number of bytes in \p text to consider
6553 * \param error set on error
6554 * \returns A newly created string object which contains \p text. On
6555 * failure returns NULL and sets \p error.
6557 MonoStringHandle
6558 mono_string_new_utf8_len_handle (MonoDomain *domain, const char *text, guint length, MonoError *error)
6560 MONO_REQ_GC_UNSAFE_MODE;
6562 error_init (error);
6564 GError *eg_error = NULL;
6565 MonoStringHandle o = NULL_HANDLE_STRING;
6566 gunichar2 *ut = NULL;
6567 glong items_written;
6569 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6571 if (!eg_error)
6572 o = mono_string_new_utf16_handle (domain, ut, items_written, error);
6573 else
6574 g_error_free (eg_error);
6576 g_free (ut);
6578 return o;
6581 MonoString*
6582 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6584 HANDLE_FUNCTION_ENTER ();
6585 error_init (error);
6586 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_utf8_len_handle (domain, text, length, error));
6589 static MonoString*
6590 mono_string_new_internal (MonoDomain *domain, const char *text)
6592 ERROR_DECL (error);
6593 MonoString *res = NULL;
6594 res = mono_string_new_checked (domain, text, error);
6595 if (!is_ok (error)) {
6596 /* Mono API compatability: assert on Out of Memory errors,
6597 * return NULL otherwise (most likely an invalid UTF-8 byte
6598 * sequence). */
6599 if (mono_error_get_error_code (error) == MONO_ERROR_OUT_OF_MEMORY)
6600 mono_error_assert_ok (error);
6601 else
6602 mono_error_cleanup (error);
6604 return res;
6608 * mono_string_new:
6609 * \param text a pointer to a UTF-8 string
6610 * \deprecated Use \c mono_string_new_checked in new code.
6611 * This function asserts if it cannot allocate a new string.
6612 * \returns A newly created string object which contains \p text.
6614 MonoString*
6615 mono_string_new (MonoDomain *domain, const char *text)
6617 MonoString *res;
6618 MONO_ENTER_GC_UNSAFE;
6619 res = mono_string_new_internal (domain, text);
6620 MONO_EXIT_GC_UNSAFE;
6621 return res;
6625 * mono_string_new_checked:
6626 * \param text a pointer to an utf8 string
6627 * \param merror set on error
6628 * \returns A newly created string object which contains \p text.
6629 * On error returns NULL and sets \p merror.
6631 MonoString*
6632 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6634 MONO_REQ_GC_UNSAFE_MODE;
6636 GError *eg_error = NULL;
6637 MonoString *o = NULL;
6638 gunichar2 *ut;
6639 glong items_written;
6640 int len;
6642 error_init (error);
6644 len = strlen (text);
6646 ut = g_utf8_to_utf16 (text, len, NULL, &items_written, &eg_error);
6648 if (!eg_error)
6649 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6650 else {
6651 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6652 g_error_free (eg_error);
6655 g_free (ut);
6657 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6658 #if 0
6659 gunichar2 *str;
6660 const gchar *end;
6661 int len;
6662 MonoString *o = NULL;
6664 if (!g_utf8_validate (text, -1, &end)) {
6665 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6666 goto leave;
6669 len = g_utf8_strlen (text, -1);
6670 o = mono_string_new_size_checked (domain, len, error);
6671 if (!o)
6672 goto leave;
6673 str = mono_string_chars (o);
6675 while (text < end) {
6676 *str++ = g_utf8_get_char (text);
6677 text = g_utf8_next_char (text);
6680 leave:
6681 #endif
6682 return o;
6686 * mono_string_new_wtf8_len_checked:
6687 * \param text a pointer to an wtf8 string (see https://simonsapin.github.io/wtf-8/)
6688 * \param length number of bytes in \p text to consider
6689 * \param merror set on error
6690 * \returns A newly created string object which contains \p text.
6691 * On error returns NULL and sets \p merror.
6693 MonoString*
6694 mono_string_new_wtf8_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6696 MONO_REQ_GC_UNSAFE_MODE;
6698 error_init (error);
6700 GError *eg_error = NULL;
6701 MonoString *o = NULL;
6702 gunichar2 *ut = NULL;
6703 glong items_written;
6705 ut = eg_wtf8_to_utf16 (text, length, NULL, &items_written, &eg_error);
6707 if (!eg_error)
6708 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6709 else
6710 g_error_free (eg_error);
6712 g_free (ut);
6714 return o;
6718 * mono_string_new_wrapper:
6719 * \param text pointer to UTF-8 characters.
6720 * Helper function to create a string object from \p text in the current domain.
6722 MonoString*
6723 mono_string_new_wrapper (const char *text)
6725 MonoString *res;
6726 MONO_ENTER_GC_UNSAFE;
6728 res = mono_string_new_internal (mono_domain_get (), text);
6729 MONO_EXIT_GC_UNSAFE;
6730 return res;
6734 * mono_value_box:
6735 * \param class the class of the value
6736 * \param value a pointer to the unboxed data
6737 * \returns A newly created object which contains \p value.
6739 MonoObject *
6740 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6742 MonoObject *result;
6743 MONO_ENTER_GC_UNSAFE;
6744 ERROR_DECL (error);
6745 result = mono_value_box_checked (domain, klass, value, error);
6746 mono_error_cleanup (error);
6747 MONO_EXIT_GC_UNSAFE;
6748 return result;
6752 * mono_value_box_checked:
6753 * \param domain the domain of the new object
6754 * \param class the class of the value
6755 * \param value a pointer to the unboxed data
6756 * \param error set on error
6757 * \returns A newly created object which contains \p value. On failure
6758 * returns NULL and sets \p error.
6760 MonoObjectHandle
6761 mono_value_box_handle (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6763 // FIXMEcoop gpointer value needs more attention
6764 MONO_REQ_GC_UNSAFE_MODE;
6765 MonoObject *res;
6766 int size;
6767 MonoVTable *vtable;
6769 error_init (error);
6771 g_assert (m_class_is_valuetype (klass));
6772 if (mono_class_is_nullable (klass))
6773 return mono_nullable_box_handle (value, klass, error);
6775 vtable = mono_class_vtable_checked (domain, klass, error);
6776 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
6778 size = mono_class_instance_size (klass);
6780 MonoObjectHandle res_handle = mono_object_new_alloc_by_vtable (vtable, error);
6781 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
6782 res = MONO_HANDLE_RAW (res_handle);
6784 size = size - MONO_ABI_SIZEOF (MonoObject);
6786 gpointer data = mono_object_get_data (res);
6788 if (mono_gc_is_moving ()) {
6789 g_assert (size == mono_class_value_size (klass, NULL));
6790 mono_gc_wbarrier_value_copy (data, value, 1, klass);
6791 } else {
6792 #if NO_UNALIGNED_ACCESS
6793 mono_gc_memmove_atomic (data, value, size);
6794 #else
6795 switch (size) {
6796 case 1:
6797 *(guint8*)data = *(guint8 *) value;
6798 break;
6799 case 2:
6800 *(guint16 *)(data) = *(guint16 *) value;
6801 break;
6802 case 4:
6803 *(guint32 *)(data) = *(guint32 *) value;
6804 break;
6805 case 8:
6806 *(guint64 *)(data) = *(guint64 *) value;
6807 break;
6808 default:
6809 mono_gc_memmove_atomic (data, value, size);
6811 #endif
6813 if (m_class_has_finalize (klass))
6814 mono_object_register_finalizer (res);
6816 return res_handle;
6820 * mono_value_box_checked:
6821 * \param domain the domain of the new object
6822 * \param class the class of the value
6823 * \param value a pointer to the unboxed data
6824 * \param error set on error
6825 * \returns A newly created object which contains \p value. On failure
6826 * returns NULL and sets \p error.
6828 MonoObject *
6829 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6831 MONO_REQ_GC_UNSAFE_MODE;
6832 MonoObject *res;
6833 int size;
6834 MonoVTable *vtable;
6836 error_init (error);
6838 g_assert (m_class_is_valuetype (klass));
6839 if (mono_class_is_nullable (klass))
6840 return mono_nullable_box ((guint8 *)value, klass, error);
6842 vtable = mono_class_vtable_checked (domain, klass, error);
6843 return_val_if_nok (error, NULL);
6845 size = mono_class_instance_size (klass);
6846 res = mono_object_new_alloc_specific_checked (vtable, error);
6847 return_val_if_nok (error, NULL);
6849 size = size - MONO_ABI_SIZEOF (MonoObject);
6851 gpointer data = mono_object_get_data (res);
6852 if (mono_gc_is_moving ()) {
6853 g_assert (size == mono_class_value_size (klass, NULL));
6854 mono_gc_wbarrier_value_copy (data, value, 1, klass);
6855 } else {
6856 #if NO_UNALIGNED_ACCESS
6857 mono_gc_memmove_atomic (data, value, size);
6858 #else
6859 switch (size) {
6860 case 1:
6861 *(guint8 *)(data) = *(guint8 *) value;
6862 break;
6863 case 2:
6864 *(guint16 *)(data) = *(guint16 *) value;
6865 break;
6866 case 4:
6867 *(guint32 *)(data) = *(guint32 *) value;
6868 break;
6869 case 8:
6870 *(guint64 *)(data) = *(guint64 *) value;
6871 break;
6872 default:
6873 mono_gc_memmove_atomic (data, value, size);
6875 #endif
6877 if (m_class_has_finalize (klass)) {
6878 mono_object_register_finalizer (res);
6879 return_val_if_nok (error, NULL);
6881 return res;
6885 * mono_value_copy:
6886 * \param dest destination pointer
6887 * \param src source pointer
6888 * \param klass a valuetype class
6889 * Copy a valuetype from \p src to \p dest. This function must be used
6890 * when \p klass contains reference fields.
6892 void
6893 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6895 MONO_REQ_GC_UNSAFE_MODE;
6897 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6901 * mono_value_copy_array:
6902 * \param dest destination array
6903 * \param dest_idx index in the \p dest array
6904 * \param src source pointer
6905 * \param count number of items
6906 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6907 * This function must be used when \p klass contains references fields.
6908 * Overlap is handled.
6910 void
6911 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6913 MONO_REQ_GC_UNSAFE_MODE;
6915 int size = mono_array_element_size (dest->obj.vtable->klass);
6916 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6917 g_assert (size == mono_class_value_size (m_class_get_element_class (mono_object_class (dest)), NULL));
6918 mono_gc_wbarrier_value_copy (d, src, count, m_class_get_element_class (mono_object_class (dest)));
6921 MonoVTable *
6922 mono_object_get_vtable (MonoObject *obj)
6924 // This could be called during STW, so untag the vtable if needed.
6925 return mono_gc_get_vtable (obj);
6929 * mono_object_get_domain:
6930 * \param obj object to query
6931 * \returns the \c MonoDomain where the object is hosted
6933 MonoDomain*
6934 mono_object_get_domain (MonoObject *obj)
6936 MONO_REQ_GC_UNSAFE_MODE;
6938 return mono_object_domain (obj);
6942 * mono_object_get_class:
6943 * \param obj object to query
6944 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6945 * \returns the \c MonoClass of the object.
6947 MonoClass*
6948 mono_object_get_class (MonoObject *obj)
6950 MonoClass *res;
6951 MONO_ENTER_GC_UNSAFE;
6953 res = mono_object_class (obj);
6954 MONO_EXIT_GC_UNSAFE;
6955 return res;
6958 * mono_object_get_size:
6959 * \param o object to query
6960 * \returns the size, in bytes, of \p o
6962 guint
6963 mono_object_get_size (MonoObject* o)
6965 MONO_REQ_GC_UNSAFE_MODE;
6967 MonoClass* klass = mono_object_class (o);
6968 if (klass == mono_defaults.string_class) {
6969 return MONO_SIZEOF_MONO_STRING + 2 * mono_string_length ((MonoString*) o) + 2;
6970 } else if (o->vtable->rank) {
6971 MonoArray *array = (MonoArray*)o;
6972 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6973 if (array->bounds) {
6974 size += 3;
6975 size &= ~3;
6976 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6978 return size;
6979 } else {
6980 return mono_class_instance_size (klass);
6985 * mono_object_unbox:
6986 * \param obj object to unbox
6987 * \returns a pointer to the start of the valuetype boxed in this
6988 * object.
6990 * This method will assert if the object passed is not a valuetype.
6992 gpointer
6993 mono_object_unbox (MonoObject *obj)
6995 gpointer res;
6996 MONO_ENTER_GC_UNSAFE;
6998 /* add assert for valuetypes? */
6999 g_assert (m_class_is_valuetype (mono_object_class (obj)));
7000 res = mono_object_get_data (obj);
7001 MONO_EXIT_GC_UNSAFE;
7002 return res;
7006 * mono_object_isinst:
7007 * \param obj an object
7008 * \param klass a pointer to a class
7009 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
7011 MonoObject *
7012 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
7014 HANDLE_FUNCTION_ENTER ();
7015 MonoObjectHandle result;
7016 MONO_ENTER_GC_UNSAFE;
7018 MONO_HANDLE_DCL (MonoObject, obj);
7019 ERROR_DECL (error);
7020 result = mono_object_handle_isinst (obj, klass, error);
7021 mono_error_cleanup (error);
7022 MONO_EXIT_GC_UNSAFE;
7023 HANDLE_FUNCTION_RETURN_OBJ (result);
7028 * mono_object_isinst_checked:
7029 * \param obj an object
7030 * \param klass a pointer to a class
7031 * \param error set on error
7032 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7033 * On failure returns NULL and sets \p error.
7035 MonoObject *
7036 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
7038 MONO_REQ_GC_UNSAFE_MODE;
7040 HANDLE_FUNCTION_ENTER ();
7041 error_init (error);
7042 MONO_HANDLE_DCL (MonoObject, obj);
7043 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
7044 HANDLE_FUNCTION_RETURN_OBJ (result);
7048 * mono_object_handle_isinst:
7049 * \param obj an object
7050 * \param klass a pointer to a class
7051 * \param error set on error
7052 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7053 * On failure returns NULL and sets \p error.
7055 MonoObjectHandle
7056 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7058 error_init (error);
7060 if (!m_class_is_inited (klass))
7061 mono_class_init (klass);
7063 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
7064 return mono_object_handle_isinst_mbyref (obj, klass, error);
7067 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7069 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from_internal (klass, mono_handle_class (obj)))
7070 MONO_HANDLE_ASSIGN (result, obj);
7071 return result;
7075 * mono_object_isinst_mbyref:
7077 MonoObject *
7078 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
7080 MONO_REQ_GC_UNSAFE_MODE;
7082 HANDLE_FUNCTION_ENTER ();
7083 ERROR_DECL (error);
7084 MONO_HANDLE_DCL (MonoObject, obj);
7085 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, error);
7086 mono_error_cleanup (error); /* FIXME better API that doesn't swallow the error */
7087 HANDLE_FUNCTION_RETURN_OBJ (result);
7090 MonoObjectHandle
7091 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7093 error_init (error);
7095 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7097 if (MONO_HANDLE_IS_NULL (obj))
7098 goto leave;
7100 MonoVTable *vt;
7101 vt = MONO_HANDLE_GETVAL (obj, vtable);
7103 if (mono_class_is_interface (klass)) {
7104 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, m_class_get_interface_id (klass))) {
7105 MONO_HANDLE_ASSIGN (result, obj);
7106 goto leave;
7109 /* casting an array one of the invariant interfaces that must act as such */
7110 if (m_class_is_array_special_interface (klass)) {
7111 if (mono_class_is_assignable_from_internal (klass, vt->klass)) {
7112 MONO_HANDLE_ASSIGN (result, obj);
7113 goto leave;
7117 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
7118 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from_internal (klass, mono_handle_class (obj))) {
7119 MONO_HANDLE_ASSIGN (result, obj);
7120 goto leave;
7122 } else {
7123 MonoClass *oklass = vt->klass;
7124 if (mono_class_is_transparent_proxy (oklass)){
7125 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
7126 oklass = remote_class->proxy_class;
7129 mono_class_setup_supertypes (klass);
7130 if (mono_class_has_parent_fast (oklass, klass)) {
7131 MONO_HANDLE_ASSIGN (result, obj);
7132 goto leave;
7135 #ifndef DISABLE_REMOTING
7136 if (mono_class_is_transparent_proxy (vt->klass))
7138 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
7139 if (!custom_type_info)
7140 goto leave;
7141 MonoDomain *domain = mono_domain_get ();
7142 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
7143 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
7144 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
7145 MonoMethod *im = NULL;
7146 gpointer pa [2];
7148 im = mono_class_get_method_from_name_checked (rpklass, "CanCastTo", -1, 0, error);
7149 goto_if_nok (error, leave);
7150 if (!im) {
7151 mono_error_set_not_supported (error, "Linked away.");
7152 goto leave;
7154 im = mono_object_handle_get_virtual_method (rp, im, error);
7155 goto_if_nok (error, leave);
7156 g_assert (im);
7158 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
7159 goto_if_nok (error, leave);
7161 pa [0] = MONO_HANDLE_RAW (reftype);
7162 pa [1] = MONO_HANDLE_RAW (obj);
7163 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
7164 goto_if_nok (error, leave);
7166 if (*(MonoBoolean *) mono_object_unbox(res)) {
7167 /* Update the vtable of the remote type, so it can safely cast to this new type */
7168 mono_upgrade_remote_class (domain, obj, klass, error);
7169 goto_if_nok (error, leave);
7170 MONO_HANDLE_ASSIGN (result, obj);
7173 #endif /* DISABLE_REMOTING */
7174 leave:
7175 return result;
7179 * mono_object_castclass_mbyref:
7180 * \param obj an object
7181 * \param klass a pointer to a class
7182 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
7184 MonoObject *
7185 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
7187 MONO_REQ_GC_UNSAFE_MODE;
7188 HANDLE_FUNCTION_ENTER ();
7189 ERROR_DECL (error);
7190 MONO_HANDLE_DCL (MonoObject, obj);
7191 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7192 if (MONO_HANDLE_IS_NULL (obj))
7193 goto leave;
7194 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, error));
7195 mono_error_cleanup (error);
7196 leave:
7197 HANDLE_FUNCTION_RETURN_OBJ (result);
7200 static MonoString*
7201 mono_string_get_pinned (MonoString *str, MonoError *error)
7203 MONO_REQ_GC_UNSAFE_MODE;
7205 error_init (error);
7207 /* We only need to make a pinned version of a string if this is a moving GC */
7208 if (!mono_gc_is_moving ())
7209 return str;
7210 int size;
7211 MonoString *news;
7212 size = MONO_SIZEOF_MONO_STRING + 2 * (mono_string_length (str) + 1);
7213 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
7214 if (news) {
7215 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
7216 news->length = mono_string_length (str);
7217 } else {
7218 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
7220 return news;
7223 static MonoString*
7224 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
7226 MONO_REQ_GC_UNSAFE_MODE;
7228 MonoGHashTable *ldstr_table;
7229 MonoString *s, *res;
7230 MonoDomain *domain;
7232 error_init (error);
7234 domain = ((MonoObject *)str)->vtable->domain;
7235 ldstr_table = domain->ldstr_table;
7236 ldstr_lock ();
7237 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
7238 if (res) {
7239 ldstr_unlock ();
7240 return res;
7242 if (insert) {
7243 /* Allocate outside the lock */
7244 ldstr_unlock ();
7245 s = mono_string_get_pinned (str, error);
7246 return_val_if_nok (error, NULL);
7247 if (s) {
7248 ldstr_lock ();
7249 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
7250 if (res) {
7251 ldstr_unlock ();
7252 return res;
7254 mono_g_hash_table_insert (ldstr_table, s, s);
7255 ldstr_unlock ();
7257 return s;
7259 ldstr_unlock ();
7260 return NULL;
7264 * mono_string_is_interned:
7265 * \param o String to probe
7266 * \returns Whether the string has been interned.
7268 MonoString*
7269 mono_string_is_interned (MonoString *o)
7271 ERROR_DECL (error);
7272 MonoString *result = mono_string_is_interned_lookup (o, FALSE, error);
7273 /* This function does not fail. */
7274 mono_error_assert_ok (error);
7275 return result;
7279 * mono_string_intern:
7280 * \param o String to intern
7281 * Interns the string passed.
7282 * \returns The interned string.
7284 MonoString*
7285 mono_string_intern (MonoString *str)
7287 ERROR_DECL (error);
7288 MonoString *result = mono_string_intern_checked (str, error);
7289 mono_error_assert_ok (error);
7290 return result;
7294 * mono_string_intern_checked:
7295 * \param o String to intern
7296 * \param error set on error.
7297 * Interns the string passed.
7298 * \returns The interned string. On failure returns NULL and sets \p error
7300 MonoString*
7301 mono_string_intern_checked (MonoString *str, MonoError *error)
7303 MONO_REQ_GC_UNSAFE_MODE;
7305 error_init (error);
7307 return mono_string_is_interned_lookup (str, TRUE, error);
7311 * mono_ldstr:
7312 * \param domain the domain where the string will be used.
7313 * \param image a metadata context
7314 * \param idx index into the user string table.
7315 * Implementation for the \c ldstr opcode.
7316 * \returns a loaded string from the \p image / \p idx combination.
7318 MonoString*
7319 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
7321 ERROR_DECL (error);
7322 MonoString *result = mono_ldstr_checked (domain, image, idx, error);
7323 mono_error_cleanup (error);
7324 return result;
7328 * mono_ldstr_checked:
7329 * \param domain the domain where the string will be used.
7330 * \param image a metadata context
7331 * \param idx index into the user string table.
7332 * \param error set on error.
7333 * Implementation for the \c ldstr opcode.
7334 * \returns A loaded string from the \p image / \p idx combination.
7335 * On failure returns NULL and sets \p error.
7337 MonoString*
7338 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
7340 MONO_REQ_GC_UNSAFE_MODE;
7341 error_init (error);
7343 if (image->dynamic) {
7344 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
7345 return str;
7346 } else {
7347 if (!mono_verifier_verify_string_signature (image, idx, error))
7348 return NULL;
7349 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
7350 return str;
7354 MonoStringHandle
7355 mono_ldstr_handle (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
7357 // FIXME invert mono_ldstr_handle and mono_ldstr_checked.
7358 return MONO_HANDLE_NEW (MonoString, mono_ldstr_checked (domain, image, idx, error));
7362 char*
7363 mono_string_from_blob (const char *str, MonoError *error)
7365 gsize len = mono_metadata_decode_blob_size (str, &str) >> 1;
7367 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7368 gunichar2 *src = (gunichar2*)str;
7369 gunichar2 *copy = g_new (gunichar2, len);
7370 int i;
7371 for (i = 0; i < len; ++i)
7372 copy [i] = GUINT16_FROM_LE (src [i]);
7374 char *res = mono_utf16_to_utf8 (copy, len, error);
7375 g_free (copy);
7376 return res;
7377 #else
7378 return mono_utf16_to_utf8 ((const gunichar2*)str, len, error);
7379 #endif
7382 * mono_ldstr_metadata_sig
7383 * \param domain the domain for the string
7384 * \param sig the signature of a metadata string
7385 * \param error set on error
7386 * \returns a \c MonoString for a string stored in the metadata. On
7387 * failure returns NULL and sets \p error.
7389 static MonoString*
7390 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
7392 MONO_REQ_GC_UNSAFE_MODE;
7394 error_init (error);
7395 const char *str = sig;
7396 MonoString *o, *interned;
7397 size_t len2;
7399 len2 = mono_metadata_decode_blob_size (str, &str);
7400 len2 >>= 1;
7402 o = mono_string_new_utf16_checked (domain, (gunichar2*)str, len2, error);
7403 return_val_if_nok (error, NULL);
7404 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7406 int i;
7407 gunichar2 *p2 = (gunichar2*)mono_string_chars (o);
7408 for (i = 0; i < len2; ++i) {
7409 *p2 = GUINT16_FROM_LE (*p2);
7410 ++p2;
7413 #endif
7414 ldstr_lock ();
7415 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
7416 ldstr_unlock ();
7417 if (interned)
7418 return interned; /* o will get garbage collected */
7420 o = mono_string_get_pinned (o, error);
7421 if (o) {
7422 ldstr_lock ();
7423 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
7424 if (!interned) {
7425 mono_g_hash_table_insert (domain->ldstr_table, o, o);
7426 interned = o;
7428 ldstr_unlock ();
7431 return interned;
7435 * mono_ldstr_utf8:
7437 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
7438 * of an object.
7440 char*
7441 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
7443 const char *str;
7444 size_t len2;
7445 long written = 0;
7446 char *as;
7447 GError *gerror = NULL;
7449 error_init (error);
7451 if (!mono_verifier_verify_string_signature (image, idx, error))
7452 return NULL;
7453 str = mono_metadata_user_string (image, idx);
7455 len2 = mono_metadata_decode_blob_size (str, &str);
7456 len2 >>= 1;
7458 as = g_utf16_to_utf8 ((gunichar2*)str, len2, NULL, &written, &gerror);
7459 if (gerror) {
7460 mono_error_set_argument (error, "string", gerror->message);
7461 g_error_free (gerror);
7462 return NULL;
7464 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7465 if (len2 > written) {
7466 /* allocate the total length and copy the part of the string that has been converted */
7467 char *as2 = (char *)g_malloc0 (len2);
7468 memcpy (as2, as, written);
7469 g_free (as);
7470 as = as2;
7473 return as;
7477 * mono_string_to_utf8:
7478 * \param s a \c System.String
7479 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
7480 * \returns the UTF-8 representation for \p s.
7481 * The resulting buffer needs to be freed with \c mono_free().
7483 char *
7484 mono_string_to_utf8 (MonoString *s)
7486 char *result;
7487 MONO_ENTER_GC_UNSAFE;
7488 ERROR_DECL (error);
7489 result = mono_string_to_utf8_checked (s, error);
7491 if (!is_ok (error)) {
7492 mono_error_cleanup (error);
7493 result = NULL;
7495 MONO_EXIT_GC_UNSAFE;
7496 return result;
7500 * mono_utf16_to_utf8:
7502 char *
7503 mono_utf16_to_utf8 (const gunichar2 *s, gsize slength, MonoError *error)
7505 MONO_REQ_GC_UNSAFE_MODE;
7507 long written = 0;
7508 char *as;
7509 GError *gerror = NULL;
7511 error_init (error);
7513 if (s == NULL)
7514 return NULL;
7516 if (!slength)
7517 return g_strdup ("");
7519 as = g_utf16_to_utf8 (s, slength, NULL, &written, &gerror);
7520 if (gerror) {
7521 mono_error_set_argument (error, "string", gerror->message);
7522 g_error_free (gerror);
7523 return NULL;
7525 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7526 if (slength > written) {
7527 /* allocate the total length and copy the part of the string that has been converted */
7528 char *as2 = (char *)g_malloc0 (slength);
7529 memcpy (as2, as, written);
7530 g_free (as);
7531 as = as2;
7534 return as;
7538 * mono_string_to_utf8_checked:
7539 * \param s a \c System.String
7540 * \param error a \c MonoError.
7541 * Converts a \c MonoString to its UTF-8 representation. May fail; check
7542 * \p error to determine whether the conversion was successful.
7543 * The resulting buffer should be freed with \c mono_free().
7545 char *
7546 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7548 MONO_REQ_GC_UNSAFE_MODE;
7550 error_init (error);
7552 if (s == NULL)
7553 return NULL;
7555 if (!s->length)
7556 return g_strdup ("");
7558 return mono_utf16_to_utf8 (mono_string_chars (s), s->length, error);
7561 char *
7562 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7564 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7568 * mono_string_to_utf8_ignore:
7569 * \param s a MonoString
7570 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7571 * invalid surrogate pairs.
7572 * The resulting buffer should be freed with \c mono_free().
7574 char *
7575 mono_string_to_utf8_ignore (MonoString *s)
7577 MONO_REQ_GC_UNSAFE_MODE;
7579 long written = 0;
7580 char *as;
7582 if (s == NULL)
7583 return NULL;
7585 if (!s->length)
7586 return g_strdup ("");
7588 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7590 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7591 if (s->length > written) {
7592 /* allocate the total length and copy the part of the string that has been converted */
7593 char *as2 = (char *)g_malloc0 (s->length);
7594 memcpy (as2, as, written);
7595 g_free (as);
7596 as = as2;
7599 return as;
7603 * mono_string_to_utf16:
7604 * \param s a \c MonoString
7605 * \returns a null-terminated array of the UTF-16 chars
7606 * contained in \p s. The result must be freed with \c g_free().
7607 * This is a temporary helper until our string implementation
7608 * is reworked to always include the null-terminating char.
7610 mono_unichar2*
7611 mono_string_to_utf16 (MonoString *s)
7613 MONO_REQ_GC_UNSAFE_MODE;
7615 if (s == NULL)
7616 return NULL;
7618 int const length = s->length;
7619 mono_unichar2* const as = (mono_unichar2*)g_malloc ((length + 1) * sizeof (*as));
7620 if (as) {
7621 as [length] = 0;
7622 if (length)
7623 memcpy (as, mono_string_chars(s), length * sizeof (*as));
7625 return as;
7629 * mono_string_to_utf32:
7630 * \param s a \c MonoString
7631 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7632 * contained in \p s. The result must be freed with \c g_free().
7634 mono_unichar4*
7635 mono_string_to_utf32 (MonoString *s)
7637 MONO_REQ_GC_UNSAFE_MODE;
7639 if (s == NULL)
7640 return NULL;
7642 return g_utf16_to_ucs4 (s->chars, s->length, NULL, NULL, NULL);
7646 * mono_string_from_utf16:
7647 * \param data the UTF-16 string (LPWSTR) to convert
7648 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7649 * \returns a \c MonoString.
7651 MonoString *
7652 mono_string_from_utf16 (gunichar2 *data)
7654 ERROR_DECL (error);
7655 MonoString *result = mono_string_from_utf16_checked (data, error);
7656 mono_error_cleanup (error);
7657 return result;
7661 * mono_string_from_utf16_checked:
7662 * \param data the UTF-16 string (LPWSTR) to convert
7663 * \param error set on error
7664 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7665 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7667 MonoString *
7668 mono_string_from_utf16_checked (const gunichar2 *data, MonoError *error)
7671 MONO_REQ_GC_UNSAFE_MODE;
7673 error_init (error);
7674 MonoDomain *domain = mono_domain_get ();
7675 int len = 0;
7677 if (!data)
7678 return NULL;
7680 while (data [len]) len++;
7682 return mono_string_new_utf16_checked (domain, data, len, error);
7686 * mono_string_from_utf32:
7687 * \param data the UTF-32 string (LPWSTR) to convert
7688 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7689 * \returns a \c MonoString.
7691 MonoString *
7692 mono_string_from_utf32 (/*const*/ mono_unichar4 *data)
7694 ERROR_DECL (error);
7695 MonoString *result = mono_string_from_utf32_checked (data, error);
7696 mono_error_cleanup (error);
7697 return result;
7701 * mono_string_from_utf32_checked:
7702 * \param data the UTF-32 string (LPWSTR) to convert
7703 * \param error set on error
7704 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7705 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7707 MonoString *
7708 mono_string_from_utf32_checked (const mono_unichar4 *data, MonoError *error)
7710 MONO_REQ_GC_UNSAFE_MODE;
7712 error_init (error);
7713 MonoString* result = NULL;
7714 mono_unichar2 *utf16_output = NULL;
7715 GError *gerror = NULL;
7716 glong items_written;
7717 int len = 0;
7719 if (!data)
7720 return NULL;
7722 while (data [len]) len++;
7724 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7726 if (gerror)
7727 g_error_free (gerror);
7729 result = mono_string_from_utf16_checked (utf16_output, error);
7730 g_free (utf16_output);
7731 return result;
7734 static char *
7735 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
7737 MONO_REQ_GC_UNSAFE_MODE;
7739 char *r;
7740 char *mp_s;
7741 int len;
7743 r = mono_string_to_utf8_checked (s, error);
7744 if (!mono_error_ok (error))
7745 return NULL;
7747 if (!mp && !image)
7748 return r;
7750 len = strlen (r) + 1;
7751 if (mp)
7752 mp_s = (char *)mono_mempool_alloc (mp, len);
7753 else
7754 mp_s = (char *)mono_image_alloc (image, len);
7756 memcpy (mp_s, r, len);
7758 g_free (r);
7760 return mp_s;
7764 * mono_string_to_utf8_image:
7765 * \param s a \c System.String
7766 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7768 char *
7769 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7771 MONO_REQ_GC_UNSAFE_MODE;
7773 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), error); /* FIXME pin the string */
7777 * mono_string_to_utf8_mp:
7778 * \param s a \c System.String
7779 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7781 char *
7782 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7784 MONO_REQ_GC_UNSAFE_MODE;
7786 return mono_string_to_utf8_internal (mp, NULL, s, error);
7790 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7792 void
7793 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7795 eh_callbacks = *cbs;
7798 MonoRuntimeExceptionHandlingCallbacks *
7799 mono_get_eh_callbacks (void)
7801 return &eh_callbacks;
7805 * mono_raise_exception:
7806 * \param ex exception object
7807 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7808 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7810 void
7811 mono_raise_exception (MonoException *ex)
7813 /* raise_exception doesn't return, so the transition to GC Unsafe is unbalanced */
7814 MONO_STACKDATA (stackdata);
7815 mono_threads_enter_gc_unsafe_region_unbalanced_with_info (mono_thread_info_current (), &stackdata);
7816 mono_raise_exception_deprecated (ex);
7820 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7822 void
7823 mono_raise_exception_deprecated (MonoException *ex)
7825 MONO_REQ_GC_UNSAFE_MODE;
7827 eh_callbacks.mono_raise_exception (ex);
7831 * mono_reraise_exception:
7832 * \param ex exception object
7833 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7834 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7836 void
7837 mono_reraise_exception (MonoException *ex)
7839 mono_reraise_exception_deprecated (ex);
7843 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7845 void
7846 mono_reraise_exception_deprecated (MonoException *ex)
7848 MONO_REQ_GC_UNSAFE_MODE;
7850 eh_callbacks.mono_reraise_exception (ex);
7854 * CTX must point to managed code.
7856 void
7857 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7859 MONO_REQ_GC_UNSAFE_MODE;
7861 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7865 * mono_wait_handle_new:
7866 * \param domain Domain where the object will be created
7867 * \param handle Handle for the wait handle
7868 * \param error set on error.
7869 * \returns A new \c MonoWaitHandle created in the given domain for the
7870 * given handle. On failure returns NULL and sets \p error.
7872 MonoWaitHandle *
7873 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7875 MONO_REQ_GC_UNSAFE_MODE;
7877 MonoWaitHandle *res;
7878 gpointer params [1];
7879 static MonoMethod *handle_set;
7881 error_init (error);
7882 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7883 return_val_if_nok (error, NULL);
7885 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7886 if (!handle_set)
7887 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7889 params [0] = &handle;
7891 mono_runtime_invoke_checked (handle_set, res, params, error);
7892 return res;
7895 HANDLE
7896 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7898 MONO_REQ_GC_UNSAFE_MODE;
7900 static MonoClassField *f_safe_handle = NULL;
7901 MonoSafeHandle *sh;
7903 if (!f_safe_handle) {
7904 f_safe_handle = mono_class_get_field_from_name_full (mono_defaults.manualresetevent_class, "safeWaitHandle", NULL);
7905 g_assert (f_safe_handle);
7908 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7909 return sh->handle;
7913 static MonoObject*
7914 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7916 #ifdef HOST_WASM
7917 return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
7918 #else
7919 MONO_REQ_GC_UNSAFE_MODE;
7921 RuntimeInvokeFunction runtime_invoke;
7923 error_init (error);
7925 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7926 MonoMethod *method = mono_get_context_capture_method ();
7927 MonoMethod *wrapper;
7928 if (!method)
7929 return NULL;
7930 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7931 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7932 return_val_if_nok (error, NULL);
7933 domain->capture_context_method = mono_compile_method_checked (method, error);
7934 return_val_if_nok (error, NULL);
7937 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7939 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7940 #endif
7943 * mono_async_result_new:
7944 * \param domain domain where the object will be created.
7945 * \param handle wait handle.
7946 * \param state state to pass to AsyncResult
7947 * \param data C closure data.
7948 * \param error set on error.
7949 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7950 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7951 * On failure returns NULL and sets \p error.
7953 MonoAsyncResult *
7954 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7956 MONO_REQ_GC_UNSAFE_MODE;
7958 error_init (error);
7959 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_class_get_asyncresult_class (), error);
7960 return_val_if_nok (error, NULL);
7961 MonoObject *context = mono_runtime_capture_context (domain, error);
7962 return_val_if_nok (error, NULL);
7963 /* we must capture the execution context from the original thread */
7964 if (context) {
7965 MONO_OBJECT_SETREF (res, execution_context, context);
7966 /* note: result may be null if the flow is suppressed */
7969 res->data = (void **)data;
7970 MONO_OBJECT_SETREF (res, object_data, object_data);
7971 MONO_OBJECT_SETREF (res, async_state, state);
7972 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7973 return_val_if_nok (error, NULL);
7974 if (handle != NULL)
7975 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7977 res->sync_completed = FALSE;
7978 res->completed = FALSE;
7980 return res;
7983 MonoObject *
7984 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7986 MONO_REQ_GC_UNSAFE_MODE;
7988 ERROR_DECL (error);
7989 MonoAsyncCall *ac;
7990 MonoObject *res;
7992 g_assert (ares);
7993 g_assert (ares->async_delegate);
7995 ac = (MonoAsyncCall*) ares->object_data;
7996 if (!ac) {
7997 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, error);
7998 if (mono_error_set_pending_exception (error))
7999 return NULL;
8000 } else {
8001 gpointer wait_event = NULL;
8003 ac->msg->exc = NULL;
8005 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, error);
8007 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
8008 mono_threads_begin_abort_protected_block ();
8010 if (!ac->msg->exc) {
8011 MonoException *ex = mono_error_convert_to_exception (error);
8012 ac->msg->exc = (MonoObject *)ex;
8013 } else {
8014 mono_error_cleanup (error);
8017 MONO_OBJECT_SETREF (ac, res, res);
8019 mono_monitor_enter ((MonoObject*) ares);
8020 ares->completed = 1;
8021 if (ares->handle)
8022 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
8023 mono_monitor_exit ((MonoObject*) ares);
8025 if (wait_event != NULL)
8026 mono_w32event_set (wait_event);
8028 error_init (error); //the else branch would leave it in an undefined state
8029 if (ac->cb_method)
8030 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, error);
8032 mono_threads_end_abort_protected_block ();
8034 if (mono_error_set_pending_exception (error))
8035 return NULL;
8038 return res;
8041 gboolean
8042 mono_message_init (MonoDomain *domain,
8043 MonoMethodMessage *this_obj,
8044 MonoReflectionMethod *method,
8045 MonoArray *out_args,
8046 MonoError *error)
8048 MONO_REQ_GC_UNSAFE_MODE;
8050 static MonoMethod *init_message_method = NULL;
8052 if (!init_message_method) {
8053 init_message_method = mono_class_get_method_from_name_checked (mono_defaults.mono_method_message_class, "InitMessage", 2, 0, error);
8054 mono_error_assert_ok (error);
8055 g_assert (init_message_method != NULL);
8058 error_init (error);
8059 /* FIXME set domain instead? */
8060 g_assert (domain == mono_domain_get ());
8062 gpointer args[2];
8064 args[0] = method;
8065 args[1] = out_args;
8067 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
8068 return is_ok (error);
8071 #ifndef DISABLE_REMOTING
8073 * mono_remoting_invoke:
8074 * \param real_proxy pointer to a \c RealProxy object
8075 * \param msg The \c MonoMethodMessage to execute
8076 * \param exc used to store exceptions
8077 * \param out_args used to store output arguments
8078 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
8079 * \c IMessage interface and it is not trivial to extract results from there. So
8080 * we call an helper method \c PrivateInvoke instead of calling
8081 * \c RealProxy::Invoke() directly.
8082 * \returns the result object.
8084 MonoObject *
8085 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
8087 MONO_REQ_GC_UNSAFE_MODE;
8089 MonoObject *o;
8090 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
8091 gpointer pa [4];
8093 g_assert (exc);
8095 error_init (error);
8097 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
8099 if (!im) {
8100 im = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "PrivateInvoke", 4, 0, error);
8101 return_val_if_nok (error, NULL);
8102 if (!im) {
8103 mono_error_set_not_supported (error, "Linked away.");
8104 return NULL;
8106 real_proxy->vtable->domain->private_invoke_method = im;
8109 pa [0] = real_proxy;
8110 pa [1] = msg;
8111 pa [2] = exc;
8112 pa [3] = out_args;
8114 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
8115 return_val_if_nok (error, NULL);
8117 return o;
8119 #endif
8121 MonoObject *
8122 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
8123 MonoObject **exc, MonoArray **out_args, MonoError *error)
8125 MONO_REQ_GC_UNSAFE_MODE;
8127 static MonoClass *object_array_klass;
8128 error_init (error);
8130 MonoDomain *domain;
8131 MonoMethod *method;
8132 MonoMethodSignature *sig;
8133 MonoArray *arr;
8134 int i, j, outarg_count = 0;
8136 #ifndef DISABLE_REMOTING
8137 if (target && mono_object_is_transparent_proxy (target)) {
8138 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
8139 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8140 target = tp->rp->unwrapped_server;
8141 } else {
8142 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
8145 #endif
8147 domain = mono_domain_get ();
8148 method = msg->method->method;
8149 sig = mono_method_signature (method);
8151 for (i = 0; i < sig->param_count; i++) {
8152 if (sig->params [i]->byref)
8153 outarg_count++;
8156 if (!object_array_klass) {
8157 MonoClass *klass;
8159 klass = mono_class_create_array (mono_defaults.object_class, 1);
8160 g_assert (klass);
8162 mono_memory_barrier ();
8163 object_array_klass = klass;
8166 MonoVTable *vt = mono_class_vtable_checked (domain, object_array_klass, error);
8167 return_val_if_nok (error, NULL);
8168 arr = mono_array_new_specific_checked (vt, outarg_count, error);
8169 return_val_if_nok (error, NULL);
8171 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
8172 *exc = NULL;
8174 MonoObject *ret = mono_runtime_try_invoke_array (method, m_class_is_valuetype (method->klass)? mono_object_unbox (target): target, msg->args, exc, error);
8175 return_val_if_nok (error, NULL);
8177 for (i = 0, j = 0; i < sig->param_count; i++) {
8178 if (sig->params [i]->byref) {
8179 MonoObject* arg;
8180 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
8181 mono_array_setref (*out_args, j, arg);
8182 j++;
8186 return ret;
8190 * prepare_to_string_method:
8191 * @obj: The object
8192 * @target: Set to @obj or unboxed value if a valuetype
8194 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
8196 static MonoMethod *
8197 prepare_to_string_method (MonoObject *obj, void **target)
8199 MONO_REQ_GC_UNSAFE_MODE;
8201 static MonoMethod *to_string = NULL;
8202 MonoMethod *method;
8203 g_assert (target);
8204 g_assert (obj);
8206 *target = obj;
8208 if (!to_string) {
8209 ERROR_DECL (error);
8210 to_string = mono_class_get_method_from_name_checked (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC, error);
8211 mono_error_assert_ok (error);
8214 method = mono_object_get_virtual_method (obj, to_string);
8216 // Unbox value type if needed
8217 if (m_class_is_valuetype (mono_method_get_class (method))) {
8218 *target = mono_object_unbox (obj);
8220 return method;
8224 * mono_object_to_string:
8225 * \param obj The object
8226 * \param exc Any exception thrown by \c ToString. May be NULL.
8227 * \returns the result of calling \c ToString on an object.
8229 MonoString *
8230 mono_object_to_string (MonoObject *obj, MonoObject **exc)
8232 ERROR_DECL (error);
8233 MonoString *s = NULL;
8234 void *target;
8235 MonoMethod *method = prepare_to_string_method (obj, &target);
8236 if (exc) {
8237 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, error);
8238 if (*exc == NULL && !mono_error_ok (error))
8239 *exc = (MonoObject*) mono_error_convert_to_exception (error);
8240 else
8241 mono_error_cleanup (error);
8242 } else {
8243 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, error);
8244 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
8247 return s;
8251 * mono_object_try_to_string:
8252 * \param obj The object
8253 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
8254 * \param error Set if method cannot be invoked.
8255 * \returns the result of calling \c ToString() on an object. If the
8256 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
8257 * and returns NULL.
8259 MonoString *
8260 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
8262 g_assert (exc);
8263 error_init (error);
8264 void *target;
8265 MonoMethod *method = prepare_to_string_method (obj, &target);
8266 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
8271 static char *
8272 get_native_backtrace (MonoException *exc_raw)
8274 HANDLE_FUNCTION_ENTER ();
8275 MONO_HANDLE_DCL(MonoException, exc);
8276 char * trace = mono_exception_handle_get_native_backtrace (exc);
8277 HANDLE_FUNCTION_RETURN_VAL (trace);
8281 * mono_print_unhandled_exception:
8282 * \param exc The exception
8283 * Prints the unhandled exception.
8285 void
8286 mono_print_unhandled_exception (MonoObject *exc)
8288 MONO_REQ_GC_UNSAFE_MODE;
8290 MonoString * str;
8291 char *message = (char*)"";
8292 gboolean free_message = FALSE;
8293 ERROR_DECL (error);
8295 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
8296 message = g_strdup ("OutOfMemoryException");
8297 free_message = TRUE;
8298 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
8299 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
8300 free_message = TRUE;
8301 } else {
8303 if (((MonoException*)exc)->native_trace_ips) {
8304 message = get_native_backtrace ((MonoException*)exc);
8305 free_message = TRUE;
8306 } else {
8307 MonoObject *other_exc = NULL;
8308 str = mono_object_try_to_string (exc, &other_exc, error);
8309 if (other_exc == NULL && !is_ok (error))
8310 other_exc = (MonoObject*)mono_error_convert_to_exception (error);
8311 else
8312 mono_error_cleanup (error);
8313 if (other_exc) {
8314 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
8315 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
8317 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
8318 original_backtrace, nested_backtrace);
8320 g_free (original_backtrace);
8321 g_free (nested_backtrace);
8322 free_message = TRUE;
8323 } else if (str) {
8324 message = mono_string_to_utf8_checked (str, error);
8325 if (!mono_error_ok (error)) {
8326 mono_error_cleanup (error);
8327 message = (char *) "";
8328 } else {
8329 free_message = TRUE;
8336 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
8337 * exc->vtable->klass->name, message);
8339 g_printerr ("\nUnhandled Exception:\n%s\n", message);
8341 if (free_message)
8342 g_free (message);
8346 * mono_delegate_ctor_with_method:
8347 * \param this pointer to an uninitialized delegate object
8348 * \param target target object
8349 * \param addr pointer to native code
8350 * \param method method
8351 * \param error set on error.
8352 * Initialize a delegate and sets a specific method, not the one
8353 * associated with \p addr. This is useful when sharing generic code.
8354 * In that case \p addr will most probably not be associated with the
8355 * correct instantiation of the method.
8356 * On failure returns FALSE and sets \p error.
8358 gboolean
8359 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
8361 MONO_REQ_GC_UNSAFE_MODE;
8363 error_init (error);
8364 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
8366 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
8367 g_assert (addr);
8369 MonoClass *klass = mono_handle_class (this_obj);
8370 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
8372 if (method)
8373 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
8375 UnlockedIncrement (&mono_stats.delegate_creations);
8377 #ifndef DISABLE_REMOTING
8378 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
8379 if (callbacks.interp_get_remoting_invoke) {
8380 MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, callbacks.interp_get_remoting_invoke (addr, error));
8381 } else {
8382 g_assert (method);
8383 method = mono_marshal_get_remoting_invoke (method, error);
8384 return_val_if_nok (error, FALSE);
8385 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
8387 return_val_if_nok (error, FALSE);
8388 MONO_HANDLE_SET (delegate, target, target);
8389 } else
8390 #endif
8392 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
8393 MONO_HANDLE_SET (delegate, target, target);
8396 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
8397 if (callbacks.init_delegate)
8398 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
8399 return TRUE;
8403 * mono_delegate_ctor:
8404 * \param this pointer to an uninitialized delegate object
8405 * \param target target object
8406 * \param addr pointer to native code
8407 * \param error set on error.
8408 * This is used to initialize a delegate.
8409 * On failure returns FALSE and sets \p error.
8411 gboolean
8412 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
8414 MONO_REQ_GC_UNSAFE_MODE;
8416 error_init (error);
8417 MonoDomain *domain = mono_domain_get ();
8418 MonoJitInfo *ji;
8419 MonoMethod *method = NULL;
8421 g_assert (addr);
8423 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
8424 /* Shared code */
8425 if (!ji && domain != mono_get_root_domain ())
8426 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
8427 if (ji) {
8428 method = mono_jit_info_get_method (ji);
8429 g_assert (!mono_class_is_gtd (method->klass));
8432 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
8436 * mono_method_call_message_new:
8437 * \param method method to encapsulate
8438 * \param params parameters to the method
8439 * \param invoke optional, delegate invoke.
8440 * \param cb async callback delegate.
8441 * \param state state passed to the async callback.
8442 * \param error set on error.
8443 * Translates arguments pointers into a \c MonoMethodMessage.
8444 * On failure returns NULL and sets \p error.
8446 MonoMethodMessage *
8447 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
8448 MonoDelegate **cb, MonoObject **state, MonoError *error)
8450 MONO_REQ_GC_UNSAFE_MODE;
8452 error_init (error);
8454 MonoDomain *domain = mono_domain_get ();
8455 MonoMethodSignature *sig = mono_method_signature (method);
8456 MonoMethodMessage *msg;
8457 int i, count;
8459 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8460 return_val_if_nok (error, NULL);
8462 if (invoke) {
8463 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8464 return_val_if_nok (error, NULL);
8465 mono_message_init (domain, msg, rm, NULL, error);
8466 return_val_if_nok (error, NULL);
8467 count = sig->param_count - 2;
8468 } else {
8469 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8470 return_val_if_nok (error, NULL);
8471 mono_message_init (domain, msg, rm, NULL, error);
8472 return_val_if_nok (error, NULL);
8473 count = sig->param_count;
8476 for (i = 0; i < count; i++) {
8477 gpointer vpos;
8478 MonoClass *klass;
8479 MonoObject *arg;
8481 if (sig->params [i]->byref)
8482 vpos = *((gpointer *)params [i]);
8483 else
8484 vpos = params [i];
8486 klass = mono_class_from_mono_type (sig->params [i]);
8488 if (m_class_is_valuetype (klass)) {
8489 arg = mono_value_box_checked (domain, klass, vpos, error);
8490 return_val_if_nok (error, NULL);
8491 } else
8492 arg = *((MonoObject **)vpos);
8494 mono_array_setref (msg->args, i, arg);
8497 if (cb != NULL && state != NULL) {
8498 *cb = *((MonoDelegate **)params [i]);
8499 i++;
8500 *state = *((MonoObject **)params [i]);
8503 return msg;
8507 * mono_method_return_message_restore:
8509 * Restore results from message based processing back to arguments pointers
8511 void
8512 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8514 MONO_REQ_GC_UNSAFE_MODE;
8516 error_init (error);
8518 MonoMethodSignature *sig = mono_method_signature (method);
8519 int i, j, type, size, out_len;
8521 if (out_args == NULL)
8522 return;
8523 out_len = mono_array_length (out_args);
8524 if (out_len == 0)
8525 return;
8527 for (i = 0, j = 0; i < sig->param_count; i++) {
8528 MonoType *pt = sig->params [i];
8530 if (pt->byref) {
8531 char *arg;
8532 if (j >= out_len) {
8533 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8534 return;
8537 arg = (char *)mono_array_get (out_args, gpointer, j);
8538 type = pt->type;
8540 g_assert (type != MONO_TYPE_VOID);
8542 if (MONO_TYPE_IS_REFERENCE (pt)) {
8543 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8544 } else {
8545 if (arg) {
8546 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8547 size = mono_class_value_size (klass, NULL);
8548 if (m_class_has_references (klass))
8549 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), mono_object_get_data ((MonoObject*)arg), 1, klass);
8550 else
8551 mono_gc_memmove_atomic (*((gpointer *)params [i]), mono_object_get_data ((MonoObject*)arg), size);
8552 } else {
8553 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8554 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8558 j++;
8563 #ifndef DISABLE_REMOTING
8566 * mono_load_remote_field:
8567 * \param this pointer to an object
8568 * \param klass klass of the object containing \p field
8569 * \param field the field to load
8570 * \param res a storage to store the result
8571 * This method is called by the runtime on attempts to load fields of
8572 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8573 * the object containing \p field. \p res is a storage location which can be
8574 * used to store the result.
8575 * \returns an address pointing to the value of field.
8577 gpointer
8578 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8580 ERROR_DECL (error);
8581 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, error);
8582 mono_error_cleanup (error);
8583 return result;
8587 * mono_load_remote_field_checked:
8588 * \param this pointer to an object
8589 * \param klass klass of the object containing \p field
8590 * \param field the field to load
8591 * \param res a storage to store the result
8592 * \param error set on error
8593 * This method is called by the runtime on attempts to load fields of
8594 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8595 * the object containing \p field. \p res is a storage location which can be
8596 * used to store the result.
8597 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8599 gpointer
8600 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8602 MONO_REQ_GC_UNSAFE_MODE;
8604 static MonoMethod *getter = NULL;
8606 error_init (error);
8608 MonoDomain *domain = mono_domain_get ();
8609 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8610 MonoClass *field_class;
8611 MonoMethodMessage *msg;
8612 MonoArray *out_args;
8613 MonoObject *exc;
8614 char* full_name;
8616 g_assert (mono_object_is_transparent_proxy (this_obj));
8617 g_assert (res != NULL);
8619 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8620 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8621 return res;
8624 if (!getter) {
8625 getter = mono_class_get_method_from_name_checked (mono_defaults.object_class, "FieldGetter", -1, 0, error);
8626 return_val_if_nok (error, NULL);
8627 if (!getter) {
8628 mono_error_set_not_supported (error, "Linked away.");
8629 return NULL;
8633 field_class = mono_class_from_mono_type (field->type);
8635 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8636 return_val_if_nok (error, NULL);
8637 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8638 return_val_if_nok (error, NULL);
8639 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8640 return_val_if_nok (error, NULL);
8641 mono_message_init (domain, msg, rm, out_args, error);
8642 return_val_if_nok (error, NULL);
8644 full_name = mono_type_get_full_name (klass);
8645 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8646 g_free (full_name);
8647 return_val_if_nok (error, NULL);
8648 mono_array_setref (msg->args, 0, full_name_str);
8649 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8650 return_val_if_nok (error, NULL);
8651 mono_array_setref (msg->args, 1, field_name);
8653 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8654 return_val_if_nok (error, NULL);
8656 if (exc) {
8657 mono_error_set_exception_instance (error, (MonoException *)exc);
8658 return NULL;
8661 if (mono_array_length (out_args) == 0)
8662 return NULL;
8664 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8666 if (m_class_is_valuetype (field_class)) {
8667 return mono_object_get_data ((MonoObject*)*res);
8668 } else
8669 return res;
8673 * mono_load_remote_field_new:
8674 * \param this
8675 * \param klass
8676 * \param field
8677 * Missing documentation.
8679 MonoObject *
8680 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8682 ERROR_DECL (error);
8684 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, error);
8685 mono_error_cleanup (error);
8686 return result;
8690 * mono_load_remote_field_new_checked:
8691 * \param this pointer to an object
8692 * \param klass klass of the object containing \p field
8693 * \param field the field to load
8694 * \param error set on error.
8695 * This method is called by the runtime on attempts to load fields of
8696 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8697 * the object containing \p field.
8698 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8700 MonoObject *
8701 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8703 MONO_REQ_GC_UNSAFE_MODE;
8705 error_init (error);
8707 static MonoMethod *tp_load = NULL;
8709 g_assert (mono_object_is_transparent_proxy (this_obj));
8711 if (!tp_load) {
8712 tp_load = mono_class_get_method_from_name_checked (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1, 0, error);
8713 return_val_if_nok (error, NULL);
8714 if (!tp_load) {
8715 mono_error_set_not_supported (error, "Linked away.");
8716 return NULL;
8720 /* MonoType *type = m_class_get_byval_arg (klass); */
8722 gpointer args[2];
8723 args [0] = &klass;
8724 args [1] = &field;
8726 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8730 * mono_store_remote_field:
8731 * \param this_obj pointer to an object
8732 * \param klass klass of the object containing \p field
8733 * \param field the field to load
8734 * \param val the value/object to store
8735 * This method is called by the runtime on attempts to store fields of
8736 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8737 * the object containing \p field. \p val is the new value to store in \p field.
8739 void
8740 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8742 ERROR_DECL (error);
8743 (void) mono_store_remote_field_checked (this_obj, klass, field, val, error);
8744 mono_error_cleanup (error);
8748 * mono_store_remote_field_checked:
8749 * \param this_obj pointer to an object
8750 * \param klass klass of the object containing \p field
8751 * \param field the field to load
8752 * \param val the value/object to store
8753 * \param error set on error
8754 * This method is called by the runtime on attempts to store fields of
8755 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8756 * the object containing \p field. \p val is the new value to store in \p field.
8757 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8759 gboolean
8760 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8763 MONO_REQ_GC_UNSAFE_MODE;
8765 error_init (error);
8767 MonoDomain *domain = mono_domain_get ();
8768 MonoClass *field_class;
8769 MonoObject *arg;
8771 g_assert (mono_object_is_transparent_proxy (this_obj));
8773 field_class = mono_class_from_mono_type (field->type);
8775 if (m_class_is_valuetype (field_class)) {
8776 arg = mono_value_box_checked (domain, field_class, val, error);
8777 return_val_if_nok (error, FALSE);
8778 } else {
8779 arg = *((MonoObject**)val);
8782 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8786 * mono_store_remote_field_new:
8787 * \param this_obj
8788 * \param klass
8789 * \param field
8790 * \param arg
8791 * Missing documentation
8793 void
8794 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8796 ERROR_DECL (error);
8797 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8798 mono_error_cleanup (error);
8802 * mono_store_remote_field_new_checked:
8803 * \param this_obj
8804 * \param klass
8805 * \param field
8806 * \param arg
8807 * \param error
8808 * Missing documentation
8810 gboolean
8811 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8813 MONO_REQ_GC_UNSAFE_MODE;
8815 static MonoMethod *tp_store = NULL;
8817 error_init (error);
8819 g_assert (mono_object_is_transparent_proxy (this_obj));
8821 if (!tp_store) {
8822 tp_store = mono_class_get_method_from_name_checked (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1, 0, error);
8823 return_val_if_nok (error, FALSE);
8824 if (!tp_store) {
8825 mono_error_set_not_supported (error, "Linked away.");
8826 return FALSE;
8830 gpointer args[3];
8831 args [0] = &klass;
8832 args [1] = &field;
8833 args [2] = arg;
8835 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8836 return is_ok (error);
8838 #endif
8841 * mono_create_ftnptr:
8843 * Given a function address, create a function descriptor for it.
8844 * This is only needed on some platforms.
8846 gpointer
8847 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8849 return callbacks.create_ftnptr (domain, addr);
8853 * mono_get_addr_from_ftnptr:
8855 * Given a pointer to a function descriptor, return the function address.
8856 * This is only needed on some platforms.
8858 gpointer
8859 mono_get_addr_from_ftnptr (gpointer descr)
8861 return callbacks.get_addr_from_ftnptr (descr);
8865 * mono_string_chars:
8866 * \param s a \c MonoString
8867 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8869 gunichar2 *
8870 mono_string_chars (MonoString *s)
8872 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8874 return s->chars;
8878 * mono_string_length:
8879 * \param s MonoString
8880 * \returns the length in characters of the string
8883 mono_string_length (MonoString *s)
8885 MONO_REQ_GC_UNSAFE_MODE;
8887 return s->length;
8891 * mono_string_handle_length:
8892 * \param s \c MonoString
8893 * \returns the length in characters of the string
8896 mono_string_handle_length (MonoStringHandle s)
8898 MONO_REQ_GC_UNSAFE_MODE;
8900 return MONO_HANDLE_GETVAL (s, length);
8905 * mono_array_length:
8906 * \param array a \c MonoArray*
8907 * \returns the total number of elements in the array. This works for
8908 * both vectors and multidimensional arrays.
8910 uintptr_t
8911 mono_array_length (MonoArray *array)
8913 uintptr_t res;
8914 MONO_ENTER_GC_UNSAFE;
8915 res = array->max_length;
8916 MONO_EXIT_GC_UNSAFE;
8917 return res;
8921 * mono_array_addr_with_size:
8922 * \param array a \c MonoArray*
8923 * \param size size of the array elements
8924 * \param idx index into the array
8925 * Use this function to obtain the address for the \p idx item on the
8926 * \p array containing elements of size \p size.
8928 * This method performs no bounds checking or type checking.
8929 * \returns the address of the \p idx element in the array.
8931 char*
8932 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8934 char *res;
8935 MONO_ENTER_GC_UNSAFE;
8937 res = mono_array_addr_with_size_fast (array, size, idx);
8938 MONO_EXIT_GC_UNSAFE;
8939 return res;
8943 MonoArray *
8944 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8946 MonoDomain *domain = mono_domain_get ();
8947 MonoArray *res;
8948 int len, i;
8950 error_init (error);
8951 if (!list)
8952 return NULL;
8954 len = g_list_length (list);
8955 res = mono_array_new_checked (domain, eclass, len, error);
8956 return_val_if_nok (error, NULL);
8958 for (i = 0; list; list = list->next, i++)
8959 mono_array_set (res, gpointer, i, list->data);
8961 return res;
8965 * mono_class_value_size:
8966 * \param klass a class
8968 * This function is used for value types, and return the
8969 * space and the alignment to store that kind of value object.
8971 * \returns the size of a value of kind \p klass
8973 gint32
8974 mono_class_value_size (MonoClass *klass, guint32 *align)
8976 gint32 size;
8978 /* fixme: check disable, because we still have external revereces to
8979 * mscorlib and Dummy Objects
8981 /*g_assert (klass->valuetype);*/
8983 size = mono_class_instance_size (klass) - MONO_ABI_SIZEOF (MonoObject);
8985 if (align)
8986 *align = m_class_get_min_align (klass);
8988 return size;
8992 * mono_object_get_data:
8994 * Return a pointer to the beginning of data inside a MonoObject.
8996 gpointer
8997 mono_object_get_data (MonoObject *o)
8999 return (guint8*)o + MONO_ABI_SIZEOF (MonoObject);
9003 * mono_vtype_get_field_addr:
9005 * Return the address of the FIELD in the valuetype VTYPE.
9007 gpointer
9008 mono_vtype_get_field_addr (gpointer vtype, MonoClassField *field)
9010 return ((char*)vtype) + field->offset - MONO_ABI_SIZEOF (MonoObject);
9014 #if NEVER_DEFINED
9016 * The following section is purely to declare prototypes and
9017 * document the API, as these C files are processed by our
9018 * tool
9022 * mono_array_set:
9023 * \param array array to alter
9024 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
9025 * \param index index into the array
9026 * \param value value to set
9027 * Value Type version: This sets the \p index's element of the \p array
9028 * with elements of size sizeof(type) to the provided \p value.
9030 * This macro does not attempt to perform type checking or bounds checking.
9032 * Use this to set value types in a \c MonoArray.
9034 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
9039 * mono_array_setref:
9040 * \param array array to alter
9041 * \param index index into the array
9042 * \param value value to set
9043 * Reference Type version. This sets the \p index's element of the
9044 * \p array with elements of size sizeof(type) to the provided \p value.
9046 * This macro does not attempt to perform type checking or bounds checking.
9048 * Use this to reference types in a \c MonoArray.
9050 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
9055 * mono_array_get:
9056 * \param array array on which to operate on
9057 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
9058 * \param index index into the array
9060 * Use this macro to retrieve the \p index element of an \p array and
9061 * extract the value assuming that the elements of the array match
9062 * the provided type value.
9064 * This method can be used with both arrays holding value types and
9065 * reference types. For reference types, the \p type parameter should
9066 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
9068 * This macro does not attempt to perform type checking or bounds checking.
9070 * \returns The element at the \p index position in the \p array.
9072 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
9075 #endif