[mono] Enter GC Unsafe mode in some string allocation functions (#19262)
[mono-project.git] / mono / metadata / object.c
bloba69ff1083a9f00e9a0a470c00f21c6389f806138
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/mono-hash-internals.h>
36 #include "mono/metadata/debug-helpers.h"
37 #include <mono/metadata/threads.h>
38 #include <mono/metadata/threads-types.h>
39 #include <mono/metadata/environment.h>
40 #include "mono/metadata/profiler-private.h"
41 #include "mono/metadata/security-manager.h"
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/metadata/w32event.h>
45 #include <mono/metadata/custom-attrs-internals.h>
46 #include <mono/metadata/abi-details.h>
47 #include <mono/utils/strenc.h>
48 #include <mono/utils/mono-counters.h>
49 #include <mono/utils/mono-error-internals.h>
50 #include <mono/utils/mono-memory-model.h>
51 #include <mono/utils/checked-build.h>
52 #include <mono/utils/mono-threads.h>
53 #include <mono/utils/mono-threads-coop.h>
54 #include <mono/utils/mono-logger-internals.h>
55 #include "cominterop.h"
56 #include <mono/utils/w32api.h>
57 #include <mono/utils/unlocked.h>
58 #include "external-only.h"
59 #include "monitor.h"
60 #include "icall-decl.h"
61 #include "icall-signatures.h"
63 // If no symbols in an object file in a static library are referenced, its exports will not be exported.
64 // There are a few workarounds:
65 // 1. Link to .o/.obj files directly on the link command line,
66 // instead of putting them in static libraries.
67 // 2. Use a Windows .def file, or exports on command line, or Unix equivalent.
68 // 3. Have a reference to at least one symbol in the .o/.obj.
69 // That is effectively what this include does.
70 #include "external-only.c"
72 static void
73 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoStringHandleOut string_handle, MonoError *error);
75 static void
76 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoStringHandleOut string_handle, MonoError *error);
78 static void
79 free_main_args (void);
81 static char *
82 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error);
84 static char *
85 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error);
87 static void
88 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
90 /* Class lazy loading functions */
91 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
92 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
93 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
94 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
95 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
96 static GENERATE_TRY_GET_CLASS_WITH_CACHE (execution_context, "System.Threading", "ExecutionContext")
97 static GENERATE_GET_CLASS_WITH_CACHE (asyncresult, "System.Runtime.Remoting.Messaging", "AsyncResult");
99 #define ldstr_lock() mono_coop_mutex_lock (&ldstr_section)
100 #define ldstr_unlock() mono_coop_mutex_unlock (&ldstr_section)
101 static MonoCoopMutex ldstr_section;
105 * mono_runtime_object_init:
106 * \param this_obj the object to initialize
107 * This function calls the zero-argument constructor (which must
108 * exist) for the given object.
110 void
111 mono_runtime_object_init (MonoObject *this_obj)
113 MONO_ENTER_GC_UNSAFE;
114 ERROR_DECL (error);
115 mono_runtime_object_init_checked (this_obj, error);
116 mono_error_assert_ok (error);
117 MONO_EXIT_GC_UNSAFE;
121 * mono_runtime_object_init_handle:
122 * \param this_obj the object to initialize
123 * \param error set on error.
124 * This function calls the zero-argument constructor (which must
125 * exist) for the given object and returns TRUE on success, or FALSE
126 * on error and sets \p error.
128 gboolean
129 mono_runtime_object_init_handle (MonoObjectHandle this_obj, MonoError *error)
131 MONO_REQ_GC_UNSAFE_MODE;
133 HANDLE_FUNCTION_ENTER ();
134 error_init (error);
136 MonoClass * const klass = MONO_HANDLE_GETVAL (this_obj, vtable)->klass;
137 MonoMethod * const method = mono_class_get_method_from_name_checked (klass, ".ctor", 0, 0, error);
138 mono_error_assert_msg_ok (error, "Could not lookup zero argument constructor");
139 g_assertf (method, "Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
141 if (m_class_is_valuetype (method->klass)) {
142 guint gchandle = 0;
143 gpointer raw = mono_object_handle_pin_unbox (this_obj, &gchandle);
144 mono_runtime_invoke_checked (method, raw, NULL, error);
145 mono_gchandle_free_internal (gchandle);
146 } else {
147 mono_runtime_invoke_handle_void (method, this_obj, NULL, error);
150 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
154 * mono_runtime_object_init_checked:
155 * \param this_obj the object to initialize
156 * \param error set on error.
157 * This function calls the zero-argument constructor (which must
158 * exist) for the given object and returns TRUE on success, or FALSE
159 * on error and sets \p error.
161 gboolean
162 mono_runtime_object_init_checked (MonoObject *this_obj_raw, MonoError *error)
164 HANDLE_FUNCTION_ENTER ();
165 MONO_HANDLE_DCL (MonoObject, this_obj);
166 gboolean const result = mono_runtime_object_init_handle (this_obj, error);
167 HANDLE_FUNCTION_RETURN_VAL (result);
170 /* The pseudo algorithm for type initialization from the spec
171 Note it doesn't say anything about domains - only threads.
173 2. If the type is initialized you are done.
174 2.1. If the type is not yet initialized, try to take an
175 initialization lock.
176 2.2. If successful, record this thread as responsible for
177 initializing the type and proceed to step 2.3.
178 2.2.1. If not, see whether this thread or any thread
179 waiting for this thread to complete already holds the lock.
180 2.2.2. If so, return since blocking would create a deadlock. This thread
181 will now see an incompletely initialized state for the type,
182 but no deadlock will arise.
183 2.2.3 If not, block until the type is initialized then return.
184 2.3 Initialize the parent type and then all interfaces implemented
185 by this type.
186 2.4 Execute the type initialization code for this type.
187 2.5 Mark the type as initialized, release the initialization lock,
188 awaken any threads waiting for this type to be initialized,
189 and return.
193 typedef struct
195 MonoNativeThreadId initializing_tid;
196 guint32 waiting_count;
197 gboolean done;
198 MonoCoopMutex mutex;
199 /* condvar used to wait for 'done' becoming TRUE */
200 MonoCoopCond cond;
201 } TypeInitializationLock;
203 /* for locking access to type_initialization_hash and blocked_thread_hash */
204 static MonoCoopMutex type_initialization_section;
206 static void
207 mono_type_initialization_lock (void)
209 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
210 mono_coop_mutex_lock (&type_initialization_section);
213 static void
214 mono_type_initialization_unlock (void)
216 mono_coop_mutex_unlock (&type_initialization_section);
219 static void
220 mono_type_init_lock (TypeInitializationLock *lock)
222 MONO_REQ_GC_NEUTRAL_MODE;
224 mono_coop_mutex_lock (&lock->mutex);
227 static void
228 mono_type_init_unlock (TypeInitializationLock *lock)
230 mono_coop_mutex_unlock (&lock->mutex);
233 /* from vtable to lock */
234 static GHashTable *type_initialization_hash;
236 /* from thread id to thread id being waited on */
237 static GHashTable *blocked_thread_hash;
239 /* Main thread */
240 static MonoThread *main_thread;
242 /* Functions supplied by the runtime */
243 static MonoRuntimeCallbacks callbacks;
246 * mono_thread_set_main:
247 * \param thread thread to set as the main thread
248 * This function can be used to instruct the runtime to treat \p thread
249 * as the main thread, ie, the thread that would normally execute the \c Main
250 * method. This basically means that at the end of \p thread, the runtime will
251 * wait for the existing foreground threads to quit and other such details.
253 void
254 mono_thread_set_main (MonoThread *thread)
256 MONO_REQ_GC_UNSAFE_MODE;
258 static gboolean registered = FALSE;
260 if (!registered) {
261 void *key = thread->internal_thread ? (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread->internal_thread->tid) : NULL;
262 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, key, "Thread Main Object");
263 registered = TRUE;
266 main_thread = thread;
270 * mono_thread_get_main:
272 MonoThread*
273 mono_thread_get_main (void)
275 MONO_REQ_GC_UNSAFE_MODE;
277 return main_thread;
280 void
281 mono_type_initialization_init (void)
283 mono_coop_mutex_init_recursive (&type_initialization_section);
284 type_initialization_hash = g_hash_table_new (NULL, NULL);
285 blocked_thread_hash = g_hash_table_new (NULL, NULL);
286 mono_coop_mutex_init (&ldstr_section);
287 mono_register_jit_icall (ves_icall_string_alloc, mono_icall_sig_object_int, FALSE);
290 void
291 mono_type_initialization_cleanup (void)
293 #if 0
294 /* This is causing race conditions with
295 * mono_release_type_locks
297 mono_coop_mutex_destroy (&type_initialization_section);
298 g_hash_table_destroy (type_initialization_hash);
299 type_initialization_hash = NULL;
300 #endif
301 mono_coop_mutex_destroy (&ldstr_section);
302 g_hash_table_destroy (blocked_thread_hash);
303 blocked_thread_hash = NULL;
305 free_main_args ();
308 static MonoException*
309 mono_get_exception_type_initialization_checked (const gchar *type_name, MonoException* inner_raw, MonoError *error)
311 HANDLE_FUNCTION_ENTER ();
312 MONO_HANDLE_DCL (MonoException, inner);
313 HANDLE_FUNCTION_RETURN_OBJ (mono_get_exception_type_initialization_handle (type_name, inner, error));
317 * get_type_init_exception_for_vtable:
319 * Return the stored type initialization exception for VTABLE.
321 static MonoException*
322 get_type_init_exception_for_vtable (MonoVTable *vtable)
324 MONO_REQ_GC_UNSAFE_MODE;
326 ERROR_DECL (error);
327 MonoDomain *domain = vtable->domain;
328 MonoClass *klass = vtable->klass;
329 MonoException *ex;
330 gchar *full_name;
332 if (!vtable->init_failed)
333 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
336 * If the initializing thread was rudely aborted, the exception is not stored
337 * in the hash.
339 ex = NULL;
340 mono_domain_lock (domain);
341 if (domain->type_init_exception_hash)
342 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
343 mono_domain_unlock (domain);
345 if (!ex) {
346 const char *klass_name_space = m_class_get_name_space (klass);
347 const char *klass_name = m_class_get_name (klass);
348 if (klass_name_space && *klass_name_space)
349 full_name = g_strdup_printf ("%s.%s", klass_name_space, klass_name);
350 else
351 full_name = g_strdup (klass_name);
352 ex = mono_get_exception_type_initialization_checked (full_name, NULL, error);
353 g_free (full_name);
354 return_val_if_nok (error, NULL);
357 return ex;
361 * mono_runtime_class_init:
362 * \param vtable vtable that needs to be initialized
363 * This routine calls the class constructor for \p vtable.
365 void
366 mono_runtime_class_init (MonoVTable *vtable)
368 MONO_REQ_GC_UNSAFE_MODE;
369 ERROR_DECL (error);
371 mono_runtime_class_init_full (vtable, error);
372 mono_error_assert_ok (error);
376 * Returns TRUE if the lock was freed.
377 * LOCKING: Caller should hold type_initialization_lock.
379 static gboolean
380 unref_type_lock (TypeInitializationLock *lock)
382 --lock->waiting_count;
383 if (lock->waiting_count == 0) {
384 mono_coop_mutex_destroy (&lock->mutex);
385 mono_coop_cond_destroy (&lock->cond);
386 g_free (lock);
387 return TRUE;
388 } else {
389 return FALSE;
394 * mono_runtime_run_module_cctor:
395 * \param image the image whose module ctor to run
396 * \param domain the domain to load the module class vtable in
397 * \param error set on error
398 * This routine runs the module ctor for \p image, if it hasn't already run
400 gboolean
401 mono_runtime_run_module_cctor (MonoImage *image, MonoDomain *domain, MonoError *error) {
402 MONO_REQ_GC_UNSAFE_MODE;
404 if (!image->checked_module_cctor) {
405 mono_image_check_for_module_cctor (image);
406 if (image->has_module_cctor) {
407 MonoClass *module_klass;
408 MonoVTable *module_vtable;
410 module_klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | 1, error);
411 if (!module_klass) {
412 return FALSE;
415 module_vtable = mono_class_vtable_checked (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 return TRUE;
426 * mono_runtime_class_init_full:
427 * \param vtable that neeeds to be initialized
428 * \param error set on error
429 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
431 gboolean
432 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
434 MONO_REQ_GC_UNSAFE_MODE;
436 MonoDomain *domain = vtable->domain;
438 error_init (error);
440 if (vtable->initialized)
441 return TRUE;
443 MonoClass *klass = vtable->klass;
445 MonoImage *klass_image = m_class_get_image (klass);
446 if (!mono_runtime_run_module_cctor(klass_image, vtable->domain, error)) {
447 return FALSE;
449 MonoMethod *method = mono_class_get_cctor (klass);
450 if (!method) {
451 vtable->initialized = 1;
452 return TRUE;
455 MonoNativeThreadId tid = mono_native_thread_id_get ();
458 * Due some preprocessing inside a global lock. If we are the first thread
459 * trying to initialize this class, create a separate lock+cond var, and
460 * acquire it before leaving the global lock. The other threads will wait
461 * on this cond var.
464 mono_type_initialization_lock ();
465 /* double check... */
466 if (vtable->initialized) {
467 mono_type_initialization_unlock ();
468 return TRUE;
471 gboolean do_initialization = FALSE;
472 MonoDomain *last_domain = NULL;
473 TypeInitializationLock *lock = NULL;
474 gboolean pending_tae = FALSE;
476 gboolean ret = FALSE;
478 HANDLE_FUNCTION_ENTER ();
480 if (vtable->init_failed) {
481 /* The type initialization already failed once, rethrow the same exception */
482 MonoException *exp = get_type_init_exception_for_vtable (vtable);
483 MONO_HANDLE_NEW (MonoException, exp);
484 /* Reset the stack_trace and trace_ips because the exception is reused */
485 exp->stack_trace = NULL;
486 exp->trace_ips = NULL;
487 mono_type_initialization_unlock ();
488 mono_error_set_exception_instance (error, exp);
489 goto return_false;
491 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
492 if (lock == NULL) {
493 /* This thread will get to do the initialization */
494 if (mono_domain_get () != domain) {
495 /* Transfer into the target domain */
496 last_domain = mono_domain_get ();
497 if (!mono_domain_set_fast (domain, FALSE)) {
498 vtable->initialized = 1;
499 mono_type_initialization_unlock ();
500 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
501 goto return_false;
504 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
505 mono_coop_mutex_init_recursive (&lock->mutex);
506 mono_coop_cond_init (&lock->cond);
507 lock->initializing_tid = tid;
508 lock->waiting_count = 1;
509 lock->done = FALSE;
510 g_hash_table_insert (type_initialization_hash, vtable, lock);
511 do_initialization = TRUE;
512 } else {
513 gpointer blocked;
514 TypeInitializationLock *pending_lock;
516 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
517 mono_type_initialization_unlock ();
518 goto return_true;
520 /* see if the thread doing the initialization is already blocked on this thread */
521 gboolean is_blocked = TRUE;
522 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
523 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
524 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
525 if (!pending_lock->done) {
526 mono_type_initialization_unlock ();
527 goto return_true;
528 } else {
529 /* the thread doing the initialization is blocked on this thread,
530 but on a lock that has already been freed. It just hasn't got
531 time to awake */
532 is_blocked = FALSE;
533 break;
536 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
538 ++lock->waiting_count;
539 /* record the fact that we are waiting on the initializing thread */
540 if (is_blocked)
541 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
543 mono_type_initialization_unlock ();
545 if (do_initialization) {
546 MonoException *exc = NULL;
548 /* We are holding the per-vtable lock, do the actual initialization */
550 mono_threads_begin_abort_protected_block ();
551 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
552 MonoExceptionHandle exch = MONO_HANDLE_NEW (MonoException, exc);
553 mono_threads_end_abort_protected_block ();
555 //exception extracted, error will be set to the right value later
556 if (exc == NULL && !is_ok (error)) { // invoking failed but exc was not set
557 exc = mono_error_convert_to_exception (error);
558 MONO_HANDLE_ASSIGN_RAW (exch, exc);
559 } else
560 mono_error_cleanup (error);
562 error_init_reuse (error);
564 const char *klass_name_space = m_class_get_name_space (klass);
565 const char *klass_name = m_class_get_name (klass);
566 /* If the initialization failed, mark the class as unusable. */
567 /* Avoid infinite loops */
568 if (!(!exc ||
569 (klass_image == mono_defaults.corlib &&
570 !strcmp (klass_name_space, "System") &&
571 !strcmp (klass_name, "TypeInitializationException")))) {
572 vtable->init_failed = 1;
574 char *full_name;
576 if (klass_name_space && *klass_name_space)
577 full_name = g_strdup_printf ("%s.%s", klass_name_space, klass_name);
578 else
579 full_name = g_strdup (klass_name);
581 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
582 MONO_HANDLE_NEW (MonoException, exc_to_throw);
583 g_free (full_name);
585 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
588 * Store the exception object so it could be thrown on subsequent
589 * accesses.
591 mono_domain_lock (domain);
592 if (!domain->type_init_exception_hash)
593 domain->type_init_exception_hash = mono_g_hash_table_new_type_internal (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Type Initialization Exception Table");
594 mono_g_hash_table_insert_internal (domain->type_init_exception_hash, klass, exc_to_throw);
595 mono_domain_unlock (domain);
598 if (last_domain)
599 mono_domain_set_fast (last_domain, TRUE);
601 /* Signal to the other threads that we are done */
602 mono_type_init_lock (lock);
603 lock->done = TRUE;
604 mono_coop_cond_broadcast (&lock->cond);
605 mono_type_init_unlock (lock);
608 * This can happen if the cctor self-aborts. We need to reactivate tae
609 * (next interruption checkpoint will throw it) and make sure we won't
610 * throw tie for the type.
612 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
613 pending_tae = TRUE;
614 mono_thread_resume_interruption (FALSE);
616 } else {
617 /* this just blocks until the initializing thread is done */
618 mono_type_init_lock (lock);
619 while (!lock->done)
620 mono_coop_cond_wait (&lock->cond, &lock->mutex);
621 mono_type_init_unlock (lock);
624 /* Do cleanup and setting vtable->initialized inside the global lock again */
625 mono_type_initialization_lock ();
626 if (!do_initialization)
627 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
630 gboolean deleted = unref_type_lock (lock);
631 if (deleted)
632 g_hash_table_remove (type_initialization_hash, vtable);
635 /* Have to set this here since we check it inside the global lock */
636 if (do_initialization && !vtable->init_failed)
637 vtable->initialized = 1;
638 mono_type_initialization_unlock ();
640 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
641 if (vtable->init_failed && !pending_tae) {
642 /* Either we were the initializing thread or we waited for the initialization */
643 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
644 goto return_false;
646 return_true:
647 ret = TRUE;
648 goto exit;
649 return_false:
650 ret = FALSE;
651 exit:
652 HANDLE_FUNCTION_RETURN_VAL (ret);
655 MonoDomain *
656 mono_vtable_domain_internal (MonoVTable *vtable)
658 return vtable->domain;
661 MonoDomain*
662 mono_vtable_domain (MonoVTable *vtable)
664 MONO_EXTERNAL_ONLY (MonoDomain*, mono_vtable_domain_internal (vtable));
667 MonoClass *
668 mono_vtable_class_internal (MonoVTable *vtable)
670 return vtable->klass;
673 MonoClass*
674 mono_vtable_class (MonoVTable *vtable)
676 MONO_EXTERNAL_ONLY (MonoClass*, mono_vtable_class_internal (vtable));
679 static
680 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
682 MONO_REQ_GC_NEUTRAL_MODE;
684 MonoVTable *vtable = (MonoVTable*)key;
686 TypeInitializationLock *lock = (TypeInitializationLock*) value;
687 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
688 lock->done = TRUE;
690 * Have to set this since it cannot be set by the normal code in
691 * mono_runtime_class_init (). In this case, the exception object is not stored,
692 * and get_type_init_exception_for_class () needs to be aware of this.
694 mono_type_init_lock (lock);
695 vtable->init_failed = 1;
696 mono_coop_cond_broadcast (&lock->cond);
697 mono_type_init_unlock (lock);
698 gboolean deleted = unref_type_lock (lock);
699 if (deleted)
700 return TRUE;
702 return FALSE;
705 void
706 mono_release_type_locks (MonoInternalThread *thread)
708 MONO_REQ_GC_UNSAFE_MODE;
710 mono_type_initialization_lock ();
711 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
712 mono_type_initialization_unlock ();
715 #ifndef DISABLE_REMOTING
717 static gpointer
718 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
720 if (!callbacks.create_remoting_trampoline)
721 g_error ("remoting not installed");
722 return callbacks.create_remoting_trampoline (domain, method, target, error);
725 #endif
727 static MonoImtTrampolineBuilder imt_trampoline_builder;
728 static gboolean always_build_imt_trampolines;
730 #if (MONO_IMT_SIZE > 32)
731 #error "MONO_IMT_SIZE cannot be larger than 32"
732 #endif
734 void
735 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
737 memcpy (&callbacks, cbs, sizeof (*cbs));
740 MonoRuntimeCallbacks*
741 mono_get_runtime_callbacks (void)
743 return &callbacks;
746 void
747 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
749 imt_trampoline_builder = func;
752 void
753 mono_set_always_build_imt_trampolines (gboolean value)
755 always_build_imt_trampolines = value;
759 * mono_compile_method:
760 * \param method The method to compile.
761 * This JIT-compiles the method, and returns the pointer to the native code
762 * produced.
764 gpointer
765 mono_compile_method (MonoMethod *method)
767 gpointer result;
769 MONO_ENTER_GC_UNSAFE;
771 ERROR_DECL (error);
772 result = mono_compile_method_checked (method, error);
773 mono_error_cleanup (error);
775 MONO_EXIT_GC_UNSAFE;
777 return result;
781 * mono_compile_method_checked:
782 * \param method The method to compile.
783 * \param error set on error.
784 * This JIT-compiles the method, and returns the pointer to the native code
785 * produced. On failure returns NULL and sets \p error.
787 gpointer
788 mono_compile_method_checked (MonoMethod *method, MonoError *error)
790 gpointer res;
792 MONO_REQ_GC_NEUTRAL_MODE
794 error_init (error);
796 g_assert (callbacks.compile_method);
797 res = callbacks.compile_method (method, error);
798 return res;
801 gpointer
802 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
804 gpointer res;
806 MONO_REQ_GC_NEUTRAL_MODE;
808 error_init (error);
809 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
810 return res;
813 gpointer
814 mono_runtime_create_delegate_trampoline (MonoClass *klass)
816 MONO_REQ_GC_NEUTRAL_MODE
818 g_assert (callbacks.create_delegate_trampoline);
819 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
823 * mono_runtime_free_method:
824 * \param domain domain where the method is hosted
825 * \param method method to release
826 * This routine is invoked to free the resources associated with
827 * a method that has been JIT compiled. This is used to discard
828 * methods that were used only temporarily (for example, used in marshalling)
830 void
831 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
833 MONO_REQ_GC_NEUTRAL_MODE
835 if (callbacks.free_method)
836 callbacks.free_method (domain, method);
838 mono_method_clear_object (domain, method);
840 mono_free_method (method);
844 * The vtables in the root appdomain are assumed to be reachable by other
845 * roots, and we don't use typed allocation in the other domains.
848 /* The sync block is no longer a GC pointer */
849 #define GC_HEADER_BITMAP (0)
851 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
853 #define MONO_OBJECT_HEADER_BITS (MONO_ABI_SIZEOF (MonoObject) / MONO_ABI_SIZEOF (gpointer))
855 static gsize*
856 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
858 MONO_REQ_GC_NEUTRAL_MODE;
860 MonoClassField *field;
861 MonoClass *p;
862 guint32 pos;
863 int max_size, wordsize;
865 wordsize = TARGET_SIZEOF_VOID_P;
867 if (static_fields)
868 max_size = mono_class_data_size (klass) / wordsize;
869 else
870 max_size = m_class_get_instance_size (klass) / wordsize;
871 if (max_size > size) {
872 g_assert (offset <= 0);
873 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
874 size = max_size;
877 /* An Ephemeron cannot be marked by sgen */
878 if (mono_gc_is_moving () && !static_fields && m_class_get_image (klass) == mono_defaults.corlib && !strcmp ("Ephemeron", m_class_get_name (klass))) {
879 *max_set = 0;
880 memset (bitmap, 0, size / 8);
881 return bitmap;
884 for (p = klass; p != NULL; p = m_class_get_parent (p)) {
885 gpointer iter = NULL;
886 while ((field = mono_class_get_fields_internal (p, &iter))) {
887 MonoType *type;
889 if (static_fields) {
890 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
891 continue;
892 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
893 continue;
894 } else {
895 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
896 continue;
898 /* FIXME: should not happen, flag as type load error */
899 if (field->type->byref)
900 break;
902 if (static_fields && field->offset == -1)
903 /* special static */
904 continue;
906 pos = field->offset / TARGET_SIZEOF_VOID_P;
907 pos += offset;
909 type = mono_type_get_underlying_type (field->type);
910 switch (type->type) {
911 case MONO_TYPE_U:
912 case MONO_TYPE_I:
913 case MONO_TYPE_PTR:
914 case MONO_TYPE_FNPTR:
915 break;
916 case MONO_TYPE_STRING:
917 case MONO_TYPE_SZARRAY:
918 case MONO_TYPE_CLASS:
919 case MONO_TYPE_OBJECT:
920 case MONO_TYPE_ARRAY:
921 g_assert ((field->offset % wordsize) == 0);
923 g_assert (pos < size || pos <= max_size);
924 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
925 *max_set = MAX (*max_set, pos);
926 break;
927 case MONO_TYPE_GENERICINST:
928 if (!mono_type_generic_inst_is_valuetype (type)) {
929 g_assert ((field->offset % wordsize) == 0);
931 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
932 *max_set = MAX (*max_set, pos);
933 break;
934 } else {
935 /* fall through */
937 case MONO_TYPE_VALUETYPE: {
938 MonoClass *fclass = mono_class_from_mono_type_internal (field->type);
939 if (m_class_has_references (fclass)) {
940 /* remove the object header */
941 compute_class_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS, max_set, FALSE);
943 break;
945 case MONO_TYPE_I1:
946 case MONO_TYPE_U1:
947 case MONO_TYPE_I2:
948 case MONO_TYPE_U2:
949 case MONO_TYPE_I4:
950 case MONO_TYPE_U4:
951 case MONO_TYPE_I8:
952 case MONO_TYPE_U8:
953 case MONO_TYPE_R4:
954 case MONO_TYPE_R8:
955 case MONO_TYPE_BOOLEAN:
956 case MONO_TYPE_CHAR:
957 break;
958 default:
959 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
960 break;
963 if (static_fields)
964 break;
966 return bitmap;
970 * mono_class_compute_bitmap:
972 * Mono internal function to compute a bitmap of reference fields in a class.
974 gsize*
975 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
977 MONO_REQ_GC_NEUTRAL_MODE;
979 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
982 #if 0
984 * similar to the above, but sets the bits in the bitmap for any non-ref field
985 * and ignores static fields
987 static gsize*
988 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
990 MonoClassField *field;
991 MonoClass *p;
992 guint32 pos, pos2;
993 int max_size, wordsize;
995 wordsize = TARGET_SIZEOF_VOID_P;
997 max_size = class->instance_size / wordsize;
998 if (max_size >= size)
999 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
1001 for (p = class; p != NULL; p = p->parent) {
1002 gpointer iter = NULL;
1003 while ((field = mono_class_get_fields_internal (p, &iter))) {
1004 MonoType *type;
1006 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
1007 continue;
1008 /* FIXME: should not happen, flag as type load error */
1009 if (field->type->byref)
1010 break;
1012 pos = field->offset / wordsize;
1013 pos += offset;
1015 type = mono_type_get_underlying_type (field->type);
1016 switch (type->type) {
1017 #if SIZEOF_VOID_P == 8
1018 case MONO_TYPE_I:
1019 case MONO_TYPE_U:
1020 case MONO_TYPE_PTR:
1021 case MONO_TYPE_FNPTR:
1022 #endif
1023 case MONO_TYPE_I8:
1024 case MONO_TYPE_U8:
1025 case MONO_TYPE_R8:
1026 if ((((field->offset + 7) / wordsize) + offset) != pos) {
1027 pos2 = ((field->offset + 7) / wordsize) + offset;
1028 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
1030 /* fall through */
1031 #if SIZEOF_VOID_P == 4
1032 case MONO_TYPE_I:
1033 case MONO_TYPE_U:
1034 case MONO_TYPE_PTR:
1035 case MONO_TYPE_FNPTR:
1036 #endif
1037 case MONO_TYPE_I4:
1038 case MONO_TYPE_U4:
1039 case MONO_TYPE_R4:
1040 if ((((field->offset + 3) / wordsize) + offset) != pos) {
1041 pos2 = ((field->offset + 3) / wordsize) + offset;
1042 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
1044 /* fall through */
1045 case MONO_TYPE_CHAR:
1046 case MONO_TYPE_I2:
1047 case MONO_TYPE_U2:
1048 if ((((field->offset + 1) / wordsize) + offset) != pos) {
1049 pos2 = ((field->offset + 1) / wordsize) + offset;
1050 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
1052 /* fall through */
1053 case MONO_TYPE_BOOLEAN:
1054 case MONO_TYPE_I1:
1055 case MONO_TYPE_U1:
1056 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
1057 break;
1058 case MONO_TYPE_STRING:
1059 case MONO_TYPE_SZARRAY:
1060 case MONO_TYPE_CLASS:
1061 case MONO_TYPE_OBJECT:
1062 case MONO_TYPE_ARRAY:
1063 break;
1064 case MONO_TYPE_GENERICINST:
1065 if (!mono_type_generic_inst_is_valuetype (type)) {
1066 break;
1067 } else {
1068 /* fall through */
1070 case MONO_TYPE_VALUETYPE: {
1071 MonoClass *fclass = mono_class_from_mono_type_internal (field->type);
1072 /* remove the object header */
1073 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS);
1074 break;
1076 default:
1077 g_assert_not_reached ();
1078 break;
1082 return bitmap;
1086 * mono_class_insecure_overlapping:
1087 * check if a class with explicit layout has references and non-references
1088 * fields overlapping.
1090 * Returns: TRUE if it is insecure to load the type.
1092 gboolean
1093 mono_class_insecure_overlapping (MonoClass *klass)
1095 int max_set = 0;
1096 gsize *bitmap;
1097 gsize default_bitmap [4] = {0};
1098 gsize *nrbitmap;
1099 gsize default_nrbitmap [4] = {0};
1100 int i, insecure = FALSE;
1101 return FALSE;
1103 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1104 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
1106 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
1107 int idx = i % (sizeof (bitmap [0]) * 8);
1108 if (bitmap [idx] & nrbitmap [idx]) {
1109 insecure = TRUE;
1110 break;
1113 if (bitmap != default_bitmap)
1114 g_free (bitmap);
1115 if (nrbitmap != default_nrbitmap)
1116 g_free (nrbitmap);
1117 if (insecure) {
1118 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1119 return FALSE;
1121 return insecure;
1123 #endif
1125 MonoStringHandle
1126 ves_icall_string_alloc_impl (int length, MonoError *error)
1128 MonoString *s = mono_string_new_size_checked (mono_domain_get (), length, error);
1129 return_val_if_nok (error, NULL_HANDLE_STRING);
1130 return MONO_HANDLE_NEW (MonoString, s);
1133 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
1135 /* LOCKING: Acquires the loader lock */
1137 * Sets the following fields in KLASS:
1138 * - gc_desc
1139 * - gc_descr_inited
1141 void
1142 mono_class_compute_gc_descriptor (MonoClass *klass)
1144 MONO_REQ_GC_NEUTRAL_MODE;
1146 int max_set = 0;
1147 gsize *bitmap;
1148 gsize default_bitmap [4] = {0};
1149 MonoGCDescriptor gc_descr;
1151 if (!m_class_is_inited (klass))
1152 mono_class_init_internal (klass);
1154 if (m_class_is_gc_descr_inited (klass))
1155 return;
1157 bitmap = default_bitmap;
1158 if (klass == mono_defaults.string_class) {
1159 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1160 } else if (m_class_get_rank (klass)) {
1161 MonoClass *klass_element_class = m_class_get_element_class (klass);
1162 mono_class_compute_gc_descriptor (klass_element_class);
1163 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass_element_class))) {
1164 gsize abm = 1;
1165 gc_descr = mono_gc_make_descr_for_array (m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1166 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1167 class->name_space, class->name);*/
1168 } else {
1169 /* remove the object header */
1170 bitmap = mono_class_compute_bitmap (klass_element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(MONO_OBJECT_HEADER_BITS), &max_set, FALSE);
1171 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));
1172 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1173 class->name_space, class->name);*/
1175 } else {
1176 /*static int count = 0;
1177 if (count++ > 58)
1178 return;*/
1179 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1181 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1182 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1184 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1186 if (m_class_has_weak_fields (klass)) {
1187 gsize *weak_bitmap = NULL;
1188 int weak_bitmap_nbits = 0;
1190 weak_bitmap = (gsize *)mono_class_alloc0 (klass, m_class_get_instance_size (klass) / sizeof (gsize));
1191 if (mono_class_has_static_metadata (klass)) {
1192 for (MonoClass *p = klass; p != NULL; p = m_class_get_parent (p)) {
1193 gpointer iter = NULL;
1194 guint32 first_field_idx = mono_class_get_first_field_idx (p);
1195 MonoClassField *field;
1197 MonoClassField *p_fields = m_class_get_fields (p);
1198 MonoImage *p_image = m_class_get_image (p);
1199 while ((field = mono_class_get_fields_internal (p, &iter))) {
1200 guint32 field_idx = first_field_idx + (field - p_fields);
1201 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p_image, field_idx + 1)) {
1202 int pos = field->offset / sizeof (gpointer);
1203 if (pos + 1 > weak_bitmap_nbits)
1204 weak_bitmap_nbits = pos + 1;
1205 weak_bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
1211 for (int pos = 0; pos < weak_bitmap_nbits; ++pos) {
1212 if (weak_bitmap [pos / BITMAP_EL_SIZE] & ((gsize)1) << (pos % BITMAP_EL_SIZE)) {
1213 /* Clear the normal bitmap so these refs don't keep an object alive */
1214 bitmap [pos / BITMAP_EL_SIZE] &= ~(((gsize)1) << (pos % BITMAP_EL_SIZE));
1218 mono_loader_lock ();
1219 mono_class_set_weak_bitmap (klass, weak_bitmap_nbits, weak_bitmap);
1220 mono_loader_unlock ();
1223 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, m_class_get_instance_size (klass));
1226 if (bitmap != default_bitmap)
1227 g_free (bitmap);
1229 /* Publish the data */
1230 mono_class_publish_gc_descriptor (klass, gc_descr);
1234 * field_is_special_static:
1235 * @fklass: The MonoClass to look up.
1236 * @field: The MonoClassField describing the field.
1238 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1239 * SPECIAL_STATIC_NONE otherwise.
1241 static gint32
1242 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1244 MONO_REQ_GC_NEUTRAL_MODE;
1246 ERROR_DECL (error);
1247 MonoCustomAttrInfo *ainfo;
1248 int i;
1249 ainfo = mono_custom_attrs_from_field_checked (fklass, field, error);
1250 mono_error_cleanup (error); /* FIXME don't swallow the error? */
1251 if (!ainfo)
1252 return FALSE;
1253 for (i = 0; i < ainfo->num_attrs; ++i) {
1254 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1255 if (m_class_get_image (klass) == mono_defaults.corlib) {
1256 const char *klass_name = m_class_get_name (klass);
1257 if (strcmp (klass_name, "ThreadStaticAttribute") == 0) {
1258 mono_custom_attrs_free (ainfo);
1259 return SPECIAL_STATIC_THREAD;
1261 else if (strcmp (klass_name, "ContextStaticAttribute") == 0) {
1262 mono_custom_attrs_free (ainfo);
1263 return SPECIAL_STATIC_CONTEXT;
1267 mono_custom_attrs_free (ainfo);
1268 return SPECIAL_STATIC_NONE;
1271 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1272 #define mix(a,b,c) { \
1273 a -= c; a ^= rot(c, 4); c += b; \
1274 b -= a; b ^= rot(a, 6); a += c; \
1275 c -= b; c ^= rot(b, 8); b += a; \
1276 a -= c; a ^= rot(c,16); c += b; \
1277 b -= a; b ^= rot(a,19); a += c; \
1278 c -= b; c ^= rot(b, 4); b += a; \
1280 #define mono_final(a,b,c) { \
1281 c ^= b; c -= rot(b,14); \
1282 a ^= c; a -= rot(c,11); \
1283 b ^= a; b -= rot(a,25); \
1284 c ^= b; c -= rot(b,16); \
1285 a ^= c; a -= rot(c,4); \
1286 b ^= a; b -= rot(a,14); \
1287 c ^= b; c -= rot(b,24); \
1291 * mono_method_get_imt_slot:
1293 * The IMT slot is embedded into AOTed code, so this must return the same value
1294 * for the same method across all executions. This means:
1295 * - pointers shouldn't be used as hash values.
1296 * - mono_metadata_str_hash () should be used for hashing strings.
1298 guint32
1299 mono_method_get_imt_slot (MonoMethod *method)
1301 MONO_REQ_GC_NEUTRAL_MODE;
1303 MonoMethodSignature *sig;
1304 int hashes_count;
1305 guint32 *hashes_start, *hashes;
1306 guint32 a, b, c;
1307 int i;
1309 /* This can be used to stress tests the collision code */
1310 //return 0;
1313 * We do this to simplify generic sharing. It will hurt
1314 * performance in cases where a class implements two different
1315 * instantiations of the same generic interface.
1316 * The code in build_imt_slots () depends on this.
1318 if (method->is_inflated)
1319 method = ((MonoMethodInflated*)method)->declaring;
1321 sig = mono_method_signature_internal (method);
1322 hashes_count = sig->param_count + 4;
1323 hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1324 hashes = hashes_start;
1326 if (! MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass)) {
1327 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1328 m_class_get_name_space (method->klass), m_class_get_name (method->klass), method->name);
1331 /* Initialize hashes */
1332 hashes [0] = mono_metadata_str_hash (m_class_get_name (method->klass));
1333 hashes [1] = mono_metadata_str_hash (m_class_get_name_space (method->klass));
1334 hashes [2] = mono_metadata_str_hash (method->name);
1335 hashes [3] = mono_metadata_type_hash (sig->ret);
1336 for (i = 0; i < sig->param_count; i++) {
1337 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1340 /* Setup internal state */
1341 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1343 /* Handle most of the hashes */
1344 while (hashes_count > 3) {
1345 a += hashes [0];
1346 b += hashes [1];
1347 c += hashes [2];
1348 mix (a,b,c);
1349 hashes_count -= 3;
1350 hashes += 3;
1353 /* Handle the last 3 hashes (all the case statements fall through) */
1354 switch (hashes_count) {
1355 case 3 : c += hashes [2];
1356 case 2 : b += hashes [1];
1357 case 1 : a += hashes [0];
1358 mono_final (a,b,c);
1359 case 0: /* nothing left to add */
1360 break;
1363 g_free (hashes_start);
1364 /* Report the result */
1365 return c % MONO_IMT_SIZE;
1367 #undef rot
1368 #undef mix
1369 #undef mono_final
1371 #define DEBUG_IMT 0
1373 static void
1374 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1375 MONO_REQ_GC_NEUTRAL_MODE;
1377 guint32 imt_slot = mono_method_get_imt_slot (method);
1378 MonoImtBuilderEntry *entry;
1380 if (slot_num >= 0 && imt_slot != slot_num) {
1381 /* we build just a single imt slot and this is not it */
1382 return;
1385 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1386 entry->key = method;
1387 entry->value.vtable_slot = vtable_slot;
1388 entry->next = imt_builder [imt_slot];
1389 if (imt_builder [imt_slot] != NULL) {
1390 entry->children = imt_builder [imt_slot]->children + 1;
1391 if (entry->children == 1) {
1392 UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1393 *imt_collisions_bitmap |= (1 << imt_slot);
1395 } else {
1396 entry->children = 0;
1397 UnlockedIncrement (&mono_stats.imt_used_slots);
1399 imt_builder [imt_slot] = entry;
1400 #if DEBUG_IMT
1402 char *method_name = mono_method_full_name (method, TRUE);
1403 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1404 method, method_name, imt_slot, vtable_slot, entry->children);
1405 g_free (method_name);
1407 #endif
1410 #if DEBUG_IMT
1411 static void
1412 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1413 if (e != NULL) {
1414 MonoMethod *method = e->key;
1415 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1416 message,
1417 num,
1418 method,
1419 method->klass->name_space,
1420 method->klass->name,
1421 method->name);
1422 } else {
1423 printf (" * %s: NULL\n", message);
1426 #endif
1428 static int
1429 compare_imt_builder_entries (const void *p1, const void *p2) {
1430 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1431 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1433 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1436 static int
1437 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1439 MONO_REQ_GC_NEUTRAL_MODE;
1441 int count = end - start;
1442 int chunk_start = out_array->len;
1443 if (count < 4) {
1444 int i;
1445 for (i = start; i < end; ++i) {
1446 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1447 item->key = sorted_array [i]->key;
1448 item->value = sorted_array [i]->value;
1449 item->has_target_code = sorted_array [i]->has_target_code;
1450 item->is_equals = TRUE;
1451 if (i < end - 1)
1452 item->check_target_idx = out_array->len + 1;
1453 else
1454 item->check_target_idx = 0;
1455 g_ptr_array_add (out_array, item);
1457 } else {
1458 int middle = start + count / 2;
1459 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1461 item->key = sorted_array [middle]->key;
1462 item->is_equals = FALSE;
1463 g_ptr_array_add (out_array, item);
1464 imt_emit_ir (sorted_array, start, middle, out_array);
1465 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1467 return chunk_start;
1470 static GPtrArray*
1471 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1472 MONO_REQ_GC_NEUTRAL_MODE;
1474 int number_of_entries = entries->children + 1;
1475 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1476 GPtrArray *result = g_ptr_array_new ();
1477 MonoImtBuilderEntry *current_entry;
1478 int i;
1480 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1481 sorted_array [i] = current_entry;
1483 mono_qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1485 /*for (i = 0; i < number_of_entries; i++) {
1486 print_imt_entry (" sorted array:", sorted_array [i], i);
1489 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1491 g_free (sorted_array);
1492 return result;
1495 static gpointer
1496 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1498 MONO_REQ_GC_NEUTRAL_MODE;
1500 if (imt_builder_entry != NULL) {
1501 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1502 /* No collision, return the vtable slot contents */
1503 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1504 } else {
1505 /* Collision, build the trampoline */
1506 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1507 gpointer result;
1508 int i;
1509 result = imt_trampoline_builder (vtable, domain,
1510 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1511 for (i = 0; i < imt_ir->len; ++i)
1512 g_free (g_ptr_array_index (imt_ir, i));
1513 g_ptr_array_free (imt_ir, TRUE);
1514 return result;
1516 } else {
1517 if (fail_tramp)
1518 return fail_tramp;
1519 else
1520 /* Empty slot */
1521 return NULL;
1525 static MonoImtBuilderEntry*
1526 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1529 * LOCKING: requires the loader and domain locks.
1532 static void
1533 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1535 MONO_REQ_GC_NEUTRAL_MODE;
1537 int i;
1538 GSList *list_item;
1539 guint32 imt_collisions_bitmap = 0;
1540 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1541 int method_count = 0;
1542 gboolean record_method_count_for_max_collisions = FALSE;
1543 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1545 #if DEBUG_IMT
1546 printf ("Building IMT for class %s.%s slot %d\n", m_class_get_name_space (klass), m_class_get_name (klass), slot_num);
1547 #endif
1548 int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass);
1549 MonoClass **klass_interfaces_packed = m_class_get_interfaces_packed (klass);
1550 guint16 *klass_interface_offsets_packed = m_class_get_interface_offsets_packed (klass);
1551 for (i = 0; i < klass_interface_offsets_count; ++i) {
1552 MonoClass *iface = klass_interfaces_packed [i];
1553 int interface_offset = klass_interface_offsets_packed [i];
1554 int method_slot_in_interface, vt_slot;
1556 if (mono_class_has_variant_generic_params (iface))
1557 has_variant_iface = TRUE;
1559 mono_class_setup_methods (iface);
1560 vt_slot = interface_offset;
1561 int mcount = mono_class_get_method_count (iface);
1562 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1563 MonoMethod *method;
1565 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1567 * The imt slot of the method is the same as for its declaring method,
1568 * see the comment in mono_method_get_imt_slot (), so we can
1569 * avoid inflating methods which will be discarded by
1570 * add_imt_builder_entry anyway.
1572 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1573 if (mono_method_get_imt_slot (method) != slot_num) {
1574 vt_slot ++;
1575 continue;
1578 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1579 if (method->is_generic) {
1580 has_generic_virtual = TRUE;
1581 vt_slot ++;
1582 continue;
1585 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL) {
1586 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1587 vt_slot ++;
1591 if (extra_interfaces) {
1592 int interface_offset = m_class_get_vtable_size (klass);
1594 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1595 MonoClass* iface = (MonoClass *)list_item->data;
1596 int method_slot_in_interface;
1597 int mcount = mono_class_get_method_count (iface);
1598 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1599 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1601 if (method->is_generic)
1602 has_generic_virtual = TRUE;
1603 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1605 interface_offset += mcount;
1608 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1609 /* overwrite the imt slot only if we're building all the entries or if
1610 * we're building this specific one
1612 if (slot_num < 0 || i == slot_num) {
1613 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1615 if (entries) {
1616 if (imt_builder [i]) {
1617 MonoImtBuilderEntry *entry;
1619 /* Link entries with imt_builder [i] */
1620 for (entry = entries; entry->next; entry = entry->next) {
1621 #if DEBUG_IMT
1622 MonoMethod *method = (MonoMethod*)entry->key;
1623 char *method_name = mono_method_full_name (method, TRUE);
1624 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1625 g_free (method_name);
1626 #endif
1628 entry->next = imt_builder [i];
1629 entries->children += imt_builder [i]->children + 1;
1631 imt_builder [i] = entries;
1634 if (has_generic_virtual || has_variant_iface) {
1636 * There might be collisions later when the the trampoline is expanded.
1638 imt_collisions_bitmap |= (1 << i);
1641 * The IMT trampoline might be called with an instance of one of the
1642 * generic virtual methods, so has to fallback to the IMT trampoline.
1644 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1645 } else {
1646 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1648 #if DEBUG_IMT
1649 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1650 #endif
1653 if (imt_builder [i] != NULL) {
1654 int methods_in_slot = imt_builder [i]->children + 1;
1655 if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1656 UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1657 record_method_count_for_max_collisions = TRUE;
1659 method_count += methods_in_slot;
1663 UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1664 if (record_method_count_for_max_collisions) {
1665 UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1668 for (i = 0; i < MONO_IMT_SIZE; i++) {
1669 MonoImtBuilderEntry* entry = imt_builder [i];
1670 while (entry != NULL) {
1671 MonoImtBuilderEntry* next = entry->next;
1672 g_free (entry);
1673 entry = next;
1676 g_free (imt_builder);
1677 /* we OR the bitmap since we may build just a single imt slot at a time */
1678 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1681 static void
1682 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1683 MONO_REQ_GC_NEUTRAL_MODE;
1685 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1689 * mono_vtable_build_imt_slot:
1690 * \param vtable virtual object table struct
1691 * \param imt_slot slot in the IMT table
1692 * Fill the given \p imt_slot in the IMT table of \p vtable with
1693 * a trampoline or a trampoline for the case of collisions.
1694 * This is part of the internal mono API.
1695 * LOCKING: Take the domain lock.
1697 void
1698 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1700 MONO_REQ_GC_NEUTRAL_MODE;
1702 gpointer *imt = (gpointer*)vtable;
1703 imt -= MONO_IMT_SIZE;
1704 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1706 /* no support for extra interfaces: the proxy objects will need
1707 * to build the complete IMT
1708 * Update and heck needs to ahppen inside the proper domain lock, as all
1709 * the changes made to a MonoVTable.
1711 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1712 mono_domain_lock (vtable->domain);
1713 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1714 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1715 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1716 mono_domain_unlock (vtable->domain);
1717 mono_loader_unlock ();
1720 #define THUNK_THRESHOLD 10
1723 * mono_method_alloc_generic_virtual_trampoline:
1724 * \param domain a domain
1725 * \param size size in bytes
1726 * Allocs \p size bytes to be used for the code of a generic virtual
1727 * trampoline. It's either allocated from the domain's code manager or
1728 * reused from a previously invalidated piece.
1729 * LOCKING: The domain lock must be held.
1731 gpointer
1732 (mono_method_alloc_generic_virtual_trampoline) (MonoDomain *domain, int size)
1734 MONO_REQ_GC_NEUTRAL_MODE;
1736 static gboolean inited = FALSE;
1737 static int generic_virtual_trampolines_size = 0;
1739 if (!inited) {
1740 mono_counters_register ("Generic virtual trampoline bytes",
1741 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1742 inited = TRUE;
1744 generic_virtual_trampolines_size += size;
1746 return mono_domain_code_reserve (domain, size);
1749 typedef struct _GenericVirtualCase {
1750 MonoMethod *method;
1751 gpointer code;
1752 int count;
1753 struct _GenericVirtualCase *next;
1754 } GenericVirtualCase;
1757 * get_generic_virtual_entries:
1759 * Return IMT entries for the generic virtual method instances and
1760 * variant interface methods for vtable slot
1761 * VTABLE_SLOT.
1763 static MonoImtBuilderEntry*
1764 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1766 MONO_REQ_GC_NEUTRAL_MODE;
1768 GenericVirtualCase *list;
1769 MonoImtBuilderEntry *entries;
1771 mono_domain_lock (domain);
1772 if (!domain->generic_virtual_cases)
1773 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1775 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1777 entries = NULL;
1778 for (; list; list = list->next) {
1779 MonoImtBuilderEntry *entry;
1781 if (list->count < THUNK_THRESHOLD)
1782 continue;
1784 entry = g_new0 (MonoImtBuilderEntry, 1);
1785 entry->key = list->method;
1786 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1787 entry->has_target_code = 1;
1788 if (entries)
1789 entry->children = entries->children + 1;
1790 entry->next = entries;
1791 entries = entry;
1794 mono_domain_unlock (domain);
1796 /* FIXME: Leaking memory ? */
1797 return entries;
1801 * \param domain a domain
1802 * \param vtable_slot pointer to the vtable slot
1803 * \param method the inflated generic virtual method
1804 * \param code the method's code
1806 * Registers a call via unmanaged code to a generic virtual method
1807 * instantiation or variant interface method. If the number of calls reaches a threshold
1808 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1809 * virtual method trampoline.
1811 void
1812 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1813 gpointer *vtable_slot,
1814 MonoMethod *method, gpointer code)
1816 MONO_REQ_GC_NEUTRAL_MODE;
1818 static gboolean inited = FALSE;
1819 static int num_added = 0;
1820 static int num_freed = 0;
1822 GenericVirtualCase *gvc, *list;
1823 MonoImtBuilderEntry *entries;
1824 int i;
1825 GPtrArray *sorted;
1827 mono_domain_lock (domain);
1828 if (!domain->generic_virtual_cases)
1829 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1831 if (!inited) {
1832 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1833 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1834 inited = TRUE;
1837 /* Check whether the case was already added */
1838 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1839 gvc = list;
1840 while (gvc) {
1841 if (gvc->method == method)
1842 break;
1843 gvc = gvc->next;
1846 /* If not found, make a new one */
1847 if (!gvc) {
1848 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1849 gvc->method = method;
1850 gvc->code = code;
1851 gvc->count = 0;
1852 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1854 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1856 num_added++;
1859 if (++gvc->count == THUNK_THRESHOLD) {
1860 gpointer *old_thunk = (void **)*vtable_slot;
1861 gpointer vtable_trampoline = NULL;
1862 gpointer imt_trampoline = NULL;
1864 if ((gpointer)vtable_slot < (gpointer)vtable) {
1865 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1866 int imt_slot = MONO_IMT_SIZE + displacement;
1868 /* Force the rebuild of the trampoline at the next call */
1869 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1870 *vtable_slot = imt_trampoline;
1871 } else {
1872 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1874 entries = get_generic_virtual_entries (domain, vtable_slot);
1876 sorted = imt_sort_slot_entries (entries);
1878 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1879 vtable_trampoline);
1881 while (entries) {
1882 MonoImtBuilderEntry *next = entries->next;
1883 g_free (entries);
1884 entries = next;
1887 for (i = 0; i < sorted->len; ++i)
1888 g_free (g_ptr_array_index (sorted, i));
1889 g_ptr_array_free (sorted, TRUE);
1891 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1892 num_freed ++;
1896 mono_domain_unlock (domain);
1899 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1902 * mono_class_vtable:
1903 * \param domain the application domain
1904 * \param class the class to initialize
1905 * VTables are domain specific because we create domain specific code, and
1906 * they contain the domain specific static class data.
1907 * On failure, NULL is returned, and \c class->exception_type is set.
1909 MonoVTable *
1910 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1912 MonoVTable* vtable;
1913 MONO_ENTER_GC_UNSAFE;
1914 ERROR_DECL (error);
1915 vtable = mono_class_vtable_checked (domain, klass, error);
1916 mono_error_cleanup (error);
1917 MONO_EXIT_GC_UNSAFE;
1918 return vtable;
1922 * mono_class_vtable_checked:
1923 * \param domain the application domain
1924 * \param class the class to initialize
1925 * \param error set on failure.
1926 * VTables are domain specific because we create domain specific code, and
1927 * they contain the domain specific static class data.
1929 MonoVTable *
1930 mono_class_vtable_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
1932 MONO_REQ_GC_UNSAFE_MODE;
1934 MonoClassRuntimeInfo *runtime_info;
1936 error_init (error);
1938 g_assert (klass);
1940 if (mono_class_has_failure (klass)) {
1941 mono_error_set_for_class_failure (error, klass);
1942 return NULL;
1945 /* this check can be inlined in jitted code, too */
1946 runtime_info = m_class_get_runtime_info (klass);
1947 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1948 return runtime_info->domain_vtables [domain->domain_id];
1949 return mono_class_create_runtime_vtable (domain, klass, error);
1953 * mono_class_try_get_vtable:
1954 * \param domain the application domain
1955 * \param class the class to initialize
1956 * This function tries to get the associated vtable from \p class if
1957 * it was already created.
1959 MonoVTable *
1960 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1962 MONO_REQ_GC_NEUTRAL_MODE;
1964 MonoClassRuntimeInfo *runtime_info;
1966 g_assert (klass);
1968 runtime_info = m_class_get_runtime_info (klass);
1969 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1970 return runtime_info->domain_vtables [domain->domain_id];
1971 return NULL;
1974 static gpointer*
1975 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1977 MONO_REQ_GC_NEUTRAL_MODE;
1979 size_t alloc_offset;
1982 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1983 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1984 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1986 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1987 g_assert ((imt_table_bytes & 7) == 4);
1988 vtable_size += 4;
1989 alloc_offset = 4;
1990 } else {
1991 alloc_offset = 0;
1994 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1997 static MonoVTable *
1998 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
2000 MONO_REQ_GC_UNSAFE_MODE;
2002 HANDLE_FUNCTION_ENTER ();
2004 MonoVTable *vt;
2005 MonoClassRuntimeInfo *runtime_info;
2006 MonoClassField *field;
2007 char *t;
2008 int i, vtable_slots;
2009 size_t imt_table_bytes;
2010 int gc_bits;
2011 guint32 vtable_size, class_size;
2012 gpointer iter;
2013 gpointer *interface_offsets;
2014 gboolean is_primitive_type_array = FALSE;
2015 gboolean use_interpreter = callbacks.is_interpreter_enabled ();
2017 mono_loader_lock (); /*FIXME mono_class_init_internal acquires it*/
2018 mono_domain_lock (domain);
2020 runtime_info = m_class_get_runtime_info (klass);
2021 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
2022 mono_domain_unlock (domain);
2023 mono_loader_unlock ();
2024 vt = runtime_info->domain_vtables [domain->domain_id];
2025 goto exit;
2027 if (!m_class_is_inited (klass) || mono_class_has_failure (klass)) {
2028 if (!mono_class_init_internal (klass) || mono_class_has_failure (klass)) {
2029 mono_domain_unlock (domain);
2030 mono_loader_unlock ();
2031 mono_error_set_for_class_failure (error, klass);
2032 goto return_null;
2036 /* Array types require that their element type be valid*/
2037 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_ARRAY || m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
2038 MonoClass *element_class = m_class_get_element_class (klass);
2039 is_primitive_type_array = m_class_is_primitive (element_class);
2040 if (!m_class_is_inited (element_class))
2041 mono_class_init_internal (element_class);
2043 /*mono_class_init_internal can leave the vtable layout to be lazily done and we can't afford this here*/
2044 if (!mono_class_has_failure (element_class) && !m_class_get_vtable_size (element_class))
2045 mono_class_setup_vtable (element_class);
2047 if (mono_class_has_failure (element_class)) {
2048 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2049 if (!mono_class_has_failure (klass))
2050 mono_class_set_type_load_failure (klass, "");
2051 mono_domain_unlock (domain);
2052 mono_loader_unlock ();
2053 mono_error_set_for_class_failure (error, klass);
2054 goto return_null;
2059 * For some classes, mono_class_init_internal () already computed klass->vtable_size, and
2060 * that is all that is needed because of the vtable trampolines.
2062 if (!m_class_get_vtable_size (klass))
2063 mono_class_setup_vtable (klass);
2065 if (mono_class_is_ginst (klass) && !m_class_get_vtable (klass))
2066 mono_class_check_vtable_constraints (klass, NULL);
2068 /* Initialize klass->has_finalize */
2069 mono_class_has_finalizer (klass);
2071 if (mono_class_has_failure (klass)) {
2072 mono_domain_unlock (domain);
2073 mono_loader_unlock ();
2074 mono_error_set_for_class_failure (error, klass);
2075 goto return_null;
2078 vtable_slots = m_class_get_vtable_size (klass);
2079 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2080 class_size = mono_class_data_size (klass);
2081 if (class_size)
2082 vtable_slots++;
2084 if (m_class_get_interface_offsets_count (klass)) {
2085 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2086 /* Interface table for the interpreter */
2087 if (use_interpreter)
2088 imt_table_bytes *= 2;
2089 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2090 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2091 } else {
2092 imt_table_bytes = 0;
2095 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2097 UnlockedIncrement (&mono_stats.used_class_count);
2098 UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
2100 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2101 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2102 /* If on interp, skip the interp interface table */
2103 if (use_interpreter)
2104 interface_offsets = (gpointer*)((char*)interface_offsets + imt_table_bytes / 2);
2105 g_assert (!((gsize)vt & 7));
2107 vt->klass = klass;
2108 vt->rank = m_class_get_rank (klass);
2109 vt->domain = domain;
2110 if ((vt->rank > 0) || klass == mono_get_string_class ())
2111 vt->flags |= MONO_VT_FLAG_ARRAY_OR_STRING;
2113 if (m_class_has_references (klass))
2114 vt->flags |= MONO_VT_FLAG_HAS_REFERENCES;
2116 if (is_primitive_type_array)
2117 vt->flags |= MONO_VT_FLAG_ARRAY_IS_PRIMITIVE;
2119 MONO_PROFILER_RAISE (vtable_loading, (vt));
2121 mono_class_compute_gc_descriptor (klass);
2123 * For Boehm:
2124 * We can't use typed allocation in the non-root domains, since the
2125 * collector needs the GC descriptor stored in the vtable even after
2126 * the mempool containing the vtable is destroyed when the domain is
2127 * unloaded. An alternative might be to allocate vtables in the GC
2128 * heap, but this does not seem to work (it leads to crashes inside
2129 * libgc). If that approach is tried, two gc descriptors need to be
2130 * allocated for each class: one for the root domain, and one for all
2131 * other domains. The second descriptor should contain a bit for the
2132 * vtable field in MonoObject, since we can no longer assume the
2133 * vtable is reachable by other roots after the appdomain is unloaded.
2135 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
2136 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2137 else
2138 vt->gc_descr = m_class_get_gc_descr (klass);
2140 gc_bits = mono_gc_get_vtable_bits (klass);
2141 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2143 vt->gc_bits = gc_bits;
2145 if (class_size) {
2146 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2147 if (m_class_has_static_refs (klass)) {
2148 MonoGCDescriptor statics_gc_descr;
2149 int max_set = 0;
2150 gsize default_bitmap [4] = {0};
2151 gsize *bitmap;
2153 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2154 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2155 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2156 vt->vtable [m_class_get_vtable_size (klass)] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, vt, "Static Fields");
2158 if (bitmap != default_bitmap)
2159 g_free (bitmap);
2160 } else {
2161 vt->vtable [m_class_get_vtable_size (klass)] = mono_domain_alloc0 (domain, class_size);
2163 vt->has_static_fields = TRUE;
2164 UnlockedAdd (&mono_stats.class_static_data_size, class_size);
2167 iter = NULL;
2168 while ((field = mono_class_get_fields_internal (klass, &iter))) {
2169 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2170 continue;
2171 if (mono_field_is_deleted (field))
2172 continue;
2173 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2174 gint32 special_static = m_class_has_no_special_static_fields (klass) ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2175 if (special_static != SPECIAL_STATIC_NONE) {
2176 guint32 size, offset;
2177 gint32 align;
2178 gsize default_bitmap [4] = {0};
2179 gsize *bitmap;
2180 int max_set = 0;
2181 int numbits;
2182 MonoClass *fclass;
2183 if (mono_type_is_reference (field->type)) {
2184 default_bitmap [0] = 1;
2185 numbits = 1;
2186 bitmap = default_bitmap;
2187 } else if (mono_type_is_struct (field->type)) {
2188 fclass = mono_class_from_mono_type_internal (field->type);
2189 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(MONO_OBJECT_HEADER_BITS), &max_set, FALSE);
2190 numbits = max_set + 1;
2191 } else {
2192 default_bitmap [0] = 0;
2193 numbits = 0;
2194 bitmap = default_bitmap;
2196 size = mono_type_size (field->type, &align);
2197 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2198 if (!domain->special_static_fields)
2199 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2200 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2201 if (bitmap != default_bitmap)
2202 g_free (bitmap);
2204 * This marks the field as special static to speed up the
2205 * checks in mono_field_static_get/set_value ().
2207 field->offset = -1;
2208 continue;
2211 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2212 MonoClass *fklass = mono_class_from_mono_type_internal (field->type);
2213 const char *data = mono_field_get_data (field);
2215 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2216 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2217 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2218 if (!data)
2219 continue;
2220 if (m_class_is_valuetype (fklass)) {
2221 memcpy (t, data, mono_class_value_size (fklass, NULL));
2222 } else {
2223 /* it's a pointer type: add check */
2224 g_assert ((m_class_get_byval_arg (fklass)->type == MONO_TYPE_PTR) || (m_class_get_byval_arg (fklass)->type == MONO_TYPE_FNPTR));
2225 *t = *(char *)data;
2227 continue;
2231 vt->max_interface_id = m_class_get_max_interface_id (klass);
2232 vt->interface_bitmap = m_class_get_interface_bitmap (klass);
2234 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2235 // class->name, klass->interface_offsets_count);
2237 /* Initialize vtable */
2238 if (callbacks.get_vtable_trampoline) {
2239 // This also covers the AOT case
2240 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2241 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2243 } else {
2244 mono_class_setup_vtable (klass);
2246 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2247 MonoMethod *cm;
2249 cm = m_class_get_vtable (klass) [i];
2250 if (cm) {
2251 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2252 if (!is_ok (error)) {
2253 mono_domain_unlock (domain);
2254 mono_loader_unlock ();
2255 MONO_PROFILER_RAISE (vtable_failed, (vt));
2256 goto return_null;
2262 if (imt_table_bytes) {
2263 /* Now that the vtable is full, we can actually fill up the IMT */
2264 for (i = 0; i < MONO_IMT_SIZE; ++i)
2265 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2269 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2270 * re-acquire them and check if another thread has created the vtable in the meantime.
2272 /* Special case System.MonoType to avoid infinite recursion */
2273 if (klass != mono_defaults.runtimetype_class) {
2274 MonoReflectionTypeHandle vt_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
2275 vt->type = MONO_HANDLE_RAW (vt_type);
2276 if (!is_ok (error)) {
2277 mono_domain_unlock (domain);
2278 mono_loader_unlock ();
2279 MONO_PROFILER_RAISE (vtable_failed, (vt));
2280 goto return_null;
2282 if (mono_handle_class (vt_type) != mono_defaults.runtimetype_class)
2283 /* This is unregistered in
2284 unregister_vtable_reflection_type() in
2285 domain.c. */
2286 MONO_GC_REGISTER_ROOT_IF_MOVING (vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object");
2289 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2291 /* class_vtable_array keeps an array of created vtables
2293 g_ptr_array_add (domain->class_vtable_array, vt);
2294 /* klass->runtime_info is protected by the loader lock, both when
2295 * it it enlarged and when it is stored info.
2299 * Store the vtable in klass->runtime_info.
2300 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2302 mono_memory_barrier ();
2304 mono_class_setup_runtime_info (klass, domain, vt);
2306 if (klass == mono_defaults.runtimetype_class) {
2307 MonoReflectionTypeHandle vt_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
2308 vt->type = MONO_HANDLE_RAW (vt_type);
2309 if (!is_ok (error)) {
2310 mono_domain_unlock (domain);
2311 mono_loader_unlock ();
2312 MONO_PROFILER_RAISE (vtable_failed, (vt));
2313 goto return_null;
2316 if (mono_handle_class (vt_type) != mono_defaults.runtimetype_class)
2317 /* This is unregistered in
2318 unregister_vtable_reflection_type() in
2319 domain.c. */
2320 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object");
2323 mono_domain_unlock (domain);
2324 mono_loader_unlock ();
2326 /* make sure the parent is initialized */
2327 /*FIXME shouldn't this fail the current type?*/
2328 if (m_class_get_parent (klass))
2329 mono_class_vtable_checked (domain, m_class_get_parent (klass), error);
2331 MONO_PROFILER_RAISE (vtable_loaded, (vt));
2333 goto exit;
2334 return_null:
2335 vt = NULL;
2336 exit:
2337 HANDLE_FUNCTION_RETURN_VAL (vt);
2340 #ifndef DISABLE_REMOTING
2342 * mono_remote_class_is_interface_proxy:
2343 * \param remote_class
2345 * Returns TRUE if the given remote class is a proxying an interface (as
2346 * opposed to a class deriving from MarshalByRefObject).
2348 gboolean
2349 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2351 /* This if condition is taking advantage of how mono_remote_class ()
2352 * works: if that code changes, this needs to change too. */
2353 return (remote_class->interface_count >= 1 &&
2354 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2358 * mono_class_proxy_vtable:
2359 * \param domain the application domain
2360 * \param remove_class the remote class
2361 * \param error set on error
2362 * Creates a vtable for transparent proxies. It is basically
2363 * a copy of the real vtable of the class wrapped in \p remote_class,
2364 * but all function pointers invoke the remoting functions, and
2365 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2367 * On failure returns NULL and sets \p error
2369 static MonoVTable *
2370 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2372 MONO_REQ_GC_UNSAFE_MODE;
2374 MonoVTable *vt, *pvt = NULL;
2375 int i, j, vtsize, extra_interface_vtsize = 0;
2376 guint32 max_interface_id;
2377 MonoClass *k;
2378 GSList *extra_interfaces = NULL;
2379 MonoClass *klass = remote_class->proxy_class;
2380 gpointer *interface_offsets;
2381 uint8_t *bitmap = NULL;
2382 int bsize;
2383 size_t imt_table_bytes;
2384 gboolean use_interpreter = callbacks.is_interpreter_enabled ();
2386 #ifdef COMPRESSED_INTERFACE_BITMAP
2387 int bcsize;
2388 #endif
2390 error_init (error);
2392 vt = mono_class_vtable_checked (domain, klass, error);
2393 if (!is_ok (error))
2394 return NULL;
2395 max_interface_id = vt->max_interface_id;
2397 /* Calculate vtable space for extra interfaces */
2398 for (j = 0; j < remote_class->interface_count; j++) {
2399 MonoClass* iclass = remote_class->interfaces[j];
2400 GPtrArray *ifaces;
2401 int method_count;
2403 /*FIXME test for interfaces with variant generic arguments*/
2404 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (iclass)))
2405 continue; /* interface implemented by the class */
2406 if (g_slist_find (extra_interfaces, iclass))
2407 continue;
2409 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2411 method_count = mono_class_num_methods (iclass);
2413 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2414 goto_if_nok (error, failure);
2415 if (ifaces) {
2416 for (i = 0; i < ifaces->len; ++i) {
2417 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2418 /*FIXME test for interfaces with variant generic arguments*/
2419 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (ic)))
2420 continue; /* interface implemented by the class */
2421 if (g_slist_find (extra_interfaces, ic))
2422 continue;
2423 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2424 method_count += mono_class_num_methods (ic);
2426 g_ptr_array_free (ifaces, TRUE);
2427 ifaces = NULL;
2430 extra_interface_vtsize += method_count * sizeof (gpointer);
2431 if (m_class_get_max_interface_id (iclass) > max_interface_id) max_interface_id = m_class_get_max_interface_id (iclass);
2434 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2435 if (use_interpreter)
2436 imt_table_bytes *= 2;
2437 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2438 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2440 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + m_class_get_vtable_size (klass) * sizeof (gpointer);
2442 UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2444 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2445 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2446 g_assert (!((gsize)pvt & 7));
2448 if (use_interpreter)
2449 interface_offsets = (gpointer*)((char*)interface_offsets + imt_table_bytes / 2);
2451 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + m_class_get_vtable_size (klass) * sizeof (gpointer));
2453 pvt->interp_vtable = NULL;
2454 pvt->klass = mono_defaults.transparent_proxy_class;
2456 MONO_PROFILER_RAISE (vtable_loading, (pvt));
2458 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2459 pvt->gc_descr = m_class_get_gc_descr (mono_defaults.transparent_proxy_class);
2461 if (mono_remote_class_is_interface_proxy (remote_class)) {
2462 /* If it's a transparent proxy for an interface, set the
2463 * MonoVTable:type to the interface type, not the placeholder
2464 * MarshalByRefObject class. This is used when mini JITs calls
2465 * to Object.GetType ()
2467 MonoType *itf_proxy_type = m_class_get_byval_arg (remote_class->interfaces[0]);
2468 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2469 goto_if_nok (error, failure);
2472 /* initialize vtable */
2473 mono_class_setup_vtable (klass);
2474 MonoMethod **klass_vtable;
2475 klass_vtable = m_class_get_vtable (klass);
2476 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2477 MonoMethod *cm;
2479 if ((cm = klass_vtable [i])) {
2480 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2481 goto_if_nok (error, failure);
2482 } else
2483 pvt->vtable [i] = NULL;
2486 if (mono_class_is_abstract (klass)) {
2487 /* create trampolines for abstract methods */
2488 for (k = klass; k; k = m_class_get_parent (k)) {
2489 MonoMethod* m;
2490 gpointer iter = NULL;
2491 while ((m = mono_class_get_methods (k, &iter)))
2492 if (!pvt->vtable [m->slot]) {
2493 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2494 goto_if_nok (error, failure);
2499 pvt->max_interface_id = max_interface_id;
2500 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2501 #ifdef COMPRESSED_INTERFACE_BITMAP
2502 bitmap = (uint8_t *)g_malloc0 (bsize);
2503 #else
2504 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2505 #endif
2507 for (i = 0; i < m_class_get_interface_offsets_count (klass); ++i) {
2508 int interface_id = m_class_get_interface_id (m_class_get_interfaces_packed (klass) [i]);
2509 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2512 if (extra_interfaces) {
2513 int slot = m_class_get_vtable_size (klass);
2514 MonoClass* interf;
2515 gpointer iter;
2516 MonoMethod* cm;
2517 GSList *list_item;
2519 /* Create trampolines for the methods of the interfaces */
2520 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2521 interf = (MonoClass *)list_item->data;
2523 guint32 interf_interface_id = m_class_get_interface_id (interf);
2524 bitmap [interf_interface_id >> 3] |= (1 << (interf_interface_id & 7));
2526 iter = NULL;
2527 j = 0;
2528 while ((cm = mono_class_get_methods (interf, &iter))) {
2529 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2530 goto_if_nok (error, failure);
2533 slot += mono_class_num_methods (interf);
2537 /* Now that the vtable is full, we can actually fill up the IMT */
2538 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2539 if (extra_interfaces) {
2540 g_slist_free (extra_interfaces);
2543 #ifdef COMPRESSED_INTERFACE_BITMAP
2544 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2545 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2546 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2547 g_free (bitmap);
2548 #else
2549 pvt->interface_bitmap = bitmap;
2550 #endif
2551 MONO_PROFILER_RAISE (vtable_loaded, (pvt));
2552 return pvt;
2553 failure:
2554 if (extra_interfaces)
2555 g_slist_free (extra_interfaces);
2556 #ifdef COMPRESSED_INTERFACE_BITMAP
2557 g_free (bitmap);
2558 #endif
2559 MONO_PROFILER_RAISE (vtable_failed, (pvt));
2560 return NULL;
2563 #endif /* DISABLE_REMOTING */
2566 * mono_class_field_is_special_static:
2567 * \returns whether \p field is a thread/context static field.
2569 gboolean
2570 mono_class_field_is_special_static (MonoClassField *field)
2572 MONO_REQ_GC_NEUTRAL_MODE
2574 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2575 return FALSE;
2576 if (mono_field_is_deleted (field))
2577 return FALSE;
2578 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2579 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2580 return TRUE;
2582 return FALSE;
2586 * mono_class_field_get_special_static_type:
2587 * \param field The \c MonoClassField describing the field.
2588 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2589 * \c SPECIAL_STATIC_NONE otherwise.
2591 guint32
2592 mono_class_field_get_special_static_type (MonoClassField *field)
2594 MONO_REQ_GC_NEUTRAL_MODE
2596 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2597 return SPECIAL_STATIC_NONE;
2598 if (mono_field_is_deleted (field))
2599 return SPECIAL_STATIC_NONE;
2600 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2601 return field_is_special_static (field->parent, field);
2602 return SPECIAL_STATIC_NONE;
2606 * mono_class_has_special_static_fields:
2607 * \returns whether \p klass has any thread/context static fields.
2609 gboolean
2610 mono_class_has_special_static_fields (MonoClass *klass)
2612 MONO_REQ_GC_NEUTRAL_MODE
2614 MonoClassField *field;
2615 gpointer iter;
2617 iter = NULL;
2618 while ((field = mono_class_get_fields_internal (klass, &iter))) {
2619 g_assert (field->parent == klass);
2620 if (mono_class_field_is_special_static (field))
2621 return TRUE;
2624 return FALSE;
2627 #ifndef DISABLE_REMOTING
2629 * create_remote_class_key:
2630 * Creates an array of pointers that can be used as a hash key for a remote class.
2631 * The first element of the array is the number of pointers.
2633 static gpointer*
2634 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2636 MONO_REQ_GC_NEUTRAL_MODE;
2638 gpointer *key;
2639 int i, j;
2641 if (remote_class == NULL) {
2642 if (mono_class_is_interface (extra_class)) {
2643 key = (void **)g_malloc (sizeof(gpointer) * 3);
2644 key [0] = GINT_TO_POINTER (2);
2645 key [1] = mono_defaults.marshalbyrefobject_class;
2646 key [2] = extra_class;
2647 } else {
2648 key = (void **)g_malloc (sizeof(gpointer) * 2);
2649 key [0] = GINT_TO_POINTER (1);
2650 key [1] = extra_class;
2652 } else {
2653 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2654 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2655 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2656 key [1] = remote_class->proxy_class;
2658 // Keep the list of interfaces sorted
2659 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2660 if (extra_class && remote_class->interfaces [i] > extra_class) {
2661 key [j++] = extra_class;
2662 extra_class = NULL;
2664 key [j] = remote_class->interfaces [i];
2666 if (extra_class)
2667 key [j] = extra_class;
2668 } else {
2669 // Replace the old class. The interface list is the same
2670 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2671 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2672 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2673 for (i = 0; i < remote_class->interface_count; i++)
2674 key [2 + i] = remote_class->interfaces [i];
2678 return key;
2682 * copy_remote_class_key:
2684 * Make a copy of KEY in the domain and return the copy.
2686 static gpointer*
2687 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2689 MONO_REQ_GC_NEUTRAL_MODE
2691 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2692 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2694 memcpy (mp_key, key, key_size);
2696 return mp_key;
2700 * mono_remote_class:
2701 * \param domain the application domain
2702 * \param class_name name of the remote class
2703 * \param error set on error
2704 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2705 * On failure returns NULL and sets \p error
2707 MonoRemoteClass*
2708 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2710 MONO_REQ_GC_UNSAFE_MODE;
2712 MonoRemoteClass *rc;
2713 gpointer* key, *mp_key;
2714 char *name;
2716 error_init (error);
2718 key = create_remote_class_key (NULL, proxy_class);
2720 mono_domain_lock (domain);
2721 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2723 if (rc) {
2724 g_free (key);
2725 mono_domain_unlock (domain);
2726 return rc;
2729 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2730 if (!is_ok (error)) {
2731 g_free (key);
2732 mono_domain_unlock (domain);
2733 return NULL;
2736 mp_key = copy_remote_class_key (domain, key);
2737 g_free (key);
2738 key = mp_key;
2740 if (mono_class_is_interface (proxy_class)) {
2741 /* If we need to proxy an interface, we use this stylized
2742 * representation (interface_count >= 1, proxy_class is
2743 * MarshalByRefObject). The code in
2744 * mono_remote_class_is_interface_proxy () depends on being
2745 * able to detect that we're doing this, so if this
2746 * representation changes, change GetType, too. */
2747 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2748 rc->interface_count = 1;
2749 rc->interfaces [0] = proxy_class;
2750 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2751 } else {
2752 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2753 rc->interface_count = 0;
2754 rc->proxy_class = proxy_class;
2757 rc->default_vtable = NULL;
2758 rc->xdomain_vtable = NULL;
2759 rc->proxy_class_name = name;
2760 #ifndef DISABLE_PERFCOUNTERS
2761 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, mono_string_length_internal (MONO_HANDLE_RAW (class_name)) + 1);
2762 #endif
2764 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2766 mono_domain_unlock (domain);
2767 return rc;
2771 * clone_remote_class:
2772 * Creates a copy of the remote_class, adding the provided class or interface
2774 static MonoRemoteClass*
2775 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2777 MONO_REQ_GC_NEUTRAL_MODE;
2779 MonoRemoteClass *rc;
2780 gpointer* key, *mp_key;
2782 key = create_remote_class_key (remote_class, extra_class);
2783 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2784 if (rc != NULL) {
2785 g_free (key);
2786 return rc;
2789 mp_key = copy_remote_class_key (domain, key);
2790 g_free (key);
2791 key = mp_key;
2793 if (mono_class_is_interface (extra_class)) {
2794 int i,j;
2795 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2796 rc->proxy_class = remote_class->proxy_class;
2797 rc->interface_count = remote_class->interface_count + 1;
2799 // Keep the list of interfaces sorted, since the hash key of
2800 // the remote class depends on this
2801 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2802 if (remote_class->interfaces [i] > extra_class && i == j)
2803 rc->interfaces [j++] = extra_class;
2804 rc->interfaces [j] = remote_class->interfaces [i];
2806 if (i == j)
2807 rc->interfaces [j] = extra_class;
2808 } else {
2809 // Replace the old class. The interface array is the same
2810 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2811 rc->proxy_class = extra_class;
2812 rc->interface_count = remote_class->interface_count;
2813 if (rc->interface_count > 0)
2814 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2817 rc->default_vtable = NULL;
2818 rc->xdomain_vtable = NULL;
2819 rc->proxy_class_name = remote_class->proxy_class_name;
2821 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2823 return rc;
2826 gpointer
2827 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2829 MONO_REQ_GC_UNSAFE_MODE;
2831 gpointer result = NULL;
2832 error_init (error);
2834 mono_loader_lock (); /*FIXME mono_class_from_mono_type_internal and mono_class_proxy_vtable take it*/
2835 mono_domain_lock (domain);
2836 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2837 if (target_domain_id != -1) {
2838 if (remote_class->xdomain_vtable == NULL)
2839 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2840 goto_if_nok (error, leave);
2841 result = remote_class->xdomain_vtable;
2842 goto leave;
2844 if (remote_class->default_vtable == NULL) {
2845 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2846 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2848 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2849 MonoClass *klass = mono_class_from_mono_type_internal (type);
2850 #ifndef DISABLE_COM
2851 gboolean target_is_com = FALSE;
2852 if (mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) {
2853 MonoVTable *klass_vtable = mono_class_vtable_checked (mono_domain_get (), klass, error);
2854 goto_if_nok (error, leave);
2855 if (!mono_vtable_is_remote (klass_vtable))
2856 target_is_com = TRUE;
2858 if (target_is_com)
2859 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2860 else
2861 #endif
2862 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2863 /* N.B. both branches of the if modify error */
2864 goto_if_nok (error, leave);
2868 result = remote_class->default_vtable;
2869 leave:
2870 mono_domain_unlock (domain);
2871 mono_loader_unlock ();
2872 return result;
2876 * mono_upgrade_remote_class:
2877 * \param domain the application domain
2878 * \param tproxy the proxy whose remote class has to be upgraded.
2879 * \param klass class to which the remote class can be casted.
2880 * \param error set on error
2881 * Updates the vtable of the remote class by adding the necessary method slots
2882 * and interface offsets so it can be safely casted to klass. klass can be a
2883 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2885 gboolean
2886 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2888 MONO_REQ_GC_UNSAFE_MODE;
2890 error_init (error);
2892 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2893 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2895 gboolean redo_vtable;
2896 if (mono_class_is_interface (klass)) {
2897 int i;
2898 redo_vtable = TRUE;
2899 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2900 if (remote_class->interfaces [i] == klass)
2901 redo_vtable = FALSE;
2903 else {
2904 redo_vtable = (remote_class->proxy_class != klass);
2907 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2908 mono_domain_lock (domain);
2909 if (redo_vtable) {
2910 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2911 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2912 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2913 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2914 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, (MonoVTable*)mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2915 goto_if_nok (error, leave);
2918 leave:
2919 mono_domain_unlock (domain);
2920 mono_loader_unlock ();
2921 return is_ok (error);
2923 #endif /* DISABLE_REMOTING */
2925 MonoMethod*
2926 mono_object_get_virtual_method_internal (MonoObject *obj_raw, MonoMethod *method)
2928 HANDLE_FUNCTION_ENTER ();
2929 MonoMethod *result;
2930 ERROR_DECL (error);
2931 MONO_HANDLE_DCL (MonoObject, obj);
2932 result = mono_object_handle_get_virtual_method (obj, method, error);
2933 mono_error_assert_ok (error);
2934 HANDLE_FUNCTION_RETURN_VAL (result);
2938 * mono_object_get_virtual_method:
2939 * \param obj object to operate on.
2940 * \param method method
2941 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2942 * the instance of a callvirt of \p method.
2944 MonoMethod*
2945 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2947 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoMethod*, mono_object_get_virtual_method_internal (obj, method));
2951 * mono_object_handle_get_virtual_method:
2952 * \param obj object to operate on.
2953 * \param method method
2954 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2955 * the instance of a callvirt of \p method.
2957 MonoMethod*
2958 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2960 error_init (error);
2962 gboolean is_proxy = FALSE;
2963 MonoClass *klass = mono_handle_class (obj);
2964 if (mono_class_is_transparent_proxy (klass)) {
2965 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2966 klass = remote_class->proxy_class;
2967 is_proxy = TRUE;
2969 return mono_class_get_virtual_method (klass, method, is_proxy, error);
2972 MonoMethod*
2973 mono_class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2975 MONO_REQ_GC_NEUTRAL_MODE;
2976 error_init (error);
2978 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2979 return method;
2981 mono_class_setup_vtable (klass);
2982 MonoMethod **vtable = m_class_get_vtable (klass);
2984 if (method->slot == -1) {
2985 /* method->slot might not be set for instances of generic methods */
2986 if (method->is_inflated) {
2987 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2988 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2989 } else {
2990 if (!is_proxy)
2991 g_assert_not_reached ();
2995 MonoMethod *res = NULL;
2996 /* check method->slot is a valid index: perform isinstance? */
2997 if (method->slot != -1) {
2998 if (mono_class_is_interface (method->klass)) {
2999 if (!is_proxy) {
3000 gboolean variance_used = FALSE;
3001 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
3002 g_assert (iface_offset > 0);
3003 res = vtable [iface_offset + method->slot];
3005 } else {
3006 res = vtable [method->slot];
3010 #ifndef DISABLE_REMOTING
3011 if (is_proxy) {
3012 /* It may be an interface, abstract class method or generic method */
3013 if (!res || mono_method_signature_internal (res)->generic_param_count)
3014 res = method;
3016 /* generic methods demand invoke_with_check */
3017 if (mono_method_signature_internal (res)->generic_param_count)
3018 res = mono_marshal_get_remoting_invoke_with_check (res, error);
3019 else {
3020 #ifndef DISABLE_COM
3021 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
3022 res = mono_cominterop_get_invoke (res);
3023 else
3024 #endif
3025 res = mono_marshal_get_remoting_invoke (res, error);
3027 } else
3028 #endif
3030 if (method->is_inflated) {
3031 /* Have to inflate the result */
3032 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
3036 return res;
3039 static MonoObject*
3040 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
3042 MONO_REQ_GC_UNSAFE_MODE;
3044 MonoObject *result = NULL;
3046 g_assert (callbacks.runtime_invoke);
3048 error_init (error);
3050 MONO_PROFILER_RAISE (method_begin_invoke, (method));
3052 result = callbacks.runtime_invoke (method, obj, params, exc, error);
3054 MONO_PROFILER_RAISE (method_end_invoke, (method));
3056 if (!is_ok (error))
3057 return NULL;
3059 return result;
3063 * mono_runtime_invoke:
3064 * \param method method to invoke
3065 * \param obj object instance
3066 * \param params arguments to the method
3067 * \param exc exception information.
3068 * Invokes the method represented by \p method on the object \p obj.
3069 * \p obj is the \c this pointer, it should be NULL for static
3070 * methods, a \c MonoObject* for object instances and a pointer to
3071 * the value type for value types.
3073 * The params array contains the arguments to the method with the
3074 * same convention: \c MonoObject* pointers for object instances and
3075 * pointers to the value type otherwise.
3077 * From unmanaged code you'll usually use the
3078 * \c mono_runtime_invoke variant.
3080 * Note that this function doesn't handle virtual methods for
3081 * you, it will exec the exact method you pass: we still need to
3082 * expose a function to lookup the derived class implementation
3083 * of a virtual method (there are examples of this in the code,
3084 * though).
3086 * You can pass NULL as the \p exc argument if you don't want to
3087 * catch exceptions, otherwise, \c *exc will be set to the exception
3088 * thrown, if any. if an exception is thrown, you can't use the
3089 * \c MonoObject* result from the function.
3091 * If the method returns a value type, it is boxed in an object
3092 * reference.
3094 MonoObject*
3095 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
3097 MonoObject *res;
3098 MONO_ENTER_GC_UNSAFE;
3099 ERROR_DECL (error);
3100 if (exc) {
3101 res = mono_runtime_try_invoke (method, obj, params, exc, error);
3102 if (*exc == NULL && !is_ok(error)) {
3103 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3104 } else
3105 mono_error_cleanup (error);
3106 } else {
3107 res = mono_runtime_invoke_checked (method, obj, params, error);
3108 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
3110 MONO_EXIT_GC_UNSAFE;
3111 return res;
3115 * mono_runtime_try_invoke:
3116 * \param method method to invoke
3117 * \param obj object instance
3118 * \param params arguments to the method
3119 * \param exc exception information.
3120 * \param error set on error
3121 * Invokes the method represented by \p method on the object \p obj.
3123 * \p obj is the \c this pointer, it should be NULL for static
3124 * methods, a \c MonoObject* for object instances and a pointer to
3125 * the value type for value types.
3127 * The params array contains the arguments to the method with the
3128 * same convention: \c MonoObject* pointers for object instances and
3129 * pointers to the value type otherwise.
3131 * From unmanaged code you'll usually use the
3132 * mono_runtime_invoke() variant.
3134 * Note that this function doesn't handle virtual methods for
3135 * you, it will exec the exact method you pass: we still need to
3136 * expose a function to lookup the derived class implementation
3137 * of a virtual method (there are examples of this in the code,
3138 * though).
3140 * For this function, you must not pass NULL as the \p exc argument if
3141 * you don't want to catch exceptions, use
3142 * mono_runtime_invoke_checked(). If an exception is thrown, you
3143 * can't use the \c MonoObject* result from the function.
3145 * If this method cannot be invoked, \p error will be set and \p exc and
3146 * the return value must not be used.
3148 * If the method returns a value type, it is boxed in an object
3149 * reference.
3151 MonoObject*
3152 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3154 MONO_REQ_GC_UNSAFE_MODE;
3156 g_assert (exc != NULL);
3158 if (mono_runtime_get_no_exec ())
3159 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3161 return do_runtime_invoke (method, obj, params, exc, error);
3164 MonoObjectHandle
3165 mono_runtime_try_invoke_handle (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3167 // FIXME? typing of params
3168 MonoException *exc = NULL;
3169 MonoObject *obj_raw = mono_runtime_try_invoke (method, MONO_HANDLE_RAW (obj), params, (MonoObject**)&exc, error);
3171 if (exc && is_ok (error))
3172 mono_error_set_exception_instance (error, exc);
3174 return MONO_HANDLE_NEW (MonoObject, obj_raw);
3178 * mono_runtime_invoke_checked:
3179 * \param method method to invoke
3180 * \param obj object instance
3181 * \param params arguments to the method
3182 * \param error set on error
3183 * Invokes the method represented by \p method on the object \p obj.
3185 * \p obj is the \c this pointer, it should be NULL for static
3186 * methods, a \c MonoObject* for object instances and a pointer to
3187 * the value type for value types.
3189 * The \p params array contains the arguments to the method with the
3190 * same convention: \c MonoObject* pointers for object instances and
3191 * pointers to the value type otherwise.
3193 * From unmanaged code you'll usually use the
3194 * mono_runtime_invoke() variant.
3196 * Note that this function doesn't handle virtual methods for
3197 * you, it will exec the exact method you pass: we still need to
3198 * expose a function to lookup the derived class implementation
3199 * of a virtual method (there are examples of this in the code,
3200 * though).
3202 * If an exception is thrown, you can't use the \c MonoObject* result
3203 * from the function.
3205 * If this method cannot be invoked, \p error will be set. If the
3206 * method throws an exception (and we're in coop mode) the exception
3207 * will be set in \p error.
3209 * If the method returns a value type, it is boxed in an object
3210 * reference.
3212 MonoObject*
3213 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3215 MONO_REQ_GC_UNSAFE_MODE;
3217 if (mono_runtime_get_no_exec ())
3218 g_error ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3220 return do_runtime_invoke (method, obj, params, NULL, error);
3223 MonoObjectHandle
3224 mono_runtime_invoke_handle (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3226 return MONO_HANDLE_NEW (MonoObject, mono_runtime_invoke_checked (method, MONO_HANDLE_RAW (obj), params, error));
3229 void
3230 mono_runtime_invoke_handle_void (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3232 mono_runtime_invoke_checked (method, MONO_HANDLE_RAW (obj), params, error);
3236 * mono_method_get_unmanaged_thunk:
3237 * \param method method to generate a thunk for.
3239 * Returns an \c unmanaged->managed thunk that can be used to call
3240 * a managed method directly from C.
3242 * The thunk's C signature closely matches the managed signature:
3244 * C#: <code>public bool Equals (object obj);</code>
3246 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3248 * The 1st (<code>this</code>) parameter must not be used with static methods:
3250 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3252 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3254 * The last argument must be a non-null \c MonoException* pointer.
3255 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3256 * exception has been thrown in managed code. Otherwise it will point
3257 * to the \c MonoException* caught by the thunk. In this case, the result of
3258 * the thunk is undefined:
3260 * <pre>
3261 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3263 * MonoException *ex = NULL;
3265 * Equals func = mono_method_get_unmanaged_thunk (method);
3267 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3269 * if (ex) {
3271 * // handle exception
3274 * </pre>
3276 * The calling convention of the thunk matches the platform's default
3277 * convention. This means that under Windows, C declarations must
3278 * contain the \c __stdcall attribute:
3280 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3282 * LIMITATIONS
3284 * Value type arguments and return values are treated as they were objects:
3286 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3287 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3289 * Arguments must be properly boxed upon trunk's invocation, while return
3290 * values must be unboxed.
3292 gpointer
3293 mono_method_get_unmanaged_thunk (MonoMethod *method)
3295 MONO_REQ_GC_NEUTRAL_MODE;
3296 MONO_REQ_API_ENTRYPOINT;
3298 ERROR_DECL (error);
3299 gpointer res;
3301 MONO_ENTER_GC_UNSAFE;
3302 method = mono_marshal_get_thunk_invoke_wrapper (method);
3303 res = mono_compile_method_checked (method, error);
3304 mono_error_cleanup (error);
3305 MONO_EXIT_GC_UNSAFE;
3307 return res;
3310 void
3311 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3313 MONO_REQ_GC_UNSAFE_MODE;
3315 int t;
3316 if (type->byref) {
3317 /* object fields cannot be byref, so we don't need a
3318 wbarrier here */
3319 gpointer *p = (gpointer*)dest;
3320 *p = value;
3321 return;
3323 t = type->type;
3324 handle_enum:
3325 switch (t) {
3326 case MONO_TYPE_BOOLEAN:
3327 case MONO_TYPE_I1:
3328 case MONO_TYPE_U1: {
3329 guint8 *p = (guint8*)dest;
3330 *p = value ? *(guint8*)value : 0;
3331 return;
3333 case MONO_TYPE_I2:
3334 case MONO_TYPE_U2:
3335 case MONO_TYPE_CHAR: {
3336 guint16 *p = (guint16*)dest;
3337 *p = value ? *(guint16*)value : 0;
3338 return;
3340 #if SIZEOF_VOID_P == 4
3341 case MONO_TYPE_I:
3342 case MONO_TYPE_U:
3343 #endif
3344 case MONO_TYPE_I4:
3345 case MONO_TYPE_U4: {
3346 gint32 *p = (gint32*)dest;
3347 *p = value ? *(gint32*)value : 0;
3348 return;
3350 #if SIZEOF_VOID_P == 8
3351 case MONO_TYPE_I:
3352 case MONO_TYPE_U:
3353 #endif
3354 case MONO_TYPE_I8:
3355 case MONO_TYPE_U8: {
3356 gint64 *p = (gint64*)dest;
3357 *p = value ? *(gint64*)value : 0;
3358 return;
3360 case MONO_TYPE_R4: {
3361 float *p = (float*)dest;
3362 *p = value ? *(float*)value : 0;
3363 return;
3365 case MONO_TYPE_R8: {
3366 double *p = (double*)dest;
3367 *p = value ? *(double*)value : 0;
3368 return;
3370 case MONO_TYPE_STRING:
3371 case MONO_TYPE_SZARRAY:
3372 case MONO_TYPE_CLASS:
3373 case MONO_TYPE_OBJECT:
3374 case MONO_TYPE_ARRAY:
3375 mono_gc_wbarrier_generic_store_internal (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3376 return;
3377 case MONO_TYPE_FNPTR:
3378 case MONO_TYPE_PTR: {
3379 gpointer *p = (gpointer*)dest;
3380 *p = deref_pointer? *(gpointer*)value: value;
3381 return;
3383 case MONO_TYPE_VALUETYPE:
3384 /* note that 't' and 'type->type' can be different */
3385 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass)) {
3386 t = mono_class_enum_basetype_internal (type->data.klass)->type;
3387 goto handle_enum;
3388 } else {
3389 MonoClass *klass = mono_class_from_mono_type_internal (type);
3390 int size = mono_class_value_size (klass, NULL);
3391 if (value == NULL)
3392 mono_gc_bzero_atomic (dest, size);
3393 else
3394 mono_gc_wbarrier_value_copy_internal (dest, value, 1, klass);
3396 return;
3397 case MONO_TYPE_GENERICINST:
3398 t = m_class_get_byval_arg (type->data.generic_class->container_class)->type;
3399 goto handle_enum;
3400 default:
3401 g_error ("got type %x", type->type);
3405 void
3406 mono_field_set_value_internal (MonoObject *obj, MonoClassField *field, void *value)
3408 void *dest;
3410 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3411 return;
3413 dest = (char*)obj + field->offset;
3414 #if ENABLE_NETCORE
3415 mono_copy_value (field->type, dest, value, value && field->type->type == MONO_TYPE_PTR);
3416 #else
3417 mono_copy_value (field->type, dest, value, FALSE);
3418 #endif
3422 * mono_field_set_value:
3423 * \param obj Instance object
3424 * \param field \c MonoClassField describing the field to set
3425 * \param value The value to be set
3427 * Sets the value of the field described by \p field in the object instance \p obj
3428 * to the value passed in \p value. This method should only be used for instance
3429 * fields. For static fields, use \c mono_field_static_set_value.
3431 * The value must be in the native format of the field type.
3433 void
3434 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3436 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_set_value_internal (obj, field, value));
3439 void
3440 mono_field_static_set_value_internal (MonoVTable *vt, MonoClassField *field, void *value)
3442 void *dest;
3444 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC) == 0)
3445 return;
3446 /* you cant set a constant! */
3447 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
3448 return;
3450 if (field->offset == -1) {
3451 /* Special static */
3452 gpointer addr;
3454 mono_domain_lock (vt->domain);
3455 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3456 mono_domain_unlock (vt->domain);
3457 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3458 } else {
3459 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3461 mono_copy_value (field->type, dest, value, FALSE);
3465 * mono_field_static_set_value:
3466 * \param field \c MonoClassField describing the field to set
3467 * \param value The value to be set
3468 * Sets the value of the static field described by \p field
3469 * to the value passed in \p value.
3470 * The value must be in the native format of the field type.
3472 void
3473 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3475 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_static_set_value_internal (vt, field, value));
3479 * mono_vtable_get_static_field_data:
3481 * Internal use function: return a pointer to the memory holding the static fields
3482 * for a class or NULL if there are no static fields.
3483 * This is exported only for use by the debugger.
3485 void *
3486 mono_vtable_get_static_field_data (MonoVTable *vt)
3488 MONO_REQ_GC_NEUTRAL_MODE
3490 if (!vt->has_static_fields)
3491 return NULL;
3492 return vt->vtable [m_class_get_vtable_size (vt->klass)];
3495 static guint8*
3496 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3498 MONO_REQ_GC_UNSAFE_MODE;
3500 guint8 *src;
3502 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3503 if (field->offset == -1) {
3504 /* Special static */
3505 gpointer addr;
3507 mono_domain_lock (vt->domain);
3508 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3509 mono_domain_unlock (vt->domain);
3510 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3511 } else {
3512 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3514 } else {
3515 src = (guint8*)obj + field->offset;
3518 return src;
3522 * mono_field_get_value:
3523 * \param obj Object instance
3524 * \param field \c MonoClassField describing the field to fetch information from
3525 * \param value pointer to the location where the value will be stored
3526 * Use this routine to get the value of the field \p field in the object
3527 * passed.
3529 * The pointer provided by value must be of the field type, for reference
3530 * types this is a \c MonoObject*, for value types its the actual pointer to
3531 * the value type.
3533 * For example:
3535 * <pre>
3536 * int i;
3538 * mono_field_get_value (obj, int_field, &i);
3539 * </pre>
3541 void
3542 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3544 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_get_value_internal (obj, field, value));
3547 void
3548 mono_field_get_value_internal (MonoObject *obj, MonoClassField *field, void *value)
3550 MONO_REQ_GC_UNSAFE_MODE;
3552 void *src;
3554 g_assert (obj);
3556 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3558 src = (char*)obj + field->offset;
3559 mono_copy_value (field->type, value, src, TRUE);
3563 * mono_field_get_value_object:
3564 * \param domain domain where the object will be created (if boxing)
3565 * \param field \c MonoClassField describing the field to fetch information from
3566 * \param obj The object instance for the field.
3567 * \returns a new \c MonoObject with the value from the given field. If the
3568 * field represents a value type, the value is boxed.
3570 MonoObject *
3571 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3573 MonoObject* result;
3574 MONO_ENTER_GC_UNSAFE;
3575 ERROR_DECL (error);
3576 result = mono_field_get_value_object_checked (domain, field, obj, error);
3577 mono_error_assert_ok (error);
3578 MONO_EXIT_GC_UNSAFE;
3579 return result;
3583 * mono_static_field_get_value_handle:
3584 * \param domain domain where the object will be created (if boxing)
3585 * \param field \c MonoClassField describing the field to fetch information from
3586 * \param obj The object instance for the field.
3587 * \returns a new \c MonoObject with the value from the given field. If the
3588 * field represents a value type, the value is boxed.
3590 MonoObjectHandle
3591 mono_static_field_get_value_handle (MonoDomain *domain, MonoClassField *field, MonoError *error)
3592 // FIXMEcoop invert
3594 HANDLE_FUNCTION_ENTER ();
3595 HANDLE_FUNCTION_RETURN_REF (MonoObject, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (domain, field, NULL, error)));
3599 * mono_field_get_value_object_checked:
3600 * \param domain domain where the object will be created (if boxing)
3601 * \param field \c MonoClassField describing the field to fetch information from
3602 * \param obj The object instance for the field.
3603 * \param error Set on error.
3604 * \returns a new \c MonoObject with the value from the given field. If the
3605 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3607 MonoObject *
3608 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3610 // FIXMEcoop
3612 HANDLE_FUNCTION_ENTER ();
3614 MONO_REQ_GC_UNSAFE_MODE;
3616 error_init (error);
3618 MonoObject *o = NULL;
3619 MonoClass *klass;
3620 MonoVTable *vtable = NULL;
3621 gpointer v;
3622 gboolean is_static = FALSE;
3623 gboolean is_ref = FALSE;
3624 gboolean is_literal = FALSE;
3625 gboolean is_ptr = FALSE;
3627 MonoStringHandle string_handle = MONO_HANDLE_NEW (MonoString, NULL);
3629 MonoType *type = mono_field_get_type_checked (field, error);
3631 goto_if_nok (error, return_null);
3633 switch (type->type) {
3634 case MONO_TYPE_STRING:
3635 case MONO_TYPE_OBJECT:
3636 case MONO_TYPE_CLASS:
3637 case MONO_TYPE_ARRAY:
3638 case MONO_TYPE_SZARRAY:
3639 is_ref = TRUE;
3640 break;
3641 case MONO_TYPE_U1:
3642 case MONO_TYPE_I1:
3643 case MONO_TYPE_BOOLEAN:
3644 case MONO_TYPE_U2:
3645 case MONO_TYPE_I2:
3646 case MONO_TYPE_CHAR:
3647 case MONO_TYPE_U:
3648 case MONO_TYPE_I:
3649 case MONO_TYPE_U4:
3650 case MONO_TYPE_I4:
3651 case MONO_TYPE_R4:
3652 case MONO_TYPE_U8:
3653 case MONO_TYPE_I8:
3654 case MONO_TYPE_R8:
3655 case MONO_TYPE_VALUETYPE:
3656 is_ref = type->byref;
3657 break;
3658 case MONO_TYPE_GENERICINST:
3659 is_ref = !mono_type_generic_inst_is_valuetype (type);
3660 break;
3661 case MONO_TYPE_PTR:
3662 is_ptr = TRUE;
3663 break;
3664 default:
3665 g_error ("type 0x%x not handled in "
3666 "mono_field_get_value_object", type->type);
3667 goto return_null;
3670 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3671 is_literal = TRUE;
3673 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3674 is_static = TRUE;
3676 if (!is_literal) {
3677 vtable = mono_class_vtable_checked (domain, field->parent, error);
3678 goto_if_nok (error, return_null);
3680 if (!vtable->initialized) {
3681 mono_runtime_class_init_full (vtable, error);
3682 goto_if_nok (error, return_null);
3685 } else {
3686 g_assert (obj);
3689 if (is_ref) {
3690 if (is_literal) {
3691 get_default_field_value (domain, field, &o, string_handle, error);
3692 goto_if_nok (error, return_null);
3693 } else if (is_static) {
3694 mono_field_static_get_value_checked (vtable, field, &o, string_handle, error);
3695 goto_if_nok (error, return_null);
3696 } else {
3697 mono_field_get_value_internal (obj, field, &o);
3699 goto exit;
3702 if (is_ptr) {
3703 gpointer args [2];
3704 gpointer *ptr;
3706 MONO_STATIC_POINTER_INIT (MonoMethod, m)
3708 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3709 m = mono_class_get_method_from_name_checked (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC, error);
3710 goto_if_nok (error, return_null);
3711 g_assert (m);
3713 MONO_STATIC_POINTER_INIT_END (MonoMethod, m)
3715 v = &ptr;
3716 if (is_literal) {
3717 get_default_field_value (domain, field, v, string_handle, error);
3718 goto_if_nok (error, return_null);
3719 } else if (is_static) {
3720 mono_field_static_get_value_checked (vtable, field, v, string_handle, error);
3721 goto_if_nok (error, return_null);
3722 } else {
3723 mono_field_get_value_internal (obj, field, v);
3726 #if ENABLE_NETCORE
3727 args [0] = ptr;
3728 #else
3729 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3730 args [0] = ptr ? *ptr : NULL;
3731 #endif
3732 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3733 goto_if_nok (error, return_null);
3735 o = mono_runtime_invoke_checked (m, NULL, args, error);
3736 goto_if_nok (error, return_null);
3738 goto exit;
3741 /* boxed value type */
3742 klass = mono_class_from_mono_type_internal (type);
3744 if (mono_class_is_nullable (klass)) {
3745 o = mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3746 goto exit;
3749 o = mono_object_new_checked (domain, klass, error);
3750 goto_if_nok (error, return_null);
3751 v = mono_object_get_data (o);
3753 if (is_literal) {
3754 get_default_field_value (domain, field, v, string_handle, error);
3755 goto_if_nok (error, return_null);
3756 } else if (is_static) {
3757 mono_field_static_get_value_checked (vtable, field, v, string_handle, error);
3758 goto_if_nok (error, return_null);
3759 } else {
3760 mono_field_get_value_internal (obj, field, v);
3763 goto exit;
3764 return_null:
3765 o = NULL;
3766 exit:
3767 HANDLE_FUNCTION_RETURN_VAL (o);
3771 * Important detail, if type is MONO_TYPE_STRING we return a blob encoded string (ie, utf16 + leb128 prefixed size)
3773 gboolean
3774 mono_metadata_read_constant_value (const char *blob, MonoTypeEnum type, void *value, MonoError *error)
3776 error_init (error);
3777 gboolean retval = TRUE;
3778 const char *p = blob;
3779 mono_metadata_decode_blob_size (p, &p);
3781 switch (type) {
3782 case MONO_TYPE_BOOLEAN:
3783 case MONO_TYPE_U1:
3784 case MONO_TYPE_I1:
3785 *(guint8 *) value = *p;
3786 break;
3787 case MONO_TYPE_CHAR:
3788 case MONO_TYPE_U2:
3789 case MONO_TYPE_I2:
3790 *(guint16*) value = read16 (p);
3791 break;
3792 case MONO_TYPE_U4:
3793 case MONO_TYPE_I4:
3794 *(guint32*) value = read32 (p);
3795 break;
3796 case MONO_TYPE_U8:
3797 case MONO_TYPE_I8:
3798 *(guint64*) value = read64 (p);
3799 break;
3800 case MONO_TYPE_R4:
3801 readr4 (p, (float*) value);
3802 break;
3803 case MONO_TYPE_R8:
3804 readr8 (p, (double*) value);
3805 break;
3806 case MONO_TYPE_STRING:
3807 *(const char**) value = blob;
3808 break;
3809 case MONO_TYPE_CLASS:
3810 *(gpointer*) value = NULL;
3811 break;
3812 default:
3813 retval = FALSE;
3814 mono_error_set_execution_engine (error, "Type 0x%02x should not be in constant table", type);
3816 return retval;
3819 gboolean
3820 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoStringHandleOut string_handle, MonoError *error)
3822 MONO_REQ_GC_UNSAFE_MODE;
3824 // FIXMEcoop excess frame, but mono_ldstr_metadata_sig does allocate a handle.
3825 HANDLE_FUNCTION_ENTER ();
3827 gboolean result = FALSE;
3829 if (!mono_metadata_read_constant_value (blob, type, value, error))
3830 goto exit;
3832 if (type == MONO_TYPE_STRING) {
3833 mono_ldstr_metadata_sig (domain, *(const char**)value, string_handle, error);
3834 *(gpointer*)value = MONO_HANDLE_RAW (string_handle);
3836 result = TRUE;
3837 exit:
3838 HANDLE_FUNCTION_RETURN_VAL (result);
3841 static void
3842 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoStringHandleOut string_handle, MonoError *error)
3844 MONO_REQ_GC_NEUTRAL_MODE;
3846 MonoTypeEnum def_type;
3847 const char* data;
3849 error_init (error);
3851 data = mono_class_get_field_default_value (field, &def_type);
3852 (void)mono_get_constant_value_from_blob (domain, def_type, data, value, string_handle, error);
3855 void
3856 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoStringHandleOut string_handle, MonoError *error)
3858 MONO_REQ_GC_UNSAFE_MODE;
3860 void *src;
3862 error_init (error);
3864 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3866 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3867 get_default_field_value (vt->domain, field, value, string_handle, error);
3868 return;
3871 if (field->offset == -1) {
3872 /* Special static */
3873 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3874 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3875 } else {
3876 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3878 mono_copy_value (field->type, value, src, TRUE);
3882 * mono_field_static_get_value:
3883 * \param vt vtable to the object
3884 * \param field \c MonoClassField describing the field to fetch information from
3885 * \param value where the value is returned
3886 * Use this routine to get the value of the static field \p field value.
3888 * The pointer provided by value must be of the field type, for reference
3889 * types this is a \c MonoObject*, for value types its the actual pointer to
3890 * the value type.
3892 * For example:
3894 * <pre>
3895 * int i;
3897 * mono_field_static_get_value (vt, int_field, &i);
3898 * </pre>
3900 void
3901 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3903 MONO_REQ_GC_NEUTRAL_MODE;
3905 ERROR_DECL (error);
3906 mono_field_static_get_value_checked (vt, field, value, MONO_HANDLE_NEW (MonoString, NULL), error);
3907 mono_error_cleanup (error);
3911 * mono_field_static_get_value_checked:
3912 * \param vt vtable to the object
3913 * \param field \c MonoClassField describing the field to fetch information from
3914 * \param value where the value is returned
3915 * \param error set on error
3916 * Use this routine to get the value of the static field \p field value.
3918 * The pointer provided by value must be of the field type, for reference
3919 * types this is a \c MonoObject*, for value types its the actual pointer to
3920 * the value type.
3922 * For example:
3923 * int i;
3924 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3925 * if (!is_ok (error)) { ... }
3927 * On failure sets \p error.
3929 void
3930 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoStringHandleOut string_handle, MonoError *error)
3932 MONO_REQ_GC_NEUTRAL_MODE;
3934 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, string_handle, error);
3938 * mono_property_set_value:
3939 * \param prop MonoProperty to set
3940 * \param obj instance object on which to act
3941 * \param params parameters to pass to the propery
3942 * \param exc optional exception
3943 * Invokes the property's set method with the given arguments on the
3944 * object instance obj (or NULL for static properties).
3946 * You can pass NULL as the exc argument if you don't want to
3947 * catch exceptions, otherwise, \c *exc will be set to the exception
3948 * thrown, if any. if an exception is thrown, you can't use the
3949 * \c MonoObject* result from the function.
3951 void
3952 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3954 MONO_ENTER_GC_UNSAFE;
3956 ERROR_DECL (error);
3957 do_runtime_invoke (prop->set, obj, params, exc, error);
3958 if (exc && *exc == NULL && !is_ok (error)) {
3959 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3960 } else {
3961 mono_error_cleanup (error);
3963 MONO_EXIT_GC_UNSAFE;
3967 * mono_property_set_value_handle:
3968 * \param prop \c MonoProperty to set
3969 * \param obj instance object on which to act
3970 * \param params parameters to pass to the propery
3971 * \param error set on error
3972 * Invokes the property's set method with the given arguments on the
3973 * object instance \p obj (or NULL for static properties).
3974 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3975 * If an exception is thrown, it will be caught and returned via \p error.
3977 gboolean
3978 mono_property_set_value_handle (MonoProperty *prop, MonoObjectHandle obj, void **params, MonoError *error)
3980 MONO_REQ_GC_UNSAFE_MODE;
3982 MonoObject *exc;
3984 error_init (error);
3985 do_runtime_invoke (prop->set, MONO_HANDLE_RAW (obj), params, &exc, error);
3986 if (exc != NULL && is_ok (error))
3987 mono_error_set_exception_instance (error, (MonoException*)exc);
3988 return is_ok (error);
3992 * mono_property_get_value:
3993 * \param prop \c MonoProperty to fetch
3994 * \param obj instance object on which to act
3995 * \param params parameters to pass to the propery
3996 * \param exc optional exception
3997 * Invokes the property's \c get method with the given arguments on the
3998 * object instance \p obj (or NULL for static properties).
4000 * You can pass NULL as the \p exc argument if you don't want to
4001 * catch exceptions, otherwise, \c *exc will be set to the exception
4002 * thrown, if any. if an exception is thrown, you can't use the
4003 * \c MonoObject* result from the function.
4005 * \returns the value from invoking the \c get method on the property.
4007 MonoObject*
4008 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
4010 MonoObject *val;
4011 MONO_ENTER_GC_UNSAFE;
4013 ERROR_DECL (error);
4014 val = do_runtime_invoke (prop->get, obj, params, exc, error);
4015 if (exc && *exc == NULL && !is_ok (error)) {
4016 *exc = (MonoObject*) mono_error_convert_to_exception (error);
4017 } else {
4018 mono_error_cleanup (error); /* FIXME don't raise here */
4020 MONO_EXIT_GC_UNSAFE;
4021 return val;
4025 * mono_property_get_value_checked:
4026 * \param prop \c MonoProperty to fetch
4027 * \param obj instance object on which to act
4028 * \param params parameters to pass to the propery
4029 * \param error set on error
4030 * Invokes the property's \c get method with the given arguments on the
4031 * object instance obj (or NULL for static properties).
4033 * If an exception is thrown, you can't use the
4034 * \c MonoObject* result from the function. The exception will be propagated via \p error.
4036 * \returns the value from invoking the get method on the property. On
4037 * failure returns NULL and sets \p error.
4039 MonoObject*
4040 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
4042 MONO_REQ_GC_UNSAFE_MODE;
4044 MonoObject *exc;
4045 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
4046 if (exc != NULL && !is_ok (error))
4047 mono_error_set_exception_instance (error, (MonoException*) exc);
4048 if (!is_ok (error))
4049 val = NULL;
4050 return val;
4053 static MonoClassField*
4054 nullable_class_get_value_field (MonoClass *klass)
4056 mono_class_setup_fields (klass);
4057 g_assert (m_class_is_fields_inited (klass));
4059 MonoClassField *klass_fields = m_class_get_fields (klass);
4060 return &klass_fields [1];
4063 static MonoClassField*
4064 nullable_class_get_has_value_field (MonoClass *klass)
4066 mono_class_setup_fields (klass);
4067 g_assert (m_class_is_fields_inited (klass));
4069 MonoClassField *klass_fields = m_class_get_fields (klass);
4070 return &klass_fields [0];
4073 static gpointer
4074 nullable_get_has_value_field_addr (guint8 *nullable, MonoClass *klass)
4076 MonoClassField *has_value_field = nullable_class_get_has_value_field (klass);
4078 return mono_vtype_get_field_addr (nullable, has_value_field);
4081 static gpointer
4082 nullable_get_value_field_addr (guint8 *nullable, MonoClass *klass)
4084 MonoClassField *has_value_field = nullable_class_get_value_field (klass);
4086 return mono_vtype_get_field_addr (nullable, has_value_field);
4090 * mono_nullable_init:
4091 * @buf: The nullable structure to initialize.
4092 * @value: the value to initialize from
4093 * @klass: the type for the object
4095 * Initialize the nullable structure pointed to by @buf from @value which
4096 * should be a boxed value type. The size of @buf should be able to hold
4097 * as much data as the @klass->instance_size (which is the number of bytes
4098 * that will be copies).
4100 * Since Nullables have variable structure, we can not define a C
4101 * structure for them.
4103 void
4104 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
4106 MONO_REQ_GC_UNSAFE_MODE;
4108 MonoClass *param_class = m_class_get_cast_class (klass);
4109 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
4110 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4112 *(guint8*)(has_value_field_addr) = value ? 1 : 0;
4113 if (value) {
4114 if (m_class_has_references (param_class))
4115 mono_gc_wbarrier_value_copy_internal (value_field_addr, mono_object_unbox_internal (value), 1, param_class);
4116 else
4117 mono_gc_memmove_atomic (value_field_addr, mono_object_unbox_internal (value), mono_class_value_size (param_class, NULL));
4118 } else {
4119 mono_gc_bzero_atomic (value_field_addr, mono_class_value_size (param_class, NULL));
4124 * mono_nullable_init_from_handle:
4125 * @buf: The nullable structure to initialize.
4126 * @value: the value to initialize from
4127 * @klass: the type for the object
4129 * Initialize the nullable structure pointed to by @buf from @value which
4130 * should be a boxed value type. The size of @buf should be able to hold
4131 * as much data as the @klass->instance_size (which is the number of bytes
4132 * that will be copies).
4134 * Since Nullables have variable structure, we can not define a C
4135 * structure for them.
4137 void
4138 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
4140 MONO_REQ_GC_UNSAFE_MODE;
4142 if (!MONO_HANDLE_IS_NULL (value)) {
4143 uint32_t value_gchandle = 0;
4144 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
4145 mono_nullable_init_unboxed (buf, src, klass);
4147 mono_gchandle_free_internal (value_gchandle);
4148 } else {
4149 mono_nullable_init_unboxed (buf, NULL, klass);
4154 * mono_nullable_init_unboxed
4156 * @buf: The nullable structure to initialize.
4157 * @value: the unboxed address of the value to initialize from
4158 * @klass: the type for the object
4160 * Initialize the nullable structure pointed to by @buf from @value which
4161 * should be a boxed value type. The size of @buf should be able to hold
4162 * as much data as the @klass->instance_size (which is the number of bytes
4163 * that will be copies).
4165 * Since Nullables have variable structure, we can not define a C
4166 * structure for them.
4168 * This function expects all objects to be pinned or for
4169 * MONO_ENTER_NO_SAFEPOINTS to be used in a caller.
4171 void
4172 mono_nullable_init_unboxed (guint8 *buf, gpointer value, MonoClass *klass)
4174 MONO_REQ_GC_UNSAFE_MODE;
4176 MonoClass *param_class = m_class_get_cast_class (klass);
4177 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
4178 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4180 *(guint8*)(has_value_field_addr) = (value == NULL) ? 0 : 1;
4181 if (value) {
4182 if (m_class_has_references (param_class))
4183 mono_gc_wbarrier_value_copy_internal (value_field_addr, value, 1, param_class);
4184 else
4185 mono_gc_memmove_atomic (value_field_addr, value, mono_class_value_size (param_class, NULL));
4186 } else {
4187 mono_gc_bzero_atomic (value_field_addr, mono_class_value_size (param_class, NULL));
4192 * mono_nullable_box:
4193 * \param buf The buffer representing the data to be boxed
4194 * \param klass the type to box it as.
4195 * \param error set on error
4197 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
4198 * \p buf. On failure returns NULL and sets \p error.
4200 MonoObject*
4201 mono_nullable_box (gpointer vbuf, MonoClass *klass, MonoError *error)
4203 guint8 *buf = (guint8*)vbuf;
4204 MONO_REQ_GC_UNSAFE_MODE;
4206 error_init (error);
4207 MonoClass *param_class = m_class_get_cast_class (klass);
4208 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
4209 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4211 g_assertf (!m_class_is_byreflike (param_class), "Unexpected Nullable<%s> - generic type instantiated with IsByRefLike type", mono_type_get_full_name (param_class));
4213 if (*(guint8*)(has_value_field_addr)) {
4214 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
4215 return_val_if_nok (error, NULL);
4216 if (m_class_has_references (param_class))
4217 mono_gc_wbarrier_value_copy_internal (mono_object_unbox_internal (o), value_field_addr, 1, param_class);
4218 else
4219 mono_gc_memmove_atomic (mono_object_unbox_internal (o), value_field_addr, mono_class_value_size (param_class, NULL));
4220 return o;
4222 else
4223 return NULL;
4226 MonoObjectHandle
4227 mono_nullable_box_handle (gpointer buf, MonoClass *klass, MonoError *error)
4229 // FIXMEcoop gpointer buf needs more attention
4230 return MONO_HANDLE_NEW (MonoObject, mono_nullable_box (buf, klass, error));
4233 MonoMethod *
4234 mono_get_delegate_invoke_internal (MonoClass *klass)
4236 MonoMethod *result;
4237 ERROR_DECL (error);
4238 result = mono_get_delegate_invoke_checked (klass, error);
4239 /* FIXME: better external API that doesn't swallow the error */
4240 mono_error_cleanup (error);
4241 return result;
4245 * mono_get_delegate_invoke:
4246 * \param klass The delegate class
4247 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
4249 MonoMethod*
4250 mono_get_delegate_invoke (MonoClass *klass)
4252 MONO_EXTERNAL_ONLY (MonoMethod*, mono_get_delegate_invoke_internal (klass));
4256 * mono_get_delegate_invoke_checked:
4257 * \param klass The delegate class
4258 * \param error set on error
4259 * \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.
4261 * Sets \p error on error
4263 MonoMethod *
4264 mono_get_delegate_invoke_checked (MonoClass *klass, MonoError *error)
4266 MONO_REQ_GC_NEUTRAL_MODE;
4268 MonoMethod *im;
4270 /* This is called at runtime, so avoid the slower search in metadata */
4271 mono_class_setup_methods (klass);
4272 if (mono_class_has_failure (klass))
4273 return NULL;
4274 im = mono_class_get_method_from_name_checked (klass, "Invoke", -1, 0, error);
4275 return im;
4278 MonoMethod *
4279 mono_get_delegate_begin_invoke_internal (MonoClass *klass)
4281 MonoMethod *result;
4282 ERROR_DECL (error);
4283 result = mono_get_delegate_begin_invoke_checked (klass, error);
4284 /* FIXME: better external API that doesn't swallow the error */
4285 mono_error_cleanup (error);
4286 return result;
4290 * mono_get_delegate_begin_invoke:
4291 * \param klass The delegate class
4292 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4294 MonoMethod*
4295 mono_get_delegate_begin_invoke (MonoClass *klass)
4297 MONO_EXTERNAL_ONLY (MonoMethod*, mono_get_delegate_begin_invoke_internal (klass));
4301 * mono_get_delegate_begin_invoke_checked:
4302 * \param klass The delegate class
4303 * \param error set on error
4304 * \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.
4306 * Sets \p error on error
4308 MonoMethod *
4309 mono_get_delegate_begin_invoke_checked (MonoClass *klass, MonoError *error)
4311 MONO_REQ_GC_NEUTRAL_MODE;
4313 MonoMethod *im;
4315 /* This is called at runtime, so avoid the slower search in metadata */
4316 mono_class_setup_methods (klass);
4317 if (mono_class_has_failure (klass))
4318 return NULL;
4319 im = mono_class_get_method_from_name_checked (klass, "BeginInvoke", -1, 0, error);
4320 return im;
4323 MonoMethod *
4324 mono_get_delegate_end_invoke_internal (MonoClass *klass)
4326 MonoMethod *result;
4327 ERROR_DECL (error);
4328 result = mono_get_delegate_end_invoke_checked (klass, error);
4329 /* FIXME: better external API that doesn't swallow the error */
4330 mono_error_cleanup (error);
4331 return result;
4335 * mono_get_delegate_end_invoke:
4336 * \param klass The delegate class
4337 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4339 MonoMethod*
4340 mono_get_delegate_end_invoke (MonoClass *klass)
4342 MONO_EXTERNAL_ONLY (MonoMethod*, mono_get_delegate_end_invoke_internal (klass));
4346 * mono_get_delegate_end_invoke_checked:
4347 * \param klass The delegate class
4348 * \param error set on error
4349 * \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.
4351 * Sets \p error on error
4353 MonoMethod *
4354 mono_get_delegate_end_invoke_checked (MonoClass *klass, MonoError *error)
4356 MONO_REQ_GC_NEUTRAL_MODE;
4358 MonoMethod *im;
4360 /* This is called at runtime, so avoid the slower search in metadata */
4361 mono_class_setup_methods (klass);
4362 if (mono_class_has_failure (klass))
4363 return NULL;
4364 im = mono_class_get_method_from_name_checked (klass, "EndInvoke", -1, 0, error);
4365 return im;
4369 * mono_runtime_delegate_invoke:
4370 * \param delegate pointer to a delegate object.
4371 * \param params parameters for the delegate.
4372 * \param exc Pointer to the exception result.
4374 * Invokes the delegate method \p delegate with the parameters provided.
4376 * You can pass NULL as the \p exc argument if you don't want to
4377 * catch exceptions, otherwise, \c *exc will be set to the exception
4378 * thrown, if any. if an exception is thrown, you can't use the
4379 * \c MonoObject* result from the function.
4381 MonoObject*
4382 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4384 MONO_REQ_GC_UNSAFE_MODE;
4386 ERROR_DECL (error);
4387 if (exc) {
4388 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, error);
4389 if (*exc) {
4390 mono_error_cleanup (error);
4391 return NULL;
4392 } else {
4393 if (!is_ok (error))
4394 *exc = (MonoObject*)mono_error_convert_to_exception (error);
4395 return result;
4397 } else {
4398 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, error);
4399 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
4400 return result;
4405 * mono_runtime_delegate_try_invoke:
4406 * \param delegate pointer to a delegate object.
4407 * \param params parameters for the delegate.
4408 * \param exc Pointer to the exception result.
4409 * \param error set on error
4410 * Invokes the delegate method \p delegate with the parameters provided.
4412 * You can pass NULL as the \p exc argument if you don't want to
4413 * catch exceptions, otherwise, \c *exc will be set to the exception
4414 * thrown, if any. On failure to execute, \p error will be set.
4415 * if an exception is thrown, you can't use the
4416 * \c MonoObject* result from the function.
4418 MonoObject*
4419 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4421 MONO_REQ_GC_UNSAFE_MODE;
4423 error_init (error);
4424 MonoMethod *im;
4425 MonoClass *klass = delegate->vtable->klass;
4426 MonoObject *o;
4428 im = mono_get_delegate_invoke_internal (klass);
4429 g_assertf (im, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4431 if (exc) {
4432 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4433 } else {
4434 o = mono_runtime_invoke_checked (im, delegate, params, error);
4437 return o;
4440 static MonoObjectHandle
4441 mono_runtime_delegate_try_invoke_handle (MonoObjectHandle delegate, void **params, MonoError *error)
4443 MONO_REQ_GC_UNSAFE_MODE;
4445 MonoClass* const klass = MONO_HANDLE_GETVAL (delegate, vtable)->klass;
4446 MonoMethod* const im = mono_get_delegate_invoke_internal (klass);
4447 g_assertf (im, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4449 return mono_runtime_try_invoke_handle (im, delegate, params, error);
4453 * mono_runtime_delegate_invoke_checked:
4454 * \param delegate pointer to a delegate object.
4455 * \param params parameters for the delegate.
4456 * \param error set on error
4457 * Invokes the delegate method \p delegate with the parameters provided.
4458 * On failure \p error will be set and you can't use the \c MonoObject*
4459 * result from the function.
4461 MonoObject*
4462 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4464 error_init (error);
4465 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4468 static char **main_args = NULL;
4469 static int num_main_args = 0;
4472 * mono_runtime_get_main_args:
4473 * \returns A \c MonoArray with the arguments passed to the main program
4475 MonoArray*
4476 mono_runtime_get_main_args (void)
4478 HANDLE_FUNCTION_ENTER ();
4479 MONO_REQ_GC_UNSAFE_MODE;
4480 ERROR_DECL (error);
4481 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
4482 error_init (error);
4483 MonoArrayHandle arg_array = mono_runtime_get_main_args_handle (error);
4484 goto_if_nok (error, leave);
4485 MONO_HANDLE_ASSIGN (result, arg_array);
4486 leave:
4487 /* FIXME: better external API that doesn't swallow the error */
4488 mono_error_cleanup (error);
4489 HANDLE_FUNCTION_RETURN_OBJ (result);
4492 static gboolean
4493 handle_main_arg_array_set (MonoDomain *domain, int idx, MonoArrayHandle dest, MonoError *error)
4495 HANDLE_FUNCTION_ENTER ();
4496 error_init (error);
4497 MonoStringHandle value = mono_string_new_handle (domain, main_args [idx], error);
4498 goto_if_nok (error, leave);
4499 MONO_HANDLE_ARRAY_SETREF (dest, idx, value);
4500 leave:
4501 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
4505 * mono_runtime_get_main_args_handle:
4506 * \param error set on error
4507 * \returns a \c MonoArray with the arguments passed to the main
4508 * program. On failure returns NULL and sets \p error.
4510 MonoArrayHandle
4511 mono_runtime_get_main_args_handle (MonoError *error)
4513 HANDLE_FUNCTION_ENTER ();
4514 MonoArrayHandle array;
4515 int i;
4516 MonoDomain *domain = mono_domain_get ();
4517 error_init (error);
4519 array = mono_array_new_handle (domain, mono_defaults.string_class, num_main_args, error);
4520 if (!is_ok (error)) {
4521 array = MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
4522 goto leave;
4524 for (i = 0; i < num_main_args; ++i) {
4525 if (!handle_main_arg_array_set (domain, i, array, error))
4526 goto leave;
4528 leave:
4529 HANDLE_FUNCTION_RETURN_REF (MonoArray, array);
4532 static void
4533 free_main_args (void)
4535 MONO_REQ_GC_NEUTRAL_MODE;
4537 int i;
4539 for (i = 0; i < num_main_args; ++i)
4540 g_free (main_args [i]);
4541 g_free (main_args);
4542 num_main_args = 0;
4543 main_args = NULL;
4547 * mono_runtime_set_main_args:
4548 * \param argc number of arguments from the command line
4549 * \param argv array of strings from the command line
4550 * Set the command line arguments from an embedding application that doesn't otherwise call
4551 * \c mono_runtime_run_main.
4554 mono_runtime_set_main_args (int argc, char* argv[])
4556 MONO_REQ_GC_NEUTRAL_MODE;
4558 int i;
4560 free_main_args ();
4561 main_args = g_new0 (char*, argc);
4562 num_main_args = argc;
4564 for (i = 0; i < argc; ++i) {
4565 gchar *utf8_arg;
4567 utf8_arg = mono_utf8_from_external (argv[i]);
4568 if (utf8_arg == NULL) {
4569 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4570 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4571 exit (-1);
4574 main_args [i] = utf8_arg;
4577 MONO_EXTERNAL_ONLY (int, 0);
4581 * Prepare an array of arguments in order to execute a standard Main()
4582 * method (argc/argv contains the executable name). This method also
4583 * sets the command line argument value needed by System.Environment.
4586 static MonoArray*
4587 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4589 MONO_REQ_GC_UNSAFE_MODE;
4591 ERROR_DECL (error);
4592 int i;
4593 MonoArray *args = NULL;
4594 MonoDomain *domain = mono_domain_get ();
4595 gchar *utf8_fullpath;
4596 MonoMethodSignature *sig;
4598 g_assert (method != NULL);
4600 mono_thread_set_main (mono_thread_current ());
4602 main_args = g_new0 (char*, argc);
4603 num_main_args = argc;
4605 if (!g_path_is_absolute (argv [0])) {
4606 gchar *basename = g_path_get_basename (argv [0]);
4607 gchar *fullpath = g_build_filename (m_class_get_image (method->klass)->assembly->basedir,
4608 basename,
4609 (const char*)NULL);
4611 utf8_fullpath = mono_utf8_from_external (fullpath);
4612 if(utf8_fullpath == NULL) {
4613 /* Printing the arg text will cause glib to
4614 * whinge about "Invalid UTF-8", but at least
4615 * its relevant, and shows the problem text
4616 * string.
4618 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4619 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4620 exit (-1);
4623 g_free (fullpath);
4624 g_free (basename);
4625 } else {
4626 utf8_fullpath = mono_utf8_from_external (argv[0]);
4627 if(utf8_fullpath == NULL) {
4628 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4629 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4630 exit (-1);
4634 main_args [0] = utf8_fullpath;
4636 for (i = 1; i < argc; ++i) {
4637 gchar *utf8_arg;
4639 utf8_arg=mono_utf8_from_external (argv[i]);
4640 if(utf8_arg==NULL) {
4641 /* Ditto the comment about Invalid UTF-8 here */
4642 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4643 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4644 exit (-1);
4647 main_args [i] = utf8_arg;
4649 argc--;
4650 argv++;
4652 sig = mono_method_signature_internal (method);
4653 if (!sig) {
4654 g_print ("Unable to load Main method.\n");
4655 exit (-1);
4658 if (sig->param_count) {
4659 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, error);
4660 mono_error_assert_ok (error);
4661 for (i = 0; i < argc; ++i) {
4662 /* The encodings should all work, given that
4663 * we've checked all these args for the
4664 * main_args array.
4666 gchar *str = mono_utf8_from_external (argv [i]);
4667 MonoString *arg = mono_string_new_checked (domain, str, error);
4668 mono_error_assert_ok (error);
4669 mono_array_setref_internal (args, i, arg);
4670 g_free (str);
4672 } else {
4673 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, error);
4674 mono_error_assert_ok (error);
4677 mono_assembly_set_main (m_class_get_image (method->klass)->assembly);
4679 return args;
4683 * mono_runtime_run_main:
4684 * \param method the method to start the application with (usually <code>Main</code>)
4685 * \param argc number of arguments from the command line
4686 * \param argv array of strings from the command line
4687 * \param exc excetption results
4688 * Execute a standard \c Main method (\p argc / \p argv contains the
4689 * executable name). This method also sets the command line argument value
4690 * needed by \c System.Environment.
4693 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4694 MonoObject **exc)
4696 int res;
4698 MONO_REQ_GC_UNSAFE_MODE;
4700 ERROR_DECL (error);
4702 MONO_ENTER_GC_UNSAFE;
4704 MonoArray *args = prepare_run_main (method, argc, argv);
4705 if (exc)
4706 res = mono_runtime_try_exec_main (method, args, exc);
4707 else
4708 res = mono_runtime_exec_main_checked (method, args, error);
4710 MONO_EXIT_GC_UNSAFE;
4712 if (!exc)
4713 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a better alternative */
4715 return res;
4719 * mono_runtime_run_main_checked:
4720 * \param method the method to start the application with (usually \c Main)
4721 * \param argc number of arguments from the command line
4722 * \param argv array of strings from the command line
4723 * \param error set on error
4725 * Execute a standard \c Main method (\p argc / \p argv contains the
4726 * executable name). This method also sets the command line argument value
4727 * needed by \c System.Environment. On failure sets \p error.
4730 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4731 MonoError *error)
4733 error_init (error);
4734 MonoArray *args = prepare_run_main (method, argc, argv);
4735 return mono_runtime_exec_main_checked (method, args, error);
4739 * mono_runtime_try_run_main:
4740 * \param method the method to start the application with (usually \c Main)
4741 * \param argc number of arguments from the command line
4742 * \param argv array of strings from the command line
4743 * \param exc set if \c Main throws an exception
4744 * \param error set if \c Main can't be executed
4745 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4746 * name). This method also sets the command line argument value needed
4747 * by \c System.Environment. On failure sets \p error if Main can't be
4748 * executed or \p exc if it threw an exception.
4751 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4752 MonoObject **exc)
4754 g_assert (exc);
4755 MonoArray *args = prepare_run_main (method, argc, argv);
4756 return mono_runtime_try_exec_main (method, args, exc);
4759 MonoObjectHandle
4760 mono_new_null (void) // A code size optimization (source and object).
4762 return MONO_HANDLE_NEW (MonoObject, NULL);
4765 static MonoObjectHandle
4766 serialize_or_deserialize_object (MonoObjectHandle obj, const gchar *method_name, MonoMethod **method, MonoError *error)
4768 if (!*method) {
4769 MonoClass *klass = mono_class_get_remoting_services_class ();
4770 *method = mono_class_get_method_from_name_checked (klass, method_name, -1, 0, error);
4771 return_val_if_nok (error, mono_new_null ());
4774 if (!*method) {
4775 mono_error_set_exception_instance (error, NULL);
4776 return mono_new_null ();
4779 void *params [ ] = { MONO_HANDLE_RAW (obj) };
4780 return mono_runtime_try_invoke_handle (*method, NULL_HANDLE, params, error);
4783 static MonoMethod *serialize_method;
4785 static MonoObjectHandle
4786 serialize_object (MonoObjectHandle obj, MonoError *error)
4788 g_assert (!mono_class_is_marshalbyref (mono_handle_class (obj)));
4789 return serialize_or_deserialize_object (obj, "SerializeCallData", &serialize_method, error);
4792 static MonoMethod *deserialize_method;
4794 static MonoObjectHandle
4795 deserialize_object (MonoObjectHandle obj, MonoError *error)
4797 MONO_REQ_GC_UNSAFE_MODE;
4798 return serialize_or_deserialize_object (obj, "DeserializeCallData", &deserialize_method, error);
4801 #ifndef DISABLE_REMOTING
4802 static MonoObjectHandle
4803 make_transparent_proxy (MonoObjectHandle obj, MonoError *error)
4805 MONO_REQ_GC_UNSAFE_MODE;
4807 static MonoMethod *get_proxy_method;
4809 if (!get_proxy_method) {
4810 get_proxy_method = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "GetTransparentProxy", 0, 0, error);
4811 mono_error_assert_ok (error);
4814 g_assert (mono_class_is_marshalbyref (MONO_HANDLE_GETVAL (obj, vtable)->klass));
4816 MonoDomain *domain = mono_domain_get ();
4817 MonoRealProxyHandle real_proxy = MONO_HANDLE_CAST (MonoRealProxy, mono_object_new_handle (domain, mono_defaults.real_proxy_class, error));
4818 goto_if_nok (error, return_null);
4819 MonoReflectionTypeHandle reflection_type;
4820 reflection_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (mono_handle_class (obj)), error);
4821 goto_if_nok (error, return_null);
4823 MONO_HANDLE_SET (real_proxy, class_to_proxy, reflection_type);
4824 MONO_HANDLE_SET (real_proxy, unwrapped_server, obj);
4826 return mono_runtime_try_invoke_handle (get_proxy_method, MONO_HANDLE_CAST (MonoObject, real_proxy), NULL, error);
4827 return_null:
4828 return mono_new_null ();
4830 #endif /* DISABLE_REMOTING */
4833 * mono_object_xdomain_representation
4834 * \param obj an object
4835 * \param target_domain a domain
4836 * \param error set on error.
4837 * Creates a representation of obj in the domain \p target_domain. This
4838 * is either a copy of \p obj arrived through via serialization and
4839 * deserialization or a proxy, depending on whether the object is
4840 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4841 * If the object cannot be represented in \p target_domain, NULL is
4842 * returned and \p error is set appropriately.
4844 MonoObjectHandle
4845 mono_object_xdomain_representation (MonoObjectHandle obj, MonoDomain *target_domain, MonoError *error)
4847 HANDLE_FUNCTION_ENTER ();
4849 MONO_REQ_GC_UNSAFE_MODE;
4851 MonoObjectHandle deserialized;
4853 #ifndef DISABLE_REMOTING
4854 if (mono_class_is_marshalbyref (mono_handle_class (obj))) {
4855 deserialized = make_transparent_proxy (obj, error);
4857 else
4858 #endif
4860 MonoDomain *domain = mono_domain_get ();
4862 mono_domain_set_internal_with_options (MONO_HANDLE_DOMAIN (obj), FALSE);
4863 MonoObjectHandle serialized = serialize_object (obj, error);
4864 mono_domain_set_internal_with_options (target_domain, FALSE);
4865 if (is_ok (error))
4866 deserialized = deserialize_object (serialized, error);
4867 else
4868 deserialized = mono_new_null ();
4870 if (domain != target_domain)
4871 mono_domain_set_internal_with_options (domain, FALSE);
4874 HANDLE_FUNCTION_RETURN_REF (MonoObject, deserialized);
4877 /* Used in call_unhandled_exception_delegate */
4878 static MonoObjectHandle
4879 create_unhandled_exception_eventargs (MonoObjectHandle exc, MonoError *error)
4881 MONO_REQ_GC_UNSAFE_MODE;
4883 MonoClass * const klass = mono_class_get_unhandled_exception_event_args_class ();
4884 mono_class_init_internal (klass);
4886 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4887 MonoMethod * const method = mono_class_get_method_from_name_checked (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC, error);
4888 goto_if_nok (error, return_null);
4889 g_assert (method);
4892 MonoBoolean is_terminating = TRUE;
4894 gpointer args [ ] = {
4895 MONO_HANDLE_RAW (exc), // FIXMEcoop (ok as long as handles are pinning)
4896 &is_terminating
4899 MonoObjectHandle obj = mono_object_new_handle (mono_domain_get (), klass, error);
4900 goto_if_nok (error, return_null);
4902 mono_runtime_invoke_handle_void (method, obj, args, error);
4903 goto_if_nok (error, return_null);
4904 return obj;
4907 return_null:
4908 return MONO_HANDLE_NEW (MonoObject, NULL);
4911 /* Used in mono_unhandled_exception_internal */
4912 static void
4913 call_unhandled_exception_delegate (MonoDomain *domain, MonoObjectHandle delegate, MonoObjectHandle exc)
4915 MONO_REQ_GC_UNSAFE_MODE;
4917 ERROR_DECL (error);
4918 MonoDomain *current_domain = mono_domain_get ();
4920 if (domain != current_domain)
4921 mono_domain_set_internal_with_options (domain, FALSE);
4923 g_assert (domain == mono_object_domain (domain->domain));
4925 if (MONO_HANDLE_DOMAIN (exc) != domain) {
4927 exc = mono_object_xdomain_representation (exc, domain, error);
4928 if (MONO_HANDLE_IS_NULL (exc)) {
4929 ERROR_DECL (inner_error);
4930 if (!is_ok (error)) {
4931 MonoExceptionHandle serialization_exc = mono_error_convert_to_exception_handle (error);
4932 exc = mono_object_xdomain_representation (MONO_HANDLE_CAST (MonoObject, serialization_exc), domain, inner_error);
4933 } else {
4934 exc = MONO_HANDLE_CAST (MonoObject, mono_exception_new_serialization ("Could not serialize unhandled exception.", inner_error));
4936 mono_error_assert_ok (inner_error);
4939 g_assert (MONO_HANDLE_DOMAIN (exc) == domain);
4941 gpointer pa [ ] = {
4942 domain->domain,
4943 MONO_HANDLE_RAW (create_unhandled_exception_eventargs (exc, error)) // FIXMEcoop
4945 mono_error_assert_ok (error);
4946 mono_runtime_delegate_try_invoke_handle (delegate, pa, error);
4948 if (domain != current_domain)
4949 mono_domain_set_internal_with_options (current_domain, FALSE);
4951 if (!is_ok (error)) {
4952 g_warning ("exception inside UnhandledException handler: %s\n", mono_error_get_message (error));
4953 mono_error_cleanup (error);
4957 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4960 * mono_runtime_unhandled_exception_policy_set:
4961 * \param policy the new policy
4962 * This is a VM internal routine.
4963 * Sets the runtime policy for handling unhandled exceptions.
4965 void
4966 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy)
4968 runtime_unhandled_exception_policy = policy;
4972 * mono_runtime_unhandled_exception_policy_get:
4974 * This is a VM internal routine.
4976 * Gets the runtime policy for handling unhandled exceptions.
4978 MonoRuntimeUnhandledExceptionPolicy
4979 mono_runtime_unhandled_exception_policy_get (void)
4981 return runtime_unhandled_exception_policy;
4984 void
4985 mono_unhandled_exception_internal (MonoObject *exc_raw)
4987 ERROR_DECL (error);
4988 HANDLE_FUNCTION_ENTER ();
4989 MONO_HANDLE_DCL (MonoObject, exc);
4990 mono_unhandled_exception_checked (exc, error);
4991 mono_error_assert_ok (error);
4992 HANDLE_FUNCTION_RETURN ();
4996 * mono_unhandled_exception:
4997 * \param exc exception thrown
4998 * This is a VM internal routine.
5000 * We call this function when we detect an unhandled exception
5001 * in the default domain.
5003 * It invokes the \c UnhandledException event in \c AppDomain or prints
5004 * a warning to the console
5006 void
5007 mono_unhandled_exception (MonoObject *exc)
5009 MONO_EXTERNAL_ONLY_VOID (mono_unhandled_exception_internal (exc));
5013 * mono_unhandled_exception_checked:
5014 * @exc: exception thrown
5016 * This is a VM internal routine.
5018 * We call this function when we detect an unhandled exception
5019 * in the default domain.
5021 * It invokes the * UnhandledException event in AppDomain or prints
5022 * a warning to the console
5024 void
5025 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
5027 MONO_REQ_GC_UNSAFE_MODE;
5029 MonoClassField *field;
5030 MonoDomain *current_domain, *root_domain;
5031 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
5033 MonoClass *klass = mono_handle_class (exc);
5035 * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
5036 * a thread started in unmanaged world.
5037 * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
5039 gboolean no_event = (klass == mono_defaults.threadabortexception_class);
5040 #ifndef ENABLE_NETCORE
5041 no_event = no_event ||
5042 (klass == mono_class_get_appdomain_unloaded_exception_class () &&
5043 mono_thread_info_current ()->runtime_thread);
5044 #endif
5045 if (no_event)
5046 return;
5048 field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "UnhandledException", NULL);
5049 g_assert (field);
5051 current_domain = mono_domain_get ();
5052 root_domain = mono_get_root_domain ();
5054 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 */
5055 return_if_nok (error);
5056 if (current_domain != root_domain) {
5057 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 */
5058 return_if_nok (error);
5061 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
5062 mono_print_unhandled_exception_internal (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
5063 } else {
5064 /* unhandled exception callbacks must not be aborted */
5065 mono_threads_begin_abort_protected_block ();
5066 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
5067 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
5068 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
5069 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
5070 mono_threads_end_abort_protected_block ();
5073 /* set exitcode only if we will abort the process */
5074 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
5075 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
5077 mono_environment_exitcode_set (1);
5082 * mono_runtime_exec_managed_code:
5083 * \param domain Application domain
5084 * \param main_func function to invoke from the execution thread
5085 * \param main_args parameter to the main_func
5086 * Launch a new thread to execute a function
5088 * \p main_func is called back from the thread with main_args as the
5089 * parameter. The callback function is expected to start \c Main
5090 * eventually. This function then waits for all managed threads to
5091 * finish.
5092 * It is not necessary anymore to execute managed code in a subthread,
5093 * so this function should not be used anymore by default: just
5094 * execute the code and then call mono_thread_manage().
5096 void
5097 mono_runtime_exec_managed_code (MonoDomain *domain,
5098 MonoMainThreadFunc mfunc,
5099 gpointer margs)
5101 // This function is external_only.
5102 MONO_ENTER_GC_UNSAFE;
5104 ERROR_DECL (error);
5105 mono_thread_create_checked (domain, mfunc, margs, error);
5106 mono_error_assert_ok (error);
5108 mono_thread_manage_internal ();
5110 MONO_EXIT_GC_UNSAFE;
5113 static void
5114 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
5116 MONO_REQ_GC_UNSAFE_MODE;
5117 MonoInternalThread* thread = mono_thread_internal_current ();
5118 MonoCustomAttrInfo* cinfo;
5119 gboolean has_stathread_attribute;
5121 if (!domain->entry_assembly) {
5122 gchar *str;
5123 ERROR_DECL (error);
5124 MonoAssembly *assembly;
5126 assembly = m_class_get_image (method->klass)->assembly;
5127 domain->entry_assembly = assembly;
5128 /* Domains created from another domain already have application_base and configuration_file set */
5129 if (domain->setup->application_base == NULL) {
5130 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, error);
5131 mono_error_assert_ok (error);
5132 MONO_OBJECT_SETREF_INTERNAL (domain->setup, application_base, basedir);
5135 if (domain->setup->configuration_file == NULL) {
5136 str = g_strconcat (assembly->image->name, ".config", (const char*)NULL);
5137 MonoString *config_file = mono_string_new_checked (domain, str, error);
5138 mono_error_assert_ok (error);
5139 MONO_OBJECT_SETREF_INTERNAL (domain->setup, configuration_file, config_file);
5140 g_free (str);
5141 mono_domain_set_options_from_config (domain);
5145 ERROR_DECL (cattr_error);
5146 cinfo = mono_custom_attrs_from_method_checked (method, cattr_error);
5147 mono_error_cleanup (cattr_error); /* FIXME warn here? */
5148 if (cinfo) {
5149 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
5150 if (!cinfo->cached)
5151 mono_custom_attrs_free (cinfo);
5152 } else {
5153 has_stathread_attribute = FALSE;
5155 if (has_stathread_attribute) {
5156 thread->apartment_state = ThreadApartmentState_STA;
5157 } else {
5158 thread->apartment_state = ThreadApartmentState_MTA;
5160 mono_thread_init_apartment_state ();
5164 static int
5165 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
5167 MONO_REQ_GC_UNSAFE_MODE;
5169 gpointer pa [1];
5170 int rval;
5172 error_init (error);
5173 g_assert (args);
5175 pa [0] = args;
5177 /* FIXME: check signature of method */
5178 if (mono_method_signature_internal (method)->ret->type == MONO_TYPE_I4) {
5179 MonoObject *res;
5180 res = mono_runtime_invoke_checked (method, NULL, pa, error);
5181 if (is_ok (error))
5182 rval = *(guint32 *)(mono_object_get_data (res));
5183 else
5184 rval = -1;
5185 mono_environment_exitcode_set (rval);
5186 } else {
5187 mono_runtime_invoke_checked (method, NULL, pa, error);
5189 if (is_ok (error))
5190 rval = 0;
5191 else {
5192 rval = -1;
5195 return rval;
5198 static int
5199 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5201 MONO_REQ_GC_UNSAFE_MODE;
5203 gpointer pa [1];
5204 int rval;
5206 g_assert (args);
5207 g_assert (exc);
5209 pa [0] = args;
5211 /* FIXME: check signature of method */
5212 if (mono_method_signature_internal (method)->ret->type == MONO_TYPE_I4) {
5213 ERROR_DECL (inner_error);
5214 MonoObject *res;
5215 res = mono_runtime_try_invoke (method, NULL, pa, exc, inner_error);
5216 if (*exc == NULL && !is_ok (inner_error))
5217 *exc = (MonoObject*) mono_error_convert_to_exception (inner_error);
5218 else
5219 mono_error_cleanup (inner_error);
5221 if (*exc == NULL)
5222 rval = *(guint32 *)(mono_object_get_data (res));
5223 else
5224 rval = -1;
5226 mono_environment_exitcode_set (rval);
5227 } else {
5228 ERROR_DECL (inner_error);
5229 mono_runtime_try_invoke (method, NULL, pa, exc, inner_error);
5230 if (*exc == NULL && !is_ok (inner_error))
5231 *exc = (MonoObject*) mono_error_convert_to_exception (inner_error);
5232 else
5233 mono_error_cleanup (inner_error);
5235 if (*exc == NULL)
5236 rval = 0;
5237 else {
5238 /* If the return type of Main is void, only
5239 * set the exitcode if an exception was thrown
5240 * (we don't want to blow away an
5241 * explicitly-set exit code)
5243 rval = -1;
5244 mono_environment_exitcode_set (rval);
5248 return rval;
5252 * Execute a standard Main() method (args doesn't contain the
5253 * executable name).
5256 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5258 int rval;
5259 MONO_ENTER_GC_UNSAFE;
5260 ERROR_DECL (error);
5261 prepare_thread_to_exec_main (mono_object_domain (args), method);
5262 if (exc) {
5263 rval = do_try_exec_main (method, args, exc);
5264 } else {
5265 rval = do_exec_main_checked (method, args, error);
5266 // FIXME Maybe change mode back here?
5267 mono_error_raise_exception_deprecated (error); /* OK to throw, external only with no better option */
5269 MONO_EXIT_GC_UNSAFE;
5270 return rval;
5274 * Execute a standard Main() method (args doesn't contain the
5275 * executable name).
5277 * On failure sets @error
5280 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
5282 error_init (error);
5283 prepare_thread_to_exec_main (mono_object_domain (args), method);
5284 return do_exec_main_checked (method, args, error);
5288 * Execute a standard Main() method (args doesn't contain the
5289 * executable name).
5291 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
5294 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5296 prepare_thread_to_exec_main (mono_object_domain (args), method);
5297 return do_try_exec_main (method, args, exc);
5300 /** invoke_array_extract_argument:
5301 * @params: array of arguments to the method.
5302 * @i: the index of the argument to extract.
5303 * @t: ith type from the method signature.
5304 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
5305 * @error: set on error.
5307 * Given an array of method arguments, return the ith one using the corresponding type
5308 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
5310 * On failure sets @error and returns NULL.
5312 static gpointer
5313 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
5315 MonoType *t_orig = t;
5316 gpointer result = NULL;
5317 error_init (error);
5318 again:
5319 switch (t->type) {
5320 case MONO_TYPE_U1:
5321 case MONO_TYPE_I1:
5322 case MONO_TYPE_BOOLEAN:
5323 case MONO_TYPE_U2:
5324 case MONO_TYPE_I2:
5325 case MONO_TYPE_CHAR:
5326 case MONO_TYPE_U:
5327 case MONO_TYPE_I:
5328 case MONO_TYPE_U4:
5329 case MONO_TYPE_I4:
5330 case MONO_TYPE_U8:
5331 case MONO_TYPE_I8:
5332 case MONO_TYPE_R4:
5333 case MONO_TYPE_R8:
5334 case MONO_TYPE_VALUETYPE:
5335 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type_internal (t_orig))) {
5336 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
5337 result = mono_array_get_internal (params, MonoObject*, i);
5338 if (t->byref)
5339 *has_byref_nullables = TRUE;
5340 } else {
5341 /* MS seems to create the objects if a null is passed in */
5342 gboolean was_null = FALSE;
5343 if (!mono_array_get_internal (params, MonoObject*, i)) {
5344 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type_internal (t_orig), error);
5345 return_val_if_nok (error, NULL);
5346 mono_array_setref_internal (params, i, o);
5347 was_null = TRUE;
5350 if (t->byref) {
5352 * We can't pass the unboxed vtype byref to the callee, since
5353 * that would mean the callee would be able to modify boxed
5354 * primitive types. So we (and MS) make a copy of the boxed
5355 * object, pass that to the callee, and replace the original
5356 * boxed object in the arg array with the copy.
5358 MonoObject *orig = mono_array_get_internal (params, MonoObject*, i);
5359 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox_internal (orig), error);
5360 return_val_if_nok (error, NULL);
5361 mono_array_setref_internal (params, i, copy);
5364 result = mono_object_unbox_internal (mono_array_get_internal (params, MonoObject*, i));
5365 if (!t->byref && was_null)
5366 mono_array_setref_internal (params, i, NULL);
5368 break;
5369 case MONO_TYPE_STRING:
5370 case MONO_TYPE_OBJECT:
5371 case MONO_TYPE_CLASS:
5372 case MONO_TYPE_ARRAY:
5373 case MONO_TYPE_SZARRAY:
5374 if (t->byref)
5375 result = mono_array_addr_internal (params, MonoObject*, i);
5376 // FIXME: I need to check this code path
5377 else
5378 result = mono_array_get_internal (params, MonoObject*, i);
5379 break;
5380 case MONO_TYPE_GENERICINST:
5381 if (t->byref)
5382 t = m_class_get_this_arg (t->data.generic_class->container_class);
5383 else
5384 t = m_class_get_byval_arg (t->data.generic_class->container_class);
5385 goto again;
5386 case MONO_TYPE_PTR: {
5387 MonoObject *arg;
5389 /* The argument should be an IntPtr */
5390 arg = mono_array_get_internal (params, MonoObject*, i);
5391 if (arg == NULL) {
5392 result = NULL;
5393 } else {
5394 g_assert (arg->vtable->klass == mono_defaults.int_class);
5395 result = ((MonoIntPtr*)arg)->m_value;
5397 break;
5399 default:
5400 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
5402 return result;
5405 * mono_runtime_invoke_array:
5406 * \param method method to invoke
5407 * \param obj object instance
5408 * \param params arguments to the method
5409 * \param exc exception information.
5410 * Invokes the method represented by \p method on the object \p obj.
5412 * \p obj is the \c this pointer, it should be NULL for static
5413 * methods, a \c MonoObject* for object instances and a pointer to
5414 * the value type for value types.
5416 * The \p params array contains the arguments to the method with the
5417 * same convention: \c MonoObject* pointers for object instances and
5418 * pointers to the value type otherwise. The \c _invoke_array
5419 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5420 * in this case the value types are boxed inside the
5421 * respective reference representation.
5423 * From unmanaged code you'll usually use the
5424 * mono_runtime_invoke_checked() variant.
5426 * Note that this function doesn't handle virtual methods for
5427 * you, it will exec the exact method you pass: we still need to
5428 * expose a function to lookup the derived class implementation
5429 * of a virtual method (there are examples of this in the code,
5430 * though).
5432 * You can pass NULL as the \p exc argument if you don't want to
5433 * catch exceptions, otherwise, \c *exc will be set to the exception
5434 * thrown, if any. if an exception is thrown, you can't use the
5435 * \c MonoObject* result from the function.
5437 * If the method returns a value type, it is boxed in an object
5438 * reference.
5440 MonoObject*
5441 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5442 MonoObject **exc)
5444 ERROR_DECL (error);
5445 if (exc) {
5446 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, error);
5447 if (*exc) {
5448 mono_error_cleanup (error);
5449 return NULL;
5450 } else {
5451 if (!is_ok (error))
5452 *exc = (MonoObject*)mono_error_convert_to_exception (error);
5453 return result;
5455 } else {
5456 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5457 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
5458 return result;
5463 * mono_runtime_invoke_array_checked:
5464 * \param method method to invoke
5465 * \param obj object instance
5466 * \param params arguments to the method
5467 * \param error set on failure.
5468 * Invokes the method represented by \p method on the object \p obj.
5470 * \p obj is the \c this pointer, it should be NULL for static
5471 * methods, a \c MonoObject* for object instances and a pointer to
5472 * the value type for value types.
5474 * The \p params array contains the arguments to the method with the
5475 * same convention: \c MonoObject* pointers for object instances and
5476 * pointers to the value type otherwise. The \c _invoke_array
5477 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5478 * in this case the value types are boxed inside the
5479 * respective reference representation.
5481 * From unmanaged code you'll usually use the
5482 * mono_runtime_invoke_checked() variant.
5484 * Note that this function doesn't handle virtual methods for
5485 * you, it will exec the exact method you pass: we still need to
5486 * expose a function to lookup the derived class implementation
5487 * of a virtual method (there are examples of this in the code,
5488 * though).
5490 * On failure or exception, \p error will be set. In that case, you
5491 * can't use the \c MonoObject* result from the function.
5493 * If the method returns a value type, it is boxed in an object
5494 * reference.
5496 MonoObject*
5497 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5498 MonoError *error)
5500 error_init (error);
5501 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5505 * mono_runtime_try_invoke_array:
5506 * \param method method to invoke
5507 * \param obj object instance
5508 * \param params arguments to the method
5509 * \param exc exception information.
5510 * \param error set on failure.
5511 * Invokes the method represented by \p method on the object \p obj.
5513 * \p obj is the \c this pointer, it should be NULL for static
5514 * methods, a \c MonoObject* for object instances and a pointer to
5515 * the value type for value types.
5517 * The \p params array contains the arguments to the method with the
5518 * same convention: \c MonoObject* pointers for object instances and
5519 * pointers to the value type otherwise. The \c _invoke_array
5520 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5521 * in this case the value types are boxed inside the
5522 * respective reference representation.
5524 * From unmanaged code you'll usually use the
5525 * mono_runtime_invoke_checked() variant.
5527 * Note that this function doesn't handle virtual methods for
5528 * you, it will exec the exact method you pass: we still need to
5529 * expose a function to lookup the derived class implementation
5530 * of a virtual method (there are examples of this in the code,
5531 * though).
5533 * You can pass NULL as the \p exc argument if you don't want to catch
5534 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5535 * any. On other failures, \p error will be set. If an exception is
5536 * thrown or there's an error, you can't use the \c MonoObject* result
5537 * from the function.
5539 * If the method returns a value type, it is boxed in an object
5540 * reference.
5542 MonoObject*
5543 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5544 MonoObject **exc, MonoError *error)
5546 MONO_REQ_GC_UNSAFE_MODE;
5548 error_init (error);
5550 MonoMethodSignature *sig = mono_method_signature_internal (method);
5551 gpointer *pa = NULL;
5552 MonoObject *res;
5553 int i;
5554 gboolean has_byref_nullables = FALSE;
5556 if (NULL != params) {
5557 pa = g_newa (gpointer, mono_array_length_internal (params));
5558 for (i = 0; i < mono_array_length_internal (params); i++) {
5559 MonoType *t = sig->params [i];
5560 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5561 return_val_if_nok (error, NULL);
5565 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5566 void *o = obj;
5568 if (mono_class_is_nullable (method->klass)) {
5569 /* Need to create a boxed vtype instead */
5570 g_assert (!obj);
5572 if (!params)
5573 return NULL;
5574 else {
5575 return mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method->klass), pa [0], error);
5579 if (!obj) {
5580 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5581 return_val_if_nok (error, NULL);
5582 g_assert (obj); /*maybe we should raise a TLE instead?*/
5583 #ifndef DISABLE_REMOTING
5584 if (mono_object_is_transparent_proxy (obj)) {
5585 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : m_class_get_vtable (method->klass) [method->slot], error);
5586 return_val_if_nok (error, NULL);
5588 #endif
5589 if (m_class_is_valuetype (method->klass))
5590 o = (MonoObject *)mono_object_unbox_internal ((MonoObject *)obj);
5591 else
5592 o = obj;
5593 } else if (m_class_is_valuetype (method->klass)) {
5594 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5595 return_val_if_nok (error, NULL);
5598 if (exc) {
5599 mono_runtime_try_invoke (method, o, pa, exc, error);
5600 } else {
5601 mono_runtime_invoke_checked (method, o, pa, error);
5604 return (MonoObject *)obj;
5605 } else {
5606 if (mono_class_is_nullable (method->klass)) {
5607 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
5608 obj = NULL;
5609 } else {
5610 MonoObject *nullable;
5611 /* Convert the unboxed vtype into a Nullable structure */
5612 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5613 return_val_if_nok (error, NULL);
5615 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method->klass), obj, error);
5616 return_val_if_nok (error, NULL);
5617 mono_nullable_init ((guint8 *)mono_object_unbox_internal (nullable), boxed, method->klass);
5618 obj = mono_object_unbox_internal (nullable);
5622 /* obj must be already unboxed if needed */
5623 if (exc) {
5624 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5625 } else {
5626 res = mono_runtime_invoke_checked (method, obj, pa, error);
5628 return_val_if_nok (error, NULL);
5630 if (sig->ret->type == MONO_TYPE_PTR) {
5631 MonoClass *pointer_class;
5632 void *box_args [2];
5633 MonoObject *box_exc;
5636 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5637 * convert it to a Pointer object.
5639 pointer_class = mono_class_get_pointer_class ();
5641 MONO_STATIC_POINTER_INIT (MonoMethod, box_method)
5642 box_method = mono_class_get_method_from_name_checked (pointer_class, "Box", -1, 0, error);
5643 mono_error_assert_ok (error);
5644 MONO_STATIC_POINTER_INIT_END (MonoMethod, box_method)
5646 g_assert (res->vtable->klass == mono_defaults.int_class);
5647 box_args [0] = ((MonoIntPtr*)res)->m_value;
5648 if (sig->ret->byref) {
5649 // byref is already unboxed by the invoke code
5650 MonoType *tmpret = mono_metadata_type_dup (NULL, sig->ret);
5651 tmpret->byref = FALSE;
5652 box_args [1] = mono_type_get_object_checked (mono_domain_get (), tmpret, error);
5653 mono_metadata_free_type (tmpret);
5654 } else {
5655 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5657 return_val_if_nok (error, NULL);
5659 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5660 g_assert (box_exc == NULL);
5661 mono_error_assert_ok (error);
5664 if (has_byref_nullables) {
5666 * The runtime invoke wrapper already converted byref nullables back,
5667 * and stored them in pa, we just need to copy them back to the
5668 * managed array.
5670 for (i = 0; i < mono_array_length_internal (params); i++) {
5671 MonoType *t = sig->params [i];
5673 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
5674 mono_array_setref_internal (params, i, pa [i]);
5678 return res;
5682 // FIXME these will move to header soon
5683 static MonoObjectHandle
5684 mono_object_new_by_vtable (MonoVTable *vtable, MonoError *error);
5687 * object_new_common_tail:
5689 * This function centralizes post-processing of objects upon creation.
5690 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields,
5691 * and setting error.
5693 static MonoObject*
5694 object_new_common_tail (MonoObject *o, MonoClass *klass, MonoError *error)
5696 error_init (error);
5698 if (G_UNLIKELY (!o)) {
5699 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (klass));
5700 return o;
5703 if (G_UNLIKELY (m_class_has_finalize (klass)))
5704 mono_object_register_finalizer (o);
5706 if (G_UNLIKELY (m_class_has_weak_fields (klass)))
5707 mono_gc_register_obj_with_weak_fields (o);
5709 return o;
5713 * object_new_handle_tail:
5715 * This function centralizes post-processing of objects upon creation.
5716 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields.
5718 static MonoObjectHandle
5719 object_new_handle_common_tail (MonoObjectHandle o, MonoClass *klass, MonoError *error)
5721 error_init (error);
5723 if (G_UNLIKELY (MONO_HANDLE_IS_NULL (o))) {
5724 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (klass));
5725 return o;
5728 if (G_UNLIKELY (m_class_has_finalize (klass)))
5729 mono_object_register_finalizer_handle (o);
5731 if (G_UNLIKELY (m_class_has_weak_fields (klass)))
5732 mono_gc_register_object_with_weak_fields (o);
5734 return o;
5738 * mono_object_new:
5739 * \param klass the class of the object that we want to create
5740 * \returns a newly created object whose definition is
5741 * looked up using \p klass. This will not invoke any constructors,
5742 * so the consumer of this routine has to invoke any constructors on
5743 * its own to initialize the object.
5745 * It returns NULL on failure.
5747 MonoObject *
5748 mono_object_new (MonoDomain *domain, MonoClass *klass)
5750 MonoObject * result;
5751 MONO_ENTER_GC_UNSAFE;
5752 ERROR_DECL (error);
5753 result = mono_object_new_checked (domain, klass, error);
5754 mono_error_cleanup (error);
5755 MONO_EXIT_GC_UNSAFE;
5756 return result;
5759 MonoObject *
5760 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5762 MONO_REQ_GC_UNSAFE_MODE;
5764 ERROR_DECL (error);
5766 MonoObject * result = mono_object_new_checked (domain, klass, error);
5768 mono_error_set_pending_exception (error);
5769 return result;
5773 * mono_object_new_checked:
5774 * \param klass the class of the object that we want to create
5775 * \param error set on error
5776 * \returns a newly created object whose definition is
5777 * looked up using \p klass. This will not invoke any constructors,
5778 * so the consumer of this routine has to invoke any constructors on
5779 * its own to initialize the object.
5781 * It returns NULL on failure and sets \p error.
5783 MonoObject *
5784 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5786 MONO_REQ_GC_UNSAFE_MODE;
5788 MonoVTable *vtable;
5790 vtable = mono_class_vtable_checked (domain, klass, error);
5791 if (!is_ok (error))
5792 return NULL;
5794 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5795 return o;
5799 * mono_object_new_handle:
5800 * \param klass the class of the object that we want to create
5801 * \param error set on error
5802 * \returns a newly created object whose definition is
5803 * looked up using \p klass. This will not invoke any constructors,
5804 * so the consumer of this routine has to invoke any constructors on
5805 * its own to initialize the object.
5807 * It returns NULL on failure and sets \p error.
5809 MonoObjectHandle
5810 mono_object_new_handle (MonoDomain *domain, MonoClass *klass, MonoError *error)
5812 MONO_REQ_GC_UNSAFE_MODE;
5814 MonoVTable* const vtable = mono_class_vtable_checked (domain, klass, error);
5816 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5818 return mono_object_new_by_vtable (vtable, error);
5822 * mono_object_new_pinned:
5824 * Same as mono_object_new, but the returned object will be pinned.
5825 * For SGEN, these objects will only be freed at appdomain unload.
5827 MonoObjectHandle
5828 mono_object_new_pinned_handle (MonoDomain *domain, MonoClass *klass, MonoError *error)
5830 MONO_REQ_GC_UNSAFE_MODE;
5832 MonoVTable* const vtable = mono_class_vtable_checked (domain, klass, error);
5833 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5835 g_assert (vtable->klass == klass);
5837 int const size = mono_class_instance_size (klass);
5839 MonoObjectHandle o = mono_gc_alloc_handle_pinned_obj (vtable, size);
5841 return object_new_handle_common_tail (o, klass, error);
5844 MonoObject *
5845 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5847 MONO_REQ_GC_UNSAFE_MODE;
5849 MonoVTable *vtable;
5851 vtable = mono_class_vtable_checked (domain, klass, error);
5852 return_val_if_nok (error, NULL);
5854 MonoObject *o = mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5856 return object_new_common_tail (o, klass, error);
5860 * mono_object_new_specific:
5861 * \param vtable the vtable of the object that we want to create
5862 * \returns A newly created object with class and domain specified
5863 * by \p vtable
5865 MonoObject *
5866 mono_object_new_specific (MonoVTable *vtable)
5868 ERROR_DECL (error);
5869 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5870 mono_error_cleanup (error);
5872 return o;
5875 MonoObject *
5876 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5878 MONO_REQ_GC_UNSAFE_MODE;
5880 MonoObject *o;
5882 error_init (error);
5884 /* check for is_com_object for COM Interop */
5885 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5887 gpointer pa [1];
5888 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5890 if (im == NULL) {
5891 MonoClass *klass = mono_class_get_activation_services_class ();
5893 if (!m_class_is_inited (klass))
5894 mono_class_init_internal (klass);
5896 im = mono_class_get_method_from_name_checked (klass, "CreateProxyForType", 1, 0, error);
5897 return_val_if_nok (error, NULL);
5898 if (!im) {
5899 mono_error_set_not_supported (error, "Linked away.");
5900 return NULL;
5902 vtable->domain->create_proxy_for_type_method = im;
5905 pa [0] = mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable->klass), error);
5906 if (!is_ok (error))
5907 return NULL;
5909 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5910 if (!is_ok (error))
5911 return NULL;
5913 if (o != NULL)
5914 return o;
5917 return mono_object_new_alloc_specific_checked (vtable, error);
5920 static MonoObjectHandle
5921 mono_object_new_by_vtable (MonoVTable *vtable, MonoError *error)
5923 // This function handles remoting and COM.
5924 // mono_object_new_alloc_by_vtable does not.
5926 MONO_REQ_GC_UNSAFE_MODE;
5928 MonoObjectHandle o = MONO_HANDLE_NEW (MonoObject, NULL);
5930 error_init (error);
5932 /* check for is_com_object for COM Interop */
5933 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5935 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5937 if (im == NULL) {
5938 MonoClass *klass = mono_class_get_activation_services_class ();
5940 if (!m_class_is_inited (klass))
5941 mono_class_init_internal (klass);
5943 im = mono_class_get_method_from_name_checked (klass, "CreateProxyForType", 1, 0, error);
5944 return_val_if_nok (error, mono_new_null ());
5945 if (!im) {
5946 mono_error_set_not_supported (error, "Linked away.");
5947 return MONO_HANDLE_NEW (MonoObject, NULL);
5949 vtable->domain->create_proxy_for_type_method = im;
5952 // FIXMEcoop
5953 gpointer pa[ ] = { mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable->klass), error) };
5954 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5956 // FIXMEcoop
5957 o = MONO_HANDLE_NEW (MonoObject, mono_runtime_invoke_checked (im, NULL, pa, error));
5958 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5960 if (!MONO_HANDLE_IS_NULL (o))
5961 return o;
5964 return mono_object_new_alloc_by_vtable (vtable, error);
5967 MonoObject *
5968 ves_icall_object_new_specific (MonoVTable *vtable)
5970 ERROR_DECL (error);
5971 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5972 mono_error_set_pending_exception (error);
5974 return o;
5978 * mono_object_new_alloc_specific:
5979 * \param vtable virtual table for the object.
5980 * This function allocates a new \c MonoObject with the type derived
5981 * from the \p vtable information. If the class of this object has a
5982 * finalizer, then the object will be tracked for finalization.
5984 * This method might raise an exception on errors. Use the
5985 * \c mono_object_new_fast_checked method if you want to manually raise
5986 * the exception.
5988 * \returns the allocated object.
5990 MonoObject *
5991 mono_object_new_alloc_specific (MonoVTable *vtable)
5993 ERROR_DECL (error);
5994 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, error);
5995 mono_error_cleanup (error);
5997 return o;
6001 * mono_object_new_alloc_specific_checked:
6002 * \param vtable virtual table for the object.
6003 * \param error holds the error return value.
6005 * This function allocates a new \c MonoObject with the type derived
6006 * from the \p vtable information. If the class of this object has a
6007 * finalizer, then the object will be tracked for finalization.
6009 * If there is not enough memory, the \p error parameter will be set
6010 * and will contain a user-visible message with the amount of bytes
6011 * that were requested.
6013 * \returns the allocated object, or NULL if there is not enough memory
6015 MonoObject *
6016 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
6018 MONO_REQ_GC_UNSAFE_MODE;
6020 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
6022 return object_new_common_tail (o, vtable->klass, error);
6025 MonoObjectHandle
6026 mono_object_new_alloc_by_vtable (MonoVTable *vtable, MonoError *error)
6028 MONO_REQ_GC_UNSAFE_MODE;
6030 MonoClass* const klass = vtable->klass;
6031 int const size = m_class_get_instance_size (klass);
6033 MonoObjectHandle o = mono_gc_alloc_handle_obj (vtable, size);
6035 return object_new_handle_common_tail (o, klass, error);
6039 * mono_object_new_fast:
6040 * \param vtable virtual table for the object.
6042 * This function allocates a new \c MonoObject with the type derived
6043 * from the \p vtable information. The returned object is not tracked
6044 * for finalization. If your object implements a finalizer, you should
6045 * use \c mono_object_new_alloc_specific instead.
6047 * This method might raise an exception on errors. Use the
6048 * \c mono_object_new_fast_checked method if you want to manually raise
6049 * the exception.
6051 * \returns the allocated object.
6053 MonoObject*
6054 mono_object_new_fast (MonoVTable *vtable)
6056 ERROR_DECL (error);
6058 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
6060 // This deliberately skips object_new_common_tail.
6062 if (G_UNLIKELY (!o))
6063 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
6065 mono_error_cleanup (error);
6067 return o;
6070 MonoObject*
6071 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
6073 MONO_REQ_GC_UNSAFE_MODE;
6075 int size;
6077 size = m_class_get_instance_size (vtable->klass);
6079 #if MONO_CROSS_COMPILE
6080 /* In cross compile mode, we should only allocate thread objects */
6081 /* The instance size refers to the target arch, this should be safe enough */
6082 size *= 2;
6083 #endif
6085 MonoObject *o = mono_gc_alloc_mature (vtable, size);
6087 return object_new_common_tail (o, vtable->klass, error);
6090 MonoObjectHandle
6091 mono_object_new_handle_mature (MonoVTable *vtable, MonoError *error)
6093 MONO_REQ_GC_UNSAFE_MODE;
6095 MonoClass* const klass = vtable->klass;
6096 int const size = m_class_get_instance_size (klass);
6098 MonoObjectHandle o = mono_gc_alloc_handle_mature (vtable, size);
6100 return object_new_handle_common_tail (o, klass, error);
6104 * mono_object_new_from_token:
6105 * \param image Context where the type_token is hosted
6106 * \param token a token of the type that we want to create
6107 * \returns A newly created object whose definition is
6108 * looked up using \p token in the \p image image
6110 MonoObject *
6111 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
6113 MONO_REQ_GC_UNSAFE_MODE;
6115 HANDLE_FUNCTION_ENTER ();
6117 ERROR_DECL (error);
6118 MonoClass *klass;
6120 klass = mono_class_get_checked (image, token, error);
6121 mono_error_assert_ok (error);
6123 MonoObjectHandle result = mono_object_new_handle (domain, klass, error);
6125 mono_error_cleanup (error);
6127 HANDLE_FUNCTION_RETURN_OBJ (result);
6131 * mono_object_clone:
6132 * \param obj the object to clone
6133 * \returns A newly created object who is a shallow copy of \p obj
6135 MonoObject *
6136 mono_object_clone (MonoObject *obj)
6138 ERROR_DECL (error);
6139 MonoObject *o = mono_object_clone_checked (obj, error);
6140 mono_error_cleanup (error);
6142 return o;
6145 MonoObject *
6146 mono_object_clone_checked (MonoObject *obj_raw, MonoError *error)
6148 MONO_REQ_GC_UNSAFE_MODE;
6149 HANDLE_FUNCTION_ENTER ();
6150 MONO_HANDLE_DCL (MonoObject, obj);
6151 HANDLE_FUNCTION_RETURN_OBJ (mono_object_clone_handle (obj, error));
6154 MonoObjectHandle
6155 mono_object_clone_handle (MonoObjectHandle obj, MonoError *error)
6157 MONO_REQ_GC_UNSAFE_MODE;
6159 MonoVTable* const vtable = MONO_HANDLE_GETVAL (obj, vtable);
6160 MonoClass* const klass = vtable->klass;
6162 if (m_class_get_rank (klass))
6163 return MONO_HANDLE_CAST (MonoObject, mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (obj),
6164 MONO_HANDLE_CAST (MonoArray, obj), error));
6166 int const size = m_class_get_instance_size (klass);
6168 MonoObjectHandle o = mono_gc_alloc_handle_obj (vtable, size);
6170 if (G_LIKELY (!MONO_HANDLE_IS_NULL (o))) {
6171 /* If the object doesn't contain references this will do a simple memmove. */
6172 mono_gc_wbarrier_object_copy_handle (o, obj);
6175 return object_new_handle_common_tail (o, klass, error);
6179 * mono_array_full_copy:
6180 * \param src source array to copy
6181 * \param dest destination array
6182 * Copies the content of one array to another with exactly the same type and size.
6184 void
6185 mono_array_full_copy (MonoArray *src, MonoArray *dest)
6187 MONO_REQ_GC_UNSAFE_MODE;
6189 uintptr_t size;
6190 MonoClass *klass = mono_object_class (&src->obj);
6192 g_assert (klass == mono_object_class (&dest->obj));
6194 size = mono_array_length_internal (src);
6195 g_assert (size == mono_array_length_internal (dest));
6196 size *= mono_array_element_size (klass);
6198 array_full_copy_unchecked_size (src, dest, klass, size);
6201 static void
6202 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
6204 if (mono_gc_is_moving ()) {
6205 MonoClass *element_class = m_class_get_element_class (klass);
6206 if (m_class_is_valuetype (element_class)) {
6207 if (m_class_has_references (element_class))
6208 mono_value_copy_array_internal (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length_internal (src));
6209 else
6210 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
6211 } else {
6212 mono_array_memcpy_refs_internal
6213 (dest, 0, src, 0, mono_array_length_internal (src));
6215 } else {
6216 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
6221 * mono_array_clone_in_domain:
6222 * \param domain the domain in which the array will be cloned into
6223 * \param array the array to clone
6224 * \param error set on error
6225 * This routine returns a copy of the array that is hosted on the
6226 * specified \c MonoDomain. On failure returns NULL and sets \p error.
6228 MonoArrayHandle
6229 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
6231 MONO_REQ_GC_UNSAFE_MODE;
6233 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
6234 uintptr_t size = 0;
6235 MonoClass *klass = mono_handle_class (array_handle);
6237 error_init (error);
6239 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
6240 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
6242 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
6243 MonoArrayHandle o;
6244 if (array_bounds == NULL) {
6245 size = mono_array_handle_length (array_handle);
6246 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
6247 goto_if_nok (error, leave);
6248 size *= mono_array_element_size (klass);
6249 } else {
6250 guint8 klass_rank = m_class_get_rank (klass);
6251 uintptr_t *sizes = g_newa (uintptr_t, klass_rank);
6252 intptr_t *lower_bounds = g_newa (intptr_t, klass_rank);
6253 size = mono_array_element_size (klass);
6254 for (int i = 0; i < klass_rank; ++i) {
6255 sizes [i] = array_bounds [i].length;
6256 size *= array_bounds [i].length;
6257 lower_bounds [i] = array_bounds [i].lower_bound;
6259 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
6260 goto_if_nok (error, leave);
6263 uint32_t dst_handle;
6264 dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
6265 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
6266 mono_gchandle_free_internal (dst_handle);
6268 MONO_HANDLE_ASSIGN (result, o);
6270 leave:
6271 mono_gchandle_free_internal (src_handle);
6272 return result;
6276 * mono_array_clone:
6277 * \param array the array to clone
6278 * \returns A newly created array who is a shallow copy of \p array
6280 MonoArray*
6281 mono_array_clone (MonoArray *array)
6283 MONO_REQ_GC_UNSAFE_MODE;
6285 ERROR_DECL (error);
6286 MonoArray *result = mono_array_clone_checked (array, error);
6287 mono_error_cleanup (error);
6288 return result;
6292 * mono_array_clone_checked:
6293 * \param array the array to clone
6294 * \param error set on error
6295 * \returns A newly created array who is a shallow copy of \p array. On
6296 * failure returns NULL and sets \p error.
6298 MonoArray*
6299 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
6301 MONO_REQ_GC_UNSAFE_MODE;
6302 HANDLE_FUNCTION_ENTER ();
6303 /* FIXME: callers of mono_array_clone_checked should use handles */
6304 error_init (error);
6305 MONO_HANDLE_DCL (MonoArray, array);
6306 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
6307 HANDLE_FUNCTION_RETURN_OBJ (result);
6310 /* helper macros to check for overflow when calculating the size of arrays */
6311 #ifdef MONO_BIG_ARRAYS
6312 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
6313 #define MYGUINT_MAX MYGUINT64_MAX
6314 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6315 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
6316 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6317 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
6318 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
6319 #else
6320 #define MYGUINT32_MAX 4294967295U
6321 #define MYGUINT_MAX MYGUINT32_MAX
6322 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6323 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
6324 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6325 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
6326 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
6327 #endif
6329 gboolean
6330 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
6332 MONO_REQ_GC_NEUTRAL_MODE;
6334 uintptr_t byte_len;
6336 byte_len = mono_array_element_size (klass);
6337 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
6338 return FALSE;
6339 byte_len *= len;
6340 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
6341 return FALSE;
6342 byte_len += MONO_SIZEOF_MONO_ARRAY;
6344 *res = byte_len;
6346 return TRUE;
6350 * mono_array_new_full:
6351 * \param domain domain where the object is created
6352 * \param array_class array class
6353 * \param lengths lengths for each dimension in the array
6354 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
6355 * This routine creates a new array object with the given dimensions,
6356 * lower bounds and type.
6358 MonoArray*
6359 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
6361 ERROR_DECL (error);
6362 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, error);
6363 mono_error_cleanup (error);
6365 return array;
6368 MonoArray*
6369 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
6371 MONO_REQ_GC_UNSAFE_MODE;
6373 uintptr_t byte_len = 0, len, bounds_size;
6374 MonoObject *o;
6375 MonoArray *array;
6376 MonoArrayBounds *bounds;
6377 MonoVTable *vtable;
6378 int i;
6380 error_init (error);
6382 if (!m_class_is_inited (array_class))
6383 mono_class_init_internal (array_class);
6385 len = 1;
6387 guint8 array_class_rank = m_class_get_rank (array_class);
6388 /* A single dimensional array with a 0 lower bound is the same as an szarray */
6389 if (array_class_rank == 1 && ((m_class_get_byval_arg (array_class)->type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
6390 len = lengths [0];
6391 if (len > MONO_ARRAY_MAX_INDEX) {
6392 mono_error_set_generic_error (error, "System", "OverflowException", "");
6393 return NULL;
6395 bounds_size = 0;
6396 } else {
6397 bounds_size = sizeof (MonoArrayBounds) * array_class_rank;
6399 for (i = 0; i < array_class_rank; ++i) {
6400 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
6401 mono_error_set_generic_error (error, "System", "OverflowException", "");
6402 return NULL;
6404 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
6405 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6406 return NULL;
6408 len *= lengths [i];
6412 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
6413 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6414 return NULL;
6417 if (bounds_size) {
6418 /* align */
6419 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
6420 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6421 return NULL;
6423 byte_len = (byte_len + 3) & ~3;
6424 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
6425 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6426 return NULL;
6428 byte_len += bounds_size;
6431 * Following three lines almost taken from mono_object_new ():
6432 * they need to be kept in sync.
6434 vtable = mono_class_vtable_checked (domain, array_class, error);
6435 return_val_if_nok (error, NULL);
6437 if (bounds_size)
6438 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
6439 else
6440 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
6442 if (G_UNLIKELY (!o)) {
6443 mono_error_set_out_of_memory (error, "Could not allocate %" G_GSIZE_FORMAT "d bytes", (gsize) byte_len);
6444 return NULL;
6447 array = (MonoArray*)o;
6449 bounds = array->bounds;
6451 if (bounds_size) {
6452 for (i = 0; i < array_class_rank; ++i) {
6453 bounds [i].length = lengths [i];
6454 if (lower_bounds)
6455 bounds [i].lower_bound = lower_bounds [i];
6459 return array;
6463 * mono_array_new:
6464 * \param domain domain where the object is created
6465 * \param eclass element class
6466 * \param n number of array elements
6467 * This routine creates a new szarray with \p n elements of type \p eclass.
6469 MonoArray *
6470 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6472 MonoArray *result;
6473 MONO_ENTER_GC_UNSAFE;
6475 ERROR_DECL (error);
6476 result = mono_array_new_checked (domain, eclass, n, error);
6477 mono_error_cleanup (error);
6478 MONO_EXIT_GC_UNSAFE;
6479 return result;
6483 * mono_array_new_checked:
6484 * \param domain domain where the object is created
6485 * \param eclass element class
6486 * \param n number of array elements
6487 * \param error set on error
6488 * This routine creates a new szarray with \p n elements of type \p eclass.
6489 * On failure returns NULL and sets \p error.
6491 MonoArray *
6492 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
6494 MonoClass *ac;
6496 error_init (error);
6498 ac = mono_class_create_array (eclass, 1);
6499 g_assert (ac);
6501 MonoVTable *vtable = mono_class_vtable_checked (domain, ac, error);
6502 return_val_if_nok (error, NULL);
6504 return mono_array_new_specific_checked (vtable, n, error);
6507 MonoArray*
6508 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6510 ERROR_DECL (error);
6511 MonoArray *arr = mono_array_new_checked (domain, eclass, n, error);
6512 mono_error_set_pending_exception (error);
6514 return arr;
6518 * mono_array_new_specific:
6519 * \param vtable a vtable in the appropriate domain for an initialized class
6520 * \param n number of array elements
6521 * This routine is a fast alternative to \c mono_array_new for code which
6522 * can be sure about the domain it operates in.
6524 MonoArray *
6525 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
6527 ERROR_DECL (error);
6528 MonoArray *arr = mono_array_new_specific_checked (vtable, n, error);
6529 mono_error_cleanup (error);
6531 return arr;
6534 MonoArray*
6535 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
6537 MONO_REQ_GC_UNSAFE_MODE;
6539 MonoObject *o;
6540 uintptr_t byte_len;
6542 error_init (error);
6544 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6545 mono_error_set_generic_error (error, "System", "OverflowException", "");
6546 return NULL;
6549 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6550 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6551 return NULL;
6553 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6555 if (G_UNLIKELY (!o)) {
6556 mono_error_set_out_of_memory (error, "Could not allocate %" G_GSIZE_FORMAT "d bytes", (gsize) byte_len);
6557 return NULL;
6560 return (MonoArray*)o;
6564 MonoArrayHandle
6565 mono_array_new_specific_handle (MonoVTable *vtable, uintptr_t n, MonoError *error)
6567 // FIXMEcoop invert relationship with mono_array_new_specific_checked
6568 return MONO_HANDLE_NEW (MonoArray, mono_array_new_specific_checked (vtable, n, error));
6571 MonoArray*
6572 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6574 ERROR_DECL (error);
6575 MonoArray *arr = mono_array_new_specific_checked (vtable, n, error);
6576 mono_error_set_pending_exception (error);
6578 return arr;
6582 * mono_string_empty_wrapper:
6584 * Returns: The same empty string instance as the managed string.Empty
6586 MonoString*
6587 mono_string_empty_wrapper (void)
6589 MonoDomain *domain = mono_domain_get ();
6590 return mono_string_empty_internal (domain);
6593 MonoString*
6594 mono_string_empty_internal (MonoDomain *domain)
6596 g_assert (domain);
6597 g_assert (domain->empty_string);
6598 return domain->empty_string;
6602 * mono_string_empty:
6604 * Returns: The same empty string instance as the managed string.Empty
6606 MonoString*
6607 mono_string_empty (MonoDomain *domain)
6609 MONO_EXTERNAL_ONLY (MonoString*, mono_string_empty_internal (domain));
6612 MonoStringHandle
6613 mono_string_empty_handle (MonoDomain *domain)
6615 return MONO_HANDLE_NEW (MonoString, mono_string_empty_internal (domain));
6619 * mono_string_new_utf16:
6620 * \param text a pointer to an utf16 string
6621 * \param len the length of the string
6622 * \returns A newly created string object which contains \p text.
6624 MonoString *
6625 mono_string_new_utf16 (MonoDomain *domain, const mono_unichar2 *text, gint32 len)
6627 MonoString *res = NULL;
6628 MONO_ENTER_GC_UNSAFE;
6629 ERROR_DECL (error);
6630 res = mono_string_new_utf16_checked (domain, text, len, error);
6631 mono_error_cleanup (error);
6632 MONO_EXIT_GC_UNSAFE;
6633 return res;
6637 * mono_string_new_utf16_checked:
6638 * \param text a pointer to an utf16 string
6639 * \param len the length of the string
6640 * \param error written on error.
6641 * \returns A newly created string object which contains \p text.
6642 * On error, returns NULL and sets \p error.
6644 MonoString *
6645 mono_string_new_utf16_checked (MonoDomain *domain, const gunichar2 *text, gint32 len, MonoError *error)
6647 MONO_REQ_GC_UNSAFE_MODE;
6649 MonoString *s;
6651 error_init (error);
6653 s = mono_string_new_size_checked (domain, len, error);
6654 if (s != NULL)
6655 memcpy (mono_string_chars_internal (s), text, len * 2);
6657 return s;
6661 * mono_string_new_utf16_handle:
6662 * \param text a pointer to an utf16 string
6663 * \param len the length of the string
6664 * \param error written on error.
6665 * \returns A newly created string object which contains \p text.
6666 * On error, returns NULL and sets \p error.
6668 MonoStringHandle
6669 mono_string_new_utf16_handle (MonoDomain *domain, const gunichar2 *text, gint32 len, MonoError *error)
6671 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6675 * mono_string_new_utf32_checked:
6676 * \param text a pointer to an utf32 string
6677 * \param len the length of the string
6678 * \param error set on failure.
6679 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6681 static MonoString *
6682 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6684 MONO_REQ_GC_UNSAFE_MODE;
6686 MonoString *s;
6687 mono_unichar2 *utf16_output = NULL;
6689 error_init (error);
6690 utf16_output = g_ucs4_to_utf16 (text, len, NULL, NULL, NULL);
6692 gint32 utf16_len = g_utf16_len (utf16_output);
6694 s = mono_string_new_size_checked (domain, utf16_len, error);
6695 goto_if_nok (error, exit);
6697 memcpy (mono_string_chars_internal (s), utf16_output, utf16_len * 2);
6699 exit:
6700 g_free (utf16_output);
6702 return s;
6706 * mono_string_new_utf32:
6707 * \param text a pointer to a UTF-32 string
6708 * \param len the length of the string
6709 * \returns A newly created string object which contains \p text.
6711 MonoString *
6712 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6714 ERROR_DECL (error);
6715 MonoString *result = mono_string_new_utf32_checked (domain, text, len, error);
6716 mono_error_cleanup (error);
6717 return result;
6721 * mono_string_new_size:
6722 * \param text a pointer to a UTF-16 string
6723 * \param len the length of the string
6724 * \returns A newly created string object of \p len
6726 MonoString *
6727 mono_string_new_size (MonoDomain *domain, gint32 len)
6729 MonoString *str;
6730 MONO_ENTER_GC_UNSAFE;
6731 ERROR_DECL (error);
6732 str = mono_string_new_size_checked (domain, len, error);
6733 mono_error_cleanup (error);
6734 MONO_EXIT_GC_UNSAFE;
6735 return str;
6738 MonoStringHandle
6739 mono_string_new_size_handle (MonoDomain *domain, gint32 len, MonoError *error)
6741 MONO_REQ_GC_UNSAFE_MODE;
6743 MonoStringHandle s;
6744 MonoVTable *vtable;
6745 size_t size;
6747 error_init (error);
6749 /* check for overflow */
6750 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6751 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6752 return NULL_HANDLE_STRING;
6755 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6756 g_assert (size > 0);
6758 vtable = mono_class_vtable_checked (domain, mono_defaults.string_class, error);
6759 return_val_if_nok (error, NULL_HANDLE_STRING);
6761 s = mono_gc_alloc_handle_string (vtable, size, len);
6763 if (G_UNLIKELY (MONO_HANDLE_IS_NULL (s)))
6764 mono_error_set_out_of_memory (error, "Could not allocate %" G_GSIZE_FORMAT " bytes", size);
6766 return s;
6769 MonoString *
6770 mono_string_new_size_checked (MonoDomain *domain, gint32 length, MonoError *error)
6772 HANDLE_FUNCTION_ENTER ();
6773 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_size_handle (domain, length, error));
6777 * mono_string_new_len:
6778 * \param text a pointer to an utf8 string
6779 * \param length number of bytes in \p text to consider
6780 * \returns A newly created string object which contains \p text.
6782 MonoString*
6783 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6785 HANDLE_FUNCTION_ENTER ();
6786 ERROR_DECL (error);
6787 MonoStringHandle result;
6789 MONO_ENTER_GC_UNSAFE;
6790 result = mono_string_new_utf8_len (domain, text, length, error);
6791 MONO_EXIT_GC_UNSAFE;
6793 mono_error_cleanup (error);
6794 HANDLE_FUNCTION_RETURN_OBJ (result);
6798 * mono_string_new_utf8_len:
6799 * \param text a pointer to an utf8 string
6800 * \param length number of bytes in \p text to consider
6801 * \param error set on error
6802 * \returns A newly created string object which contains \p text. On
6803 * failure returns NULL and sets \p error.
6805 MonoStringHandle
6806 mono_string_new_utf8_len (MonoDomain *domain, const char *text, guint length, MonoError *error)
6808 MONO_REQ_GC_UNSAFE_MODE;
6810 error_init (error);
6812 GError *eg_error = NULL;
6813 MonoStringHandle o = NULL_HANDLE_STRING;
6814 gunichar2 *ut = NULL;
6815 glong items_written;
6817 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6819 if (eg_error) {
6820 o = NULL_HANDLE_STRING;
6821 // Like mono_ldstr_utf8:
6822 mono_error_set_argument (error, "string", eg_error->message);
6823 // FIXME? See mono_string_new_checked.
6824 //mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6825 g_error_free (eg_error);
6826 } else {
6827 o = mono_string_new_utf16_handle (domain, ut, items_written, error);
6830 g_free (ut);
6832 return o;
6835 MonoString*
6836 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6838 HANDLE_FUNCTION_ENTER ();
6839 error_init (error);
6840 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_utf8_len (domain, text, length, error));
6843 static
6844 MonoString*
6845 mono_string_new_internal (MonoDomain *domain, const char *text)
6847 ERROR_DECL (error);
6848 MonoString *res = NULL;
6849 res = mono_string_new_checked (domain, text, error);
6850 if (!is_ok (error)) {
6851 /* Mono API compatability: assert on Out of Memory errors,
6852 * return NULL otherwise (most likely an invalid UTF-8 byte
6853 * sequence). */
6854 if (mono_error_get_error_code (error) == MONO_ERROR_OUT_OF_MEMORY)
6855 mono_error_assert_ok (error);
6856 else
6857 mono_error_cleanup (error);
6859 return res;
6863 * mono_string_new:
6864 * \param text a pointer to a UTF-8 string
6865 * \deprecated Use \c mono_string_new_checked in new code.
6866 * This function asserts if it cannot allocate a new string.
6867 * \returns A newly created string object which contains \p text.
6869 MonoString*
6870 mono_string_new (MonoDomain *domain, const char *text)
6872 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoString*, mono_string_new_internal (domain, text));
6876 * mono_string_new_checked:
6877 * \param text a pointer to an utf8 string
6878 * \param merror set on error
6879 * \returns A newly created string object which contains \p text.
6880 * On error returns NULL and sets \p merror.
6882 MonoString*
6883 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6885 MONO_REQ_GC_UNSAFE_MODE;
6887 GError *eg_error = NULL;
6888 MonoString *o = NULL;
6889 gunichar2 *ut;
6890 glong items_written;
6891 int len;
6893 error_init (error);
6895 len = strlen (text);
6897 ut = g_utf8_to_utf16 (text, len, NULL, &items_written, &eg_error);
6899 if (!eg_error)
6900 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6901 else {
6902 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6903 g_error_free (eg_error);
6906 g_free (ut);
6908 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6909 #if 0
6910 gunichar2 *str;
6911 const gchar *end;
6912 int len;
6913 MonoString *o = NULL;
6915 if (!g_utf8_validate (text, -1, &end)) {
6916 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6917 goto leave;
6920 len = g_utf8_strlen (text, -1);
6921 o = mono_string_new_size_checked (domain, len, error);
6922 if (!o)
6923 goto leave;
6924 str = mono_string_chars_internal (o);
6926 while (text < end) {
6927 *str++ = g_utf8_get_char (text);
6928 text = g_utf8_next_char (text);
6931 leave:
6932 #endif
6933 return o;
6937 * mono_string_new_wtf8_len_checked:
6938 * \param text a pointer to an wtf8 string (see https://simonsapin.github.io/wtf-8/)
6939 * \param length number of bytes in \p text to consider
6940 * \param merror set on error
6941 * \returns A newly created string object which contains \p text.
6942 * On error returns NULL and sets \p merror.
6944 MonoString*
6945 mono_string_new_wtf8_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6947 MONO_REQ_GC_UNSAFE_MODE;
6949 error_init (error);
6951 GError *eg_error = NULL;
6952 MonoString *o = NULL;
6953 gunichar2 *ut = NULL;
6954 glong items_written;
6956 ut = eg_wtf8_to_utf16 (text, length, NULL, &items_written, &eg_error);
6958 if (!eg_error)
6959 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6960 else
6961 g_error_free (eg_error);
6963 g_free (ut);
6965 return o;
6968 MonoStringHandle
6969 mono_string_new_wrapper_internal_impl (const char *text, MonoError *error)
6971 return MONO_HANDLE_NEW (MonoString, mono_string_new_internal (mono_domain_get (), text));
6975 * mono_string_new_wrapper:
6976 * \param text pointer to UTF-8 characters.
6977 * Helper function to create a string object from \p text in the current domain.
6979 MonoString*
6980 mono_string_new_wrapper (const char *text)
6982 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoString*, mono_string_new_wrapper_internal (text));
6986 * mono_value_box:
6987 * \param class the class of the value
6988 * \param value a pointer to the unboxed data
6989 * \returns A newly created object which contains \p value.
6991 MonoObject *
6992 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6994 MonoObject *result;
6995 MONO_ENTER_GC_UNSAFE;
6996 ERROR_DECL (error);
6997 result = mono_value_box_checked (domain, klass, value, error);
6998 mono_error_cleanup (error);
6999 MONO_EXIT_GC_UNSAFE;
7000 return result;
7004 * mono_value_box_handle:
7005 * \param domain the domain of the new object
7006 * \param class the class of the value
7007 * \param value a pointer to the unboxed data
7008 * \param error set on error
7009 * \returns A newly created object which contains \p value. On failure
7010 * returns NULL and sets \p error.
7012 MonoObjectHandle
7013 mono_value_box_handle (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
7015 // FIXMEcoop gpointer value needs more attention
7016 MONO_REQ_GC_UNSAFE_MODE;
7017 MonoVTable *vtable;
7019 error_init (error);
7021 g_assert (m_class_is_valuetype (klass));
7022 g_assert (value != NULL);
7023 if (G_UNLIKELY (m_class_is_byreflike (klass))) {
7024 char *full_name = mono_type_get_full_name (klass);
7025 mono_error_set_execution_engine (error, "Cannot box IsByRefLike type %s", full_name);
7026 g_free (full_name);
7027 return NULL_HANDLE;
7029 if (mono_class_is_nullable (klass))
7030 return mono_nullable_box_handle (value, klass, error);
7032 vtable = mono_class_vtable_checked (domain, klass, error);
7033 return_val_if_nok (error, NULL_HANDLE);
7035 int size = mono_class_instance_size (klass);
7037 MonoObjectHandle res_handle = mono_object_new_alloc_by_vtable (vtable, error);
7038 return_val_if_nok (error, NULL_HANDLE);
7040 size -= MONO_ABI_SIZEOF (MonoObject);
7041 if (mono_gc_is_moving ()) {
7042 g_assert (size == mono_class_value_size (klass, NULL));
7043 MONO_ENTER_NO_SAFEPOINTS;
7044 gpointer data = mono_handle_get_data_unsafe (res_handle);
7045 mono_gc_wbarrier_value_copy_internal (data, value, 1, klass);
7046 MONO_EXIT_NO_SAFEPOINTS;
7047 } else {
7048 MONO_ENTER_NO_SAFEPOINTS;
7049 gpointer data = mono_handle_get_data_unsafe (res_handle);
7050 #if NO_UNALIGNED_ACCESS
7051 mono_gc_memmove_atomic (data, value, size);
7052 #else
7053 switch (size) {
7054 case 1:
7055 *(guint8*)data = *(guint8 *) value;
7056 break;
7057 case 2:
7058 *(guint16 *)(data) = *(guint16 *) value;
7059 break;
7060 case 4:
7061 *(guint32 *)(data) = *(guint32 *) value;
7062 break;
7063 case 8:
7064 *(guint64 *)(data) = *(guint64 *) value;
7065 break;
7066 default:
7067 mono_gc_memmove_atomic (data, value, size);
7069 #endif
7070 MONO_EXIT_NO_SAFEPOINTS;
7072 if (m_class_has_finalize (klass))
7073 mono_object_register_finalizer_handle (res_handle);
7075 return res_handle;
7079 * mono_value_box_checked:
7080 * \param domain the domain of the new object
7081 * \param class the class of the value
7082 * \param value a pointer to the unboxed data
7083 * \param error set on error
7084 * \returns A newly created object which contains \p value. On failure
7085 * returns NULL and sets \p error.
7087 MonoObject *
7088 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
7090 HANDLE_FUNCTION_ENTER ();
7091 HANDLE_FUNCTION_RETURN_OBJ (mono_value_box_handle (domain, klass, value, error));
7094 void
7095 mono_value_copy_internal (gpointer dest, gconstpointer src, MonoClass *klass)
7097 MONO_REQ_GC_UNSAFE_MODE;
7099 mono_gc_wbarrier_value_copy_internal (dest, src, 1, klass);
7103 * mono_value_copy:
7104 * \param dest destination pointer
7105 * \param src source pointer
7106 * \param klass a valuetype class
7107 * Copy a valuetype from \p src to \p dest. This function must be used
7108 * when \p klass contains reference fields.
7110 void
7111 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
7113 mono_value_copy_internal (dest, src, klass);
7116 void
7117 mono_value_copy_array_internal (MonoArray *dest, int dest_idx, gconstpointer src, int count)
7119 MONO_REQ_GC_UNSAFE_MODE;
7121 int size = mono_array_element_size (dest->obj.vtable->klass);
7122 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
7123 g_assert (size == mono_class_value_size (m_class_get_element_class (mono_object_class (dest)), NULL));
7124 // FIXME remove (gpointer) cast.
7125 mono_gc_wbarrier_value_copy_internal (d, (gpointer)src, count, m_class_get_element_class (mono_object_class (dest)));
7128 void
7129 mono_value_copy_array_handle (MonoArrayHandle dest, int dest_idx, gconstpointer src, int count)
7131 mono_value_copy_array_internal (MONO_HANDLE_RAW (dest), dest_idx, src, count);
7135 * mono_value_copy_array:
7136 * \param dest destination array
7137 * \param dest_idx index in the \p dest array
7138 * \param src source pointer
7139 * \param count number of items
7140 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
7141 * This function must be used when \p klass contains references fields.
7142 * Overlap is handled.
7144 void
7145 mono_value_copy_array (MonoArray *dest, int dest_idx, void* src, int count)
7147 MONO_EXTERNAL_ONLY_VOID (mono_value_copy_array_internal (dest, dest_idx, src, count));
7150 MonoVTable *
7151 mono_object_get_vtable_internal (MonoObject *obj)
7153 // This could be called during STW, so untag the vtable if needed.
7154 return mono_gc_get_vtable (obj);
7157 MonoVTable*
7158 mono_object_get_vtable (MonoObject *obj)
7160 MONO_EXTERNAL_ONLY (MonoVTable*, mono_object_get_vtable_internal (obj));
7163 MonoDomain*
7164 mono_object_get_domain_internal (MonoObject *obj)
7166 MONO_REQ_GC_UNSAFE_MODE;
7168 return mono_object_domain (obj);
7172 * mono_object_get_domain:
7173 * \param obj object to query
7174 * \returns the \c MonoDomain where the object is hosted
7176 MonoDomain*
7177 mono_object_get_domain (MonoObject *obj)
7179 MonoDomain* ret = NULL;
7180 MONO_ENTER_GC_UNSAFE;
7181 ret = mono_object_get_domain_internal (obj);
7182 MONO_EXIT_GC_UNSAFE;
7183 return ret;
7187 * mono_object_get_class:
7188 * \param obj object to query
7189 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
7190 * \returns the \c MonoClass of the object.
7192 MonoClass*
7193 mono_object_get_class (MonoObject *obj)
7195 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoClass*, mono_object_class (obj));
7198 guint
7199 mono_object_get_size_internal (MonoObject* o)
7201 MONO_REQ_GC_UNSAFE_MODE;
7203 MonoClass* klass = mono_object_class (o);
7204 if (klass == mono_defaults.string_class) {
7205 return MONO_SIZEOF_MONO_STRING + 2 * mono_string_length_internal ((MonoString*) o) + 2;
7206 } else if (o->vtable->rank) {
7207 MonoArray *array = (MonoArray*)o;
7208 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length_internal (array);
7209 if (array->bounds) {
7210 size += 3;
7211 size &= ~3;
7212 size += sizeof (MonoArrayBounds) * o->vtable->rank;
7214 return size;
7215 } else {
7216 return mono_class_instance_size (klass);
7221 * mono_object_get_size:
7222 * \param o object to query
7223 * \returns the size, in bytes, of \p o
7225 unsigned
7226 mono_object_get_size (MonoObject *o)
7228 MONO_EXTERNAL_ONLY (unsigned, mono_object_get_size_internal (o));
7232 * mono_object_unbox:
7233 * \param obj object to unbox
7234 * \returns a pointer to the start of the valuetype boxed in this
7235 * object.
7237 * This method will assert if the object passed is not a valuetype.
7239 void*
7240 mono_object_unbox (MonoObject *obj)
7242 MONO_EXTERNAL_ONLY_GC_UNSAFE (void*, mono_object_unbox_internal (obj));
7246 * mono_object_isinst:
7247 * \param obj an object
7248 * \param klass a pointer to a class
7249 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
7251 MonoObject *
7252 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
7254 HANDLE_FUNCTION_ENTER ();
7255 MonoObjectHandle result;
7256 MONO_ENTER_GC_UNSAFE;
7258 MONO_HANDLE_DCL (MonoObject, obj);
7259 ERROR_DECL (error);
7260 result = mono_object_handle_isinst (obj, klass, error);
7261 mono_error_cleanup (error);
7262 MONO_EXIT_GC_UNSAFE;
7263 HANDLE_FUNCTION_RETURN_OBJ (result);
7267 * mono_object_isinst_checked:
7268 * \param obj an object
7269 * \param klass a pointer to a class
7270 * \param error set on error
7271 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7272 * On failure returns NULL and sets \p error.
7274 MonoObject *
7275 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
7277 MONO_REQ_GC_UNSAFE_MODE;
7279 HANDLE_FUNCTION_ENTER ();
7280 error_init (error);
7281 MONO_HANDLE_DCL (MonoObject, obj);
7282 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
7283 HANDLE_FUNCTION_RETURN_OBJ (result);
7287 * mono_object_handle_isinst:
7288 * \param obj an object
7289 * \param klass a pointer to a class
7290 * \param error set on error
7291 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7292 * On failure returns NULL and sets \p error.
7294 MonoObjectHandle
7295 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7297 error_init (error);
7299 if (!m_class_is_inited (klass))
7300 mono_class_init_internal (klass);
7302 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
7303 return mono_object_handle_isinst_mbyref (obj, klass, error);
7306 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7308 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from_internal (klass, mono_handle_class (obj)))
7309 MONO_HANDLE_ASSIGN (result, obj);
7310 return result;
7314 * mono_object_isinst_mbyref:
7316 MonoObject *
7317 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
7319 MONO_REQ_GC_UNSAFE_MODE;
7321 HANDLE_FUNCTION_ENTER ();
7322 ERROR_DECL (error);
7323 MONO_HANDLE_DCL (MonoObject, obj);
7324 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, error);
7325 mono_error_cleanup (error); /* FIXME better API that doesn't swallow the error */
7326 HANDLE_FUNCTION_RETURN_OBJ (result);
7329 MonoObjectHandle
7330 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7332 gboolean success = FALSE;
7333 error_init (error);
7335 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7337 if (MONO_HANDLE_IS_NULL (obj))
7338 goto leave;
7340 success = mono_object_handle_isinst_mbyref_raw (obj, klass, error);
7341 if (success && is_ok (error))
7342 MONO_HANDLE_ASSIGN (result, obj);
7344 leave:
7345 return result;
7348 gboolean
7349 mono_object_handle_isinst_mbyref_raw (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7351 error_init (error);
7353 gboolean result = FALSE;
7355 if (MONO_HANDLE_IS_NULL (obj))
7356 goto leave;
7358 MonoVTable *vt;
7359 vt = MONO_HANDLE_GETVAL (obj, vtable);
7361 if (mono_class_is_interface (klass)) {
7362 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, m_class_get_interface_id (klass))) {
7363 result = TRUE;
7364 goto leave;
7367 /* casting an array one of the invariant interfaces that must act as such */
7368 if (m_class_is_array_special_interface (klass)) {
7369 if (mono_class_is_assignable_from_internal (klass, vt->klass)) {
7370 result = TRUE;
7371 goto leave;
7375 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
7376 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from_internal (klass, mono_handle_class (obj))) {
7377 result = TRUE;
7378 goto leave;
7380 } else {
7381 MonoClass *oklass = vt->klass;
7382 if (mono_class_is_transparent_proxy (oklass)){
7383 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
7384 oklass = remote_class->proxy_class;
7387 mono_class_setup_supertypes (klass);
7388 if (mono_class_has_parent_fast (oklass, klass)) {
7389 result = TRUE;
7390 goto leave;
7393 #ifndef DISABLE_REMOTING
7394 if (mono_class_is_transparent_proxy (vt->klass))
7396 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
7397 if (!custom_type_info)
7398 goto leave;
7399 MonoDomain *domain = mono_domain_get ();
7400 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
7401 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
7402 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
7403 MonoMethod *im = NULL;
7404 gpointer pa [2];
7406 im = mono_class_get_method_from_name_checked (rpklass, "CanCastTo", -1, 0, error);
7407 goto_if_nok (error, leave);
7408 if (!im) {
7409 mono_error_set_not_supported (error, "Linked away.");
7410 goto leave;
7412 im = mono_object_handle_get_virtual_method (rp, im, error);
7413 goto_if_nok (error, leave);
7414 g_assert (im);
7416 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
7417 goto_if_nok (error, leave);
7419 pa [0] = MONO_HANDLE_RAW (reftype);
7420 pa [1] = MONO_HANDLE_RAW (obj);
7421 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
7422 goto_if_nok (error, leave);
7424 if (*(MonoBoolean *) mono_object_unbox_internal (res)) {
7425 /* Update the vtable of the remote type, so it can safely cast to this new type */
7426 mono_upgrade_remote_class (domain, obj, klass, error);
7427 goto_if_nok (error, leave);
7428 result = TRUE;
7429 goto leave;
7432 #endif /* DISABLE_REMOTING */
7433 leave:
7434 return result;
7438 * mono_object_castclass_mbyref:
7439 * \param obj an object
7440 * \param klass a pointer to a class
7441 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
7443 MonoObject *
7444 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
7446 MONO_REQ_GC_UNSAFE_MODE;
7447 HANDLE_FUNCTION_ENTER ();
7448 ERROR_DECL (error);
7449 MONO_HANDLE_DCL (MonoObject, obj);
7450 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7451 if (MONO_HANDLE_IS_NULL (obj))
7452 goto leave;
7453 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, error));
7454 mono_error_cleanup (error);
7455 leave:
7456 HANDLE_FUNCTION_RETURN_OBJ (result);
7459 static MonoStringHandle
7460 mono_string_get_pinned (MonoStringHandle str, MonoError *error)
7462 MONO_REQ_GC_UNSAFE_MODE;
7464 error_init (error);
7466 /* We only need to make a pinned version of a string if this is a moving GC */
7467 if (!mono_gc_is_moving ())
7468 return str;
7470 const gsize length = mono_string_handle_length (str);
7471 const gsize size = MONO_SIZEOF_MONO_STRING + (length + 1) * sizeof (gunichar2);
7472 MonoStringHandle news = MONO_HANDLE_CAST (MonoString, mono_gc_alloc_handle_pinned_obj (MONO_HANDLE_GETVAL (str, object.vtable), size));
7473 if (!MONO_HANDLE_BOOL (news)) {
7474 mono_error_set_out_of_memory (error, "Could not allocate %" G_GSIZE_FORMAT " bytes", size);
7475 return news;
7478 MONO_ENTER_NO_SAFEPOINTS;
7480 memcpy (mono_string_chars_internal (MONO_HANDLE_RAW (news)),
7481 mono_string_chars_internal (MONO_HANDLE_RAW (str)),
7482 length * sizeof (gunichar2));
7484 MONO_EXIT_NO_SAFEPOINTS;
7486 MONO_HANDLE_SETVAL (news, length, int, length);
7487 return news;
7490 MonoStringHandle
7491 mono_string_is_interned_lookup (MonoStringHandle str, gboolean insert, MonoError *error)
7493 MONO_REQ_GC_UNSAFE_MODE;
7495 MonoGHashTable *ldstr_table = MONO_HANDLE_DOMAIN (str)->ldstr_table;
7496 ldstr_lock ();
7497 MonoString *res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, MONO_HANDLE_RAW (str));
7498 ldstr_unlock ();
7499 if (res)
7500 return MONO_HANDLE_NEW (MonoString, res);
7501 if (!insert)
7502 return NULL_HANDLE_STRING;
7504 // Allocate outside the lock.
7505 MonoStringHandle s = mono_string_get_pinned (str, error);
7506 if (!is_ok (error) || !MONO_HANDLE_BOOL (s))
7507 return NULL_HANDLE_STRING;
7509 // Try again inside lock.
7510 ldstr_lock ();
7511 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, MONO_HANDLE_RAW (str));
7512 if (res)
7513 MONO_HANDLE_ASSIGN_RAW (s, res);
7514 else
7515 mono_g_hash_table_insert_internal (ldstr_table, MONO_HANDLE_RAW (s), MONO_HANDLE_RAW (s));
7516 ldstr_unlock ();
7517 return s;
7521 * mono_string_is_interned:
7522 * \param o String to probe
7523 * \returns Whether the string has been interned.
7525 MonoString*
7526 mono_string_is_interned (MonoString *str_raw)
7528 ERROR_DECL (error);
7529 HANDLE_FUNCTION_ENTER ();
7530 MONO_HANDLE_DCL (MonoString, str);
7531 MONO_ENTER_GC_UNSAFE;
7532 str = mono_string_is_interned_internal (str, error);
7533 MONO_EXIT_GC_UNSAFE;
7534 mono_error_assert_ok (error);
7535 HANDLE_FUNCTION_RETURN_OBJ (str);
7539 * mono_string_intern:
7540 * \param o String to intern
7541 * Interns the string passed.
7542 * \returns The interned string.
7544 MonoString*
7545 mono_string_intern (MonoString *str_raw)
7547 ERROR_DECL (error);
7548 HANDLE_FUNCTION_ENTER ();
7549 MONO_HANDLE_DCL (MonoString, str);
7550 MONO_ENTER_GC_UNSAFE;
7551 str = mono_string_intern_checked (str, error);
7552 MONO_EXIT_GC_UNSAFE;
7553 HANDLE_FUNCTION_RETURN_OBJ (str);
7557 * mono_ldstr:
7558 * \param domain the domain where the string will be used.
7559 * \param image a metadata context
7560 * \param idx index into the user string table.
7561 * Implementation for the \c ldstr opcode.
7562 * \returns a loaded string from the \p image / \p idx combination.
7564 MonoString*
7565 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
7567 MonoString *result;
7568 MONO_ENTER_GC_UNSAFE;
7569 ERROR_DECL (error);
7570 result = mono_ldstr_checked (domain, image, idx, error);
7571 mono_error_cleanup (error);
7572 MONO_EXIT_GC_UNSAFE;
7573 return result;
7577 * mono_ldstr_checked:
7578 * \param domain the domain where the string will be used.
7579 * \param image a metadata context
7580 * \param idx index into the user string table.
7581 * \param error set on error.
7582 * Implementation for the \c ldstr opcode.
7583 * \returns A loaded string from the \p image / \p idx combination.
7584 * On failure returns NULL and sets \p error.
7586 MonoString*
7587 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
7589 MONO_REQ_GC_UNSAFE_MODE;
7590 error_init (error);
7592 HANDLE_FUNCTION_ENTER ();
7594 MonoStringHandle str = MONO_HANDLE_NEW (MonoString, NULL);
7596 if (image->dynamic) {
7597 MONO_HANDLE_ASSIGN_RAW (str, (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error));
7598 goto exit;
7600 if (!mono_verifier_verify_string_signature (image, idx, error))
7601 goto exit;
7602 mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), str, error);
7603 exit:
7604 HANDLE_FUNCTION_RETURN_OBJ (str);
7607 MonoStringHandle
7608 mono_ldstr_handle (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
7610 // FIXME invert mono_ldstr_handle and mono_ldstr_checked.
7611 return MONO_HANDLE_NEW (MonoString, mono_ldstr_checked (domain, image, idx, error));
7614 char*
7615 mono_string_from_blob (const char *str, MonoError *error)
7617 gsize len = mono_metadata_decode_blob_size (str, &str) >> 1;
7619 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7620 gunichar2 *src = (gunichar2*)str;
7621 gunichar2 *copy = g_new (gunichar2, len);
7622 int i;
7623 for (i = 0; i < len; ++i)
7624 copy [i] = GUINT16_FROM_LE (src [i]);
7626 char *res = mono_utf16_to_utf8 (copy, len, error);
7627 g_free (copy);
7628 return res;
7629 #else
7630 return mono_utf16_to_utf8 ((const gunichar2*)str, len, error);
7631 #endif
7634 * mono_ldstr_metadata_sig
7635 * \param domain the domain for the string
7636 * \param sig the signature of a metadata string
7637 * \param error set on error
7638 * \returns a \c MonoString for a string stored in the metadata. On
7639 * failure returns NULL and sets \p error.
7641 static void
7642 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoStringHandleOut string_handle, MonoError *error)
7644 MONO_REQ_GC_UNSAFE_MODE;
7646 error_init (error);
7648 MONO_HANDLE_ASSIGN_RAW (string_handle, NULL);
7650 const gsize len = mono_metadata_decode_blob_size (sig, &sig) / sizeof (gunichar2);
7652 // FIXMEcoop excess handle, use mono_string_new_utf16_checked and string_handle parameter
7654 MonoStringHandle o = mono_string_new_utf16_handle (domain, (gunichar2*)sig, len, error);
7655 return_if_nok (error);
7657 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7658 gunichar2 *p = mono_string_chars_internal (MONO_HANDLE_RAW (o));
7659 for (gsize i = 0; i < len; ++i)
7660 p [i] = GUINT16_FROM_LE (p [i]);
7661 #endif
7662 // FIXMEcoop excess handle in mono_string_intern_checked
7664 MONO_HANDLE_ASSIGN_RAW (string_handle, MONO_HANDLE_RAW (mono_string_intern_checked (o, error)));
7668 * mono_ldstr_utf8:
7670 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
7671 * of an object.
7673 char*
7674 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
7676 const char *str;
7677 size_t len2;
7678 long written = 0;
7679 char *as;
7680 GError *gerror = NULL;
7682 error_init (error);
7684 if (!mono_verifier_verify_string_signature (image, idx, error))
7685 return NULL;
7686 str = mono_metadata_user_string (image, idx);
7688 len2 = mono_metadata_decode_blob_size (str, &str);
7689 len2 >>= 1;
7691 as = g_utf16_to_utf8 ((gunichar2*)str, len2, NULL, &written, &gerror);
7692 if (gerror) {
7693 mono_error_set_argument (error, "string", gerror->message);
7694 g_error_free (gerror);
7695 return NULL;
7697 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7698 if (len2 > written) {
7699 /* allocate the total length and copy the part of the string that has been converted */
7700 char *as2 = (char *)g_malloc0 (len2);
7701 memcpy (as2, as, written);
7702 g_free (as);
7703 as = as2;
7706 return as;
7710 * mono_string_to_utf8:
7711 * \param s a \c System.String
7712 * \deprecated Use \c mono_string_to_utf8_checked_internal to avoid having an exception arbitrarily raised.
7713 * \returns the UTF-8 representation for \p s.
7714 * The resulting buffer needs to be freed with \c mono_free().
7716 char *
7717 mono_string_to_utf8 (MonoString *s)
7719 char *result;
7720 MONO_ENTER_GC_UNSAFE;
7721 ERROR_DECL (error);
7722 result = mono_string_to_utf8_checked_internal (s, error);
7724 if (!is_ok (error)) {
7725 mono_error_cleanup (error);
7726 result = NULL;
7728 MONO_EXIT_GC_UNSAFE;
7729 return result;
7733 * mono_utf16_to_utf8len:
7735 char *
7736 mono_utf16_to_utf8len (const gunichar2 *s, gsize slength, gsize *utf8_length, MonoError *error)
7738 MONO_REQ_GC_UNSAFE_MODE;
7740 long written = 0;
7741 *utf8_length = 0;
7742 char *as;
7743 GError *gerror = NULL;
7745 error_init (error);
7747 if (s == NULL)
7748 return NULL;
7750 if (!slength)
7751 return g_strdup ("");
7753 as = g_utf16_to_utf8 (s, slength, NULL, &written, &gerror);
7754 *utf8_length = written;
7755 if (gerror) {
7756 mono_error_set_argument (error, "string", gerror->message);
7757 g_error_free (gerror);
7758 return NULL;
7760 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7761 if (slength > written) {
7762 /* allocate the total length and copy the part of the string that has been converted */
7763 char *as2 = (char *)g_malloc0 (slength);
7764 memcpy (as2, as, written);
7765 g_free (as);
7766 as = as2;
7768 // FIXME utf8_length is ambiguous here.
7769 // For now it is what strlen would report.
7770 // A lot of code does not deal correctly with embedded nuls.
7773 return as;
7777 * mono_utf16_to_utf8:
7779 char *
7780 mono_utf16_to_utf8 (const gunichar2 *s, gsize slength, MonoError *error)
7782 gsize utf8_length = 0;
7783 return mono_utf16_to_utf8len (s, slength, &utf8_length, error);
7786 char *
7787 mono_string_to_utf8_checked_internal (MonoString *s, MonoError *error)
7789 MONO_REQ_GC_UNSAFE_MODE;
7791 error_init (error);
7793 if (s == NULL)
7794 return NULL;
7796 if (!s->length)
7797 return g_strdup ("");
7799 return mono_utf16_to_utf8 (mono_string_chars_internal (s), s->length, error);
7802 char *
7803 mono_string_to_utf8len (MonoStringHandle s, gsize *utf8len, MonoError *error)
7805 *utf8len = 0;
7806 if (MONO_HANDLE_IS_NULL (s))
7807 return NULL;
7809 char *utf8;
7811 MONO_ENTER_NO_SAFEPOINTS;
7813 utf8 = mono_utf16_to_utf8len (mono_string_chars_internal (MONO_HANDLE_RAW (s)), mono_string_handle_length (s), utf8len, error);
7815 MONO_EXIT_NO_SAFEPOINTS;
7817 return utf8;
7821 * mono_string_to_utf8_checked:
7822 * \param s a \c System.String
7823 * \param error a \c MonoError.
7824 * Converts a \c MonoString to its UTF-8 representation. May fail; check
7825 * \p error to determine whether the conversion was successful.
7826 * The resulting buffer should be freed with \c mono_free().
7828 char*
7829 mono_string_to_utf8_checked (MonoString *string_obj, MonoError *error)
7831 MONO_EXTERNAL_ONLY_GC_UNSAFE (char*, mono_string_to_utf8_checked_internal (string_obj, error));
7834 char *
7835 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7837 return mono_string_to_utf8_checked_internal (MONO_HANDLE_RAW (s), error);
7841 * mono_string_to_utf8_ignore:
7842 * \param s a MonoString
7843 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7844 * invalid surrogate pairs.
7845 * The resulting buffer should be freed with \c mono_free().
7847 char *
7848 mono_string_to_utf8_ignore (MonoString *s)
7850 MONO_REQ_GC_UNSAFE_MODE;
7852 long written = 0;
7853 char *as;
7855 if (s == NULL)
7856 return NULL;
7858 if (!s->length)
7859 return g_strdup ("");
7861 as = g_utf16_to_utf8 (mono_string_chars_internal (s), s->length, NULL, &written, NULL);
7863 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7864 if (s->length > written) {
7865 /* allocate the total length and copy the part of the string that has been converted */
7866 char *as2 = (char *)g_malloc0 (s->length);
7867 memcpy (as2, as, written);
7868 g_free (as);
7869 as = as2;
7872 return as;
7875 mono_unichar2*
7876 mono_string_to_utf16_internal_impl (MonoStringHandle s, MonoError *error)
7878 MONO_REQ_GC_UNSAFE_MODE;
7880 // FIXME This optimization ok to miss before wrapper? Or null is rare?
7881 if (MONO_HANDLE_RAW (s) == NULL)
7882 return NULL;
7884 int const length = mono_string_handle_length (s);
7885 mono_unichar2* const as = (mono_unichar2*)g_malloc ((length + 1) * sizeof (*as));
7886 if (as) {
7887 as [length] = 0;
7888 if (length)
7889 memcpy (as, mono_string_chars_internal (MONO_HANDLE_RAW (s)), length * sizeof (*as));
7891 return as;
7895 * mono_string_to_utf16:
7896 * \param s a \c MonoString
7897 * \returns a null-terminated array of the UTF-16 chars
7898 * contained in \p s. The result must be freed with \c g_free().
7899 * This is a temporary helper until our string implementation
7900 * is reworked to always include the null-terminating char.
7902 mono_unichar2*
7903 mono_string_to_utf16 (MonoString *string_obj)
7905 if (!string_obj)
7906 return NULL;
7907 MONO_EXTERNAL_ONLY (mono_unichar2*, mono_string_to_utf16_internal (string_obj));
7910 mono_unichar4*
7911 mono_string_to_utf32_internal_impl (MonoStringHandle s, MonoError *error)
7913 MONO_REQ_GC_UNSAFE_MODE;
7915 // FIXME This optimization ok to miss before wrapper? Or null is rare?
7916 if (MONO_HANDLE_RAW (s) == NULL)
7917 return NULL;
7919 return g_utf16_to_ucs4 (MONO_HANDLE_RAW (s)->chars, mono_string_handle_length (s), NULL, NULL, NULL);
7923 * mono_string_to_utf32:
7924 * \param s a \c MonoString
7925 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7926 * contained in \p s. The result must be freed with \c g_free().
7928 mono_unichar4*
7929 mono_string_to_utf32 (MonoString *string_obj)
7931 MONO_EXTERNAL_ONLY (mono_unichar4*, mono_string_to_utf32_internal (string_obj));
7935 * mono_string_from_utf16:
7936 * \param data the UTF-16 string (LPWSTR) to convert
7937 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7938 * \returns a \c MonoString.
7940 MonoString *
7941 mono_string_from_utf16 (gunichar2 *data)
7943 ERROR_DECL (error);
7944 MonoString *result = mono_string_from_utf16_checked (data, error);
7945 mono_error_cleanup (error);
7946 return result;
7950 * mono_string_from_utf16_checked:
7951 * \param data the UTF-16 string (LPWSTR) to convert
7952 * \param error set on error
7953 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7954 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7956 MonoString *
7957 mono_string_from_utf16_checked (const gunichar2 *data, MonoError *error)
7959 MONO_REQ_GC_UNSAFE_MODE;
7960 error_init (error);
7961 if (!data)
7962 return NULL;
7963 return mono_string_new_utf16_checked (mono_domain_get (), data, g_utf16_len (data), error);
7967 * mono_string_from_utf32:
7968 * \param data the UTF-32 string (LPWSTR) to convert
7969 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7970 * \returns a \c MonoString.
7972 MonoString *
7973 mono_string_from_utf32 (/*const*/ mono_unichar4 *data)
7975 ERROR_DECL (error);
7976 MonoString *result = mono_string_from_utf32_checked (data, error);
7977 mono_error_cleanup (error);
7978 return result;
7982 * mono_string_from_utf32_checked:
7983 * \param data the UTF-32 string (LPWSTR) to convert
7984 * \param error set on error
7985 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7986 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7988 MonoString *
7989 mono_string_from_utf32_checked (const mono_unichar4 *data, MonoError *error)
7991 MONO_REQ_GC_UNSAFE_MODE;
7993 error_init (error);
7994 MonoString* result = NULL;
7995 mono_unichar2 *utf16_output = NULL;
7996 GError *gerror = NULL;
7997 glong items_written;
7998 int len = 0;
8000 if (!data)
8001 return NULL;
8003 while (data [len]) len++;
8005 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
8007 if (gerror)
8008 g_error_free (gerror);
8010 result = mono_string_from_utf16_checked (utf16_output, error);
8011 g_free (utf16_output);
8012 return result;
8015 static char *
8016 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
8018 MONO_REQ_GC_UNSAFE_MODE;
8020 char *r;
8021 char *mp_s;
8022 int len;
8024 r = mono_string_to_utf8_checked_internal (s, error);
8025 if (!is_ok (error))
8026 return NULL;
8028 if (!mp && !image)
8029 return r;
8031 len = strlen (r) + 1;
8032 if (mp)
8033 mp_s = (char *)mono_mempool_alloc (mp, len);
8034 else
8035 mp_s = (char *)mono_image_alloc (image, len);
8037 memcpy (mp_s, r, len);
8039 g_free (r);
8041 return mp_s;
8045 * mono_string_to_utf8_image:
8046 * \param s a \c System.String
8047 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
8049 char *
8050 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
8052 MONO_REQ_GC_UNSAFE_MODE;
8054 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), error); /* FIXME pin the string */
8058 * mono_string_to_utf8_mp:
8059 * \param s a \c System.String
8060 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
8062 char *
8063 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
8065 MONO_REQ_GC_UNSAFE_MODE;
8067 return mono_string_to_utf8_internal (mp, NULL, s, error);
8071 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
8073 void
8074 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
8076 eh_callbacks = *cbs;
8079 MonoRuntimeExceptionHandlingCallbacks *
8080 mono_get_eh_callbacks (void)
8082 return &eh_callbacks;
8085 void
8086 mono_raise_exception_internal (MonoException *ex)
8088 /* raise_exception doesn't return, so the transition to GC Unsafe is unbalanced */
8089 MONO_STACKDATA (stackdata);
8090 mono_threads_enter_gc_unsafe_region_unbalanced_with_info (mono_thread_info_current (), &stackdata);
8091 mono_raise_exception_deprecated (ex);
8095 * mono_raise_exception:
8096 * \param ex exception object
8097 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
8098 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8100 void
8101 mono_raise_exception (MonoException *ex)
8103 MONO_EXTERNAL_ONLY_VOID (mono_raise_exception_internal (ex));
8107 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8109 void
8110 mono_raise_exception_deprecated (MonoException *ex)
8112 MONO_REQ_GC_UNSAFE_MODE;
8114 eh_callbacks.mono_raise_exception (ex);
8118 * mono_reraise_exception:
8119 * \param ex exception object
8120 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
8121 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8123 void
8124 mono_reraise_exception (MonoException *ex)
8126 mono_reraise_exception_deprecated (ex);
8130 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8132 void
8133 mono_reraise_exception_deprecated (MonoException *ex)
8135 MONO_REQ_GC_UNSAFE_MODE;
8137 eh_callbacks.mono_reraise_exception (ex);
8141 * CTX must point to managed code.
8143 void
8144 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
8146 MONO_REQ_GC_UNSAFE_MODE;
8148 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
8151 #ifndef ENABLE_NETCORE
8154 * mono_wait_handle_new:
8155 * \param domain Domain where the object will be created
8156 * \param handle Handle for the wait handle
8157 * \param error set on error.
8158 * \returns A new \c MonoWaitHandle created in the given domain for the
8159 * given handle. On failure returns NULL and sets \p error.
8161 MonoWaitHandle *
8162 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
8164 MONO_REQ_GC_UNSAFE_MODE;
8166 MonoWaitHandle *res;
8167 gpointer params [1];
8168 static MonoMethod *handle_set;
8170 error_init (error);
8171 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
8172 return_val_if_nok (error, NULL);
8174 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
8175 if (!handle_set)
8176 handle_set = mono_class_get_property_from_name_internal (mono_defaults.manualresetevent_class, "Handle")->set;
8178 params [0] = &handle;
8180 mono_runtime_invoke_checked (handle_set, res, params, error);
8181 return res;
8184 HANDLE
8185 mono_wait_handle_get_handle (MonoWaitHandle *handle)
8187 MONO_REQ_GC_UNSAFE_MODE;
8189 MonoSafeHandle *sh;
8191 MONO_STATIC_POINTER_INIT (MonoClassField, f_safe_handle)
8193 f_safe_handle = mono_class_get_field_from_name_full (mono_defaults.manualresetevent_class, "safeWaitHandle", NULL);
8194 g_assert (f_safe_handle);
8196 MONO_STATIC_POINTER_INIT_END (MonoClassField, f_safe_handle)
8198 mono_field_get_value_internal ((MonoObject*)handle, f_safe_handle, &sh);
8199 return sh->handle;
8202 #endif /* ENABLE_NETCORE */
8205 * Returns the MonoMethod to call to Capture the ExecutionContext.
8207 MonoMethod*
8208 mono_get_context_capture_method (void)
8210 /* older corlib revisions won't have the class (nor the method) */
8211 MonoClass *execution_context = mono_class_try_get_execution_context_class ();
8212 if (!execution_context)
8213 return NULL;
8215 MONO_STATIC_POINTER_INIT (MonoMethod, method)
8217 ERROR_DECL (error);
8218 mono_class_init_internal (execution_context);
8219 method = mono_class_get_method_from_name_checked (execution_context, "Capture", 0, 0, error);
8220 mono_error_assert_ok (error);
8222 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
8224 return method;
8227 static MonoObject*
8228 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
8230 #ifdef HOST_WASM
8231 return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
8232 #else
8233 MONO_REQ_GC_UNSAFE_MODE;
8235 RuntimeInvokeFunction runtime_invoke;
8237 error_init (error);
8239 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
8240 MonoMethod *method = mono_get_context_capture_method ();
8241 MonoMethod *wrapper;
8242 if (!method)
8243 return NULL;
8244 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
8245 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
8246 return_val_if_nok (error, NULL);
8247 domain->capture_context_method = mono_compile_method_checked (method, error);
8248 return_val_if_nok (error, NULL);
8251 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
8253 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
8254 #endif
8257 #ifndef ENABLE_NETCORE
8260 * mono_async_result_new:
8261 * \param domain domain where the object will be created.
8262 * \param handle wait handle.
8263 * \param state state to pass to AsyncResult
8264 * \param data C closure data.
8265 * \param error set on error.
8266 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
8267 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
8268 * On failure returns NULL and sets \p error.
8270 MonoAsyncResult *
8271 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
8273 MONO_REQ_GC_UNSAFE_MODE;
8275 error_init (error);
8276 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_class_get_asyncresult_class (), error);
8277 return_val_if_nok (error, NULL);
8278 MonoObject *context = mono_runtime_capture_context (domain, error);
8279 return_val_if_nok (error, NULL);
8280 /* we must capture the execution context from the original thread */
8281 if (context) {
8282 MONO_OBJECT_SETREF_INTERNAL (res, execution_context, context);
8283 /* note: result may be null if the flow is suppressed */
8286 res->data = (void **)data;
8287 MONO_OBJECT_SETREF_INTERNAL (res, object_data, object_data);
8288 MONO_OBJECT_SETREF_INTERNAL (res, async_state, state);
8289 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
8290 return_val_if_nok (error, NULL);
8291 if (handle != NULL)
8292 MONO_OBJECT_SETREF_INTERNAL (res, handle, (MonoObject *) wait_handle);
8294 res->sync_completed = FALSE;
8295 res->completed = FALSE;
8297 return res;
8300 static MonoObject*
8301 mono_message_invoke (MonoThreadInfo* mono_thread_info_current_var,
8302 MonoObject* target, MonoMethodMessage* msg,
8303 MonoObject** exc, MonoArray** out_args, MonoError* error);
8305 MonoObjectHandle
8306 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResultHandle aresh, MonoError* error)
8308 MONO_REQ_GC_UNSAFE_MODE;
8310 SETUP_ICALL_FUNCTION;
8312 MonoAsyncCall *ac;
8313 MonoObjectHandle res = MONO_HANDLE_NEW (MonoObject, NULL);
8314 MonoAsyncResult* ares = MONO_HANDLE_RAW (aresh);
8316 g_assert (ares);
8317 g_assert (ares->async_delegate);
8318 MONO_HANDLE_NEW (MonoObject, ares->async_delegate);
8320 ac = (MonoAsyncCall*) ares->object_data;
8321 MONO_HANDLE_NEW (MonoAsyncCall, ac);
8323 if (!ac) {
8324 MONO_HANDLE_ASSIGN_RAW (res, mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, error));
8325 return_val_if_nok (error, NULL_HANDLE);
8326 } else {
8327 gpointer wait_event = NULL;
8329 MONO_HANDLE_NEW (MonoMethodMessage, ac->msg);
8331 ac->msg->exc = NULL;
8333 MONO_HANDLE_ASSIGN_RAW (res, mono_message_invoke (mono_thread_info_current_var,
8334 ares->async_delegate,
8335 ac->msg,
8336 &ac->msg->exc,
8337 &ac->out_args,
8338 error));
8340 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
8341 mono_threads_begin_abort_protected_block ();
8343 if (!ac->msg->exc) {
8344 MonoException *ex = mono_error_convert_to_exception (error);
8345 MONO_OBJECT_SETREF_INTERNAL (ac->msg, exc, (MonoObject *)ex);
8346 } else {
8347 mono_error_cleanup (error);
8350 MONO_OBJECT_SETREF_INTERNAL (ac, res, MONO_HANDLE_RAW (res));
8352 MonoObjectHandle handle = MONO_HANDLE_NEW (MonoObject, NULL); // Create handle outside of lock.
8354 mono_monitor_enter_internal ((MonoObject*) ares);
8355 ares->completed = 1;
8356 if (ares->handle) {
8357 MONO_HANDLE_ASSIGN_RAW (handle, ares->handle);
8358 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
8360 mono_monitor_exit_internal ((MonoObject*) ares);
8362 if (wait_event != NULL)
8363 mono_w32event_set (wait_event);
8365 error_init (error); //the else branch would leave it in an undefined state
8366 if (ac->cb_method) {
8367 MONO_HANDLE_NEW (MonoDelegate, ac->cb_target);
8368 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, error);
8371 mono_threads_end_abort_protected_block ();
8373 return_val_if_nok (error, NULL_HANDLE);
8375 return res;
8377 #endif /* ENABLE_NETCORE */
8379 gboolean
8380 mono_message_init (MonoDomain *domain,
8381 MonoMethodMessage *this_obj,
8382 MonoReflectionMethod *method,
8383 MonoArray *out_args,
8384 MonoError *error)
8386 MONO_REQ_GC_UNSAFE_MODE;
8388 MONO_STATIC_POINTER_INIT (MonoMethod, init_message_method)
8390 init_message_method = mono_class_get_method_from_name_checked (mono_defaults.mono_method_message_class, "InitMessage", 2, 0, error);
8391 mono_error_assert_ok (error);
8392 g_assert (init_message_method != NULL);
8394 MONO_STATIC_POINTER_INIT_END (MonoMethod, init_message_method)
8396 error_init (error);
8397 /* FIXME set domain instead? */
8398 g_assert (domain == mono_domain_get ());
8400 gpointer args[2];
8402 args[0] = method;
8403 args[1] = out_args;
8405 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
8406 return is_ok (error);
8409 #ifndef DISABLE_REMOTING
8411 * mono_remoting_invoke:
8412 * \param real_proxy pointer to a \c RealProxy object
8413 * \param msg The \c MonoMethodMessage to execute
8414 * \param exc used to store exceptions
8415 * \param out_args used to store output arguments
8416 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
8417 * \c IMessage interface and it is not trivial to extract results from there. So
8418 * we call an helper method \c PrivateInvoke instead of calling
8419 * \c RealProxy::Invoke() directly.
8420 * \returns the result object.
8422 MonoObject *
8423 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
8425 MONO_REQ_GC_UNSAFE_MODE;
8427 MonoObject *o;
8428 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
8429 gpointer pa [4];
8431 g_assert (exc);
8433 error_init (error);
8435 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
8437 if (!im) {
8438 im = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "PrivateInvoke", 4, 0, error);
8439 return_val_if_nok (error, NULL);
8440 if (!im) {
8441 mono_error_set_not_supported (error, "Linked away.");
8442 return NULL;
8444 real_proxy->vtable->domain->private_invoke_method = im;
8447 pa [0] = real_proxy;
8448 pa [1] = msg;
8449 pa [2] = exc;
8450 pa [3] = out_args;
8452 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
8453 return_val_if_nok (error, NULL);
8455 return o;
8457 #endif
8459 // FIXME inline in the only caller
8460 static MonoObject*
8461 mono_message_invoke (MonoThreadInfo *mono_thread_info_current_var,
8462 MonoObject *target, MonoMethodMessage *msg,
8463 MonoObject **exc, MonoArray **out_args, MonoError *error)
8465 MONO_REQ_GC_UNSAFE_MODE;
8467 static MonoClass *object_array_klass;
8468 error_init (error);
8470 MonoDomain *domain;
8471 MonoMethod *method;
8472 MonoMethodSignature *sig;
8473 MonoArray *arr;
8474 int i, j, outarg_count = 0;
8476 #ifndef DISABLE_REMOTING
8477 if (target && mono_object_is_transparent_proxy (target)) {
8478 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
8480 gboolean const is_contextbound = mono_class_is_contextbound (tp->remote_class->proxy_class);
8482 MonoObject* const context = is_contextbound ? MONO_HANDLE_RAW (MONO_HANDLE_NEW (MonoObject, (MonoObject*)mono_context_get ())) : NULL;
8484 if (is_contextbound && tp->rp->context == context) {
8485 target = tp->rp->unwrapped_server;
8486 MONO_HANDLE_NEW (MonoObject, target);
8487 } else {
8488 MONO_HANDLE_NEW (MonoRealProxy, tp->rp);
8489 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
8492 #endif
8494 domain = mono_domain_get ();
8495 method = msg->method->method;
8496 sig = mono_method_signature_internal (method);
8498 for (i = 0; i < sig->param_count; i++) {
8499 if (sig->params [i]->byref)
8500 outarg_count++;
8503 if (!object_array_klass) {
8504 MonoClass *klass;
8506 klass = mono_class_create_array (mono_defaults.object_class, 1);
8507 g_assert (klass);
8509 mono_memory_barrier ();
8510 object_array_klass = klass;
8513 MonoVTable *vt = mono_class_vtable_checked (domain, object_array_klass, error);
8514 return_val_if_nok (error, NULL);
8515 arr = mono_array_new_specific_checked (vt, outarg_count, error);
8516 return_val_if_nok (error, NULL);
8517 MONO_HANDLE_NEW (MonoArray, arr);
8519 mono_gc_wbarrier_generic_store_internal (out_args, (MonoObject*) arr);
8520 *exc = NULL;
8522 MONO_HANDLE_NEW (MonoArray, msg->args);
8523 MonoObject *ret = mono_runtime_try_invoke_array (method, m_class_is_valuetype (method->klass)? mono_object_unbox_internal (target): target, msg->args, exc, error);
8524 return_val_if_nok (error, NULL);
8525 MONO_HANDLE_NEW (MonoObject, ret);
8527 MonoObjectHandle argh = MONO_HANDLE_NEW (MonoObject, NULL);
8529 for (i = 0, j = 0; i < sig->param_count; i++) {
8530 if (sig->params [i]->byref) {
8531 MonoObject* arg;
8532 arg = (MonoObject *)mono_array_get_internal (msg->args, gpointer, i);
8533 MONO_HANDLE_ASSIGN_RAW (argh, arg);
8534 mono_array_setref_internal (*out_args, j, arg);
8535 j++;
8539 return ret;
8543 * prepare_to_string_method:
8544 * @obj: The object
8545 * @target: Set to @obj or unboxed value if a valuetype
8547 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
8549 static MonoMethod *
8550 prepare_to_string_method (MonoObject *obj, void **target)
8552 MONO_REQ_GC_UNSAFE_MODE;
8554 MonoMethod *method;
8555 g_assert (target);
8556 g_assert (obj);
8558 *target = obj;
8560 MONO_STATIC_POINTER_INIT (MonoMethod, to_string)
8562 ERROR_DECL (error);
8563 to_string = mono_class_get_method_from_name_checked (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC, error);
8564 mono_error_assert_ok (error);
8566 MONO_STATIC_POINTER_INIT_END (MonoMethod, to_string)
8568 method = mono_object_get_virtual_method_internal (obj, to_string);
8570 // Unbox value type if needed
8571 if (m_class_is_valuetype (mono_method_get_class (method))) {
8572 *target = mono_object_unbox_internal (obj);
8574 return method;
8578 * mono_object_to_string:
8579 * \param obj The object
8580 * \param exc Any exception thrown by \c ToString. May be NULL.
8581 * \returns the result of calling \c ToString on an object.
8583 MonoString *
8584 mono_object_to_string (MonoObject *obj, MonoObject **exc)
8586 ERROR_DECL (error);
8587 MonoString *s = NULL;
8588 void *target;
8589 MonoMethod *method = prepare_to_string_method (obj, &target);
8590 if (exc) {
8591 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, error);
8592 if (*exc == NULL && !is_ok (error))
8593 *exc = (MonoObject*) mono_error_convert_to_exception (error);
8594 else
8595 mono_error_cleanup (error);
8596 } else {
8597 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, error);
8598 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
8601 return s;
8605 * mono_object_try_to_string:
8606 * \param obj The object
8607 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
8608 * \param error Set if method cannot be invoked.
8609 * \returns the result of calling \c ToString() on an object. If the
8610 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
8611 * and returns NULL.
8613 MonoString *
8614 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
8616 g_assert (exc);
8617 error_init (error);
8618 void *target;
8619 MonoMethod *method = prepare_to_string_method (obj, &target);
8620 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
8625 static char *
8626 get_native_backtrace (MonoException *exc_raw)
8628 HANDLE_FUNCTION_ENTER ();
8629 MONO_HANDLE_DCL(MonoException, exc);
8630 char * const trace = mono_exception_handle_get_native_backtrace (exc);
8631 HANDLE_FUNCTION_RETURN_VAL (trace);
8635 * mono_print_unhandled_exception:
8636 * \param exc The exception
8637 * Prints the unhandled exception.
8639 void
8640 mono_print_unhandled_exception_internal (MonoObject *exc)
8642 MONO_REQ_GC_UNSAFE_MODE;
8644 MonoString * str;
8645 char *message = (char*)"";
8646 gboolean free_message = FALSE;
8647 ERROR_DECL (error);
8649 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
8650 message = g_strdup ("OutOfMemoryException");
8651 free_message = TRUE;
8652 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
8653 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
8654 free_message = TRUE;
8655 } else {
8657 if (((MonoException*)exc)->native_trace_ips) {
8658 message = get_native_backtrace ((MonoException*)exc);
8659 free_message = TRUE;
8660 } else {
8661 MonoObject *other_exc = NULL;
8662 str = mono_object_try_to_string (exc, &other_exc, error);
8663 if (other_exc == NULL && !is_ok (error))
8664 other_exc = (MonoObject*)mono_error_convert_to_exception (error);
8665 else
8666 mono_error_cleanup (error);
8667 if (other_exc) {
8668 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
8669 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
8671 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
8672 original_backtrace, nested_backtrace);
8674 g_free (original_backtrace);
8675 g_free (nested_backtrace);
8676 free_message = TRUE;
8677 } else if (str) {
8678 message = mono_string_to_utf8_checked_internal (str, error);
8679 if (!is_ok (error)) {
8680 mono_error_cleanup (error);
8681 message = (char *) "";
8682 } else {
8683 free_message = TRUE;
8690 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
8691 * exc->vtable->klass->name, message);
8693 g_printerr ("\nUnhandled Exception:\n%s\n", message);
8695 if (free_message)
8696 g_free (message);
8699 void
8700 mono_print_unhandled_exception (MonoObject *exc)
8702 MONO_EXTERNAL_ONLY_VOID (mono_print_unhandled_exception_internal (exc));
8706 * mono_delegate_ctor_with_method:
8707 * \param this pointer to an uninitialized delegate object
8708 * \param target target object
8709 * \param addr pointer to native code
8710 * \param method method
8711 * \param error set on error.
8712 * Initialize a delegate and sets a specific method, not the one
8713 * associated with \p addr. This is useful when sharing generic code.
8714 * In that case \p addr will most probably not be associated with the
8715 * correct instantiation of the method.
8716 * On failure returns FALSE and sets \p error.
8718 gboolean
8719 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
8721 MONO_REQ_GC_UNSAFE_MODE;
8723 error_init (error);
8724 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
8726 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
8728 MonoClass *klass = mono_handle_class (this_obj);
8729 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
8731 if (method)
8732 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
8734 UnlockedIncrement (&mono_stats.delegate_creations);
8736 if (addr)
8737 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
8739 #ifndef DISABLE_REMOTING
8740 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
8741 if (callbacks.interp_get_remoting_invoke) {
8742 MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, callbacks.interp_get_remoting_invoke (method, addr, error));
8743 } else {
8744 g_assert (method);
8745 method = mono_marshal_get_remoting_invoke (method, error);
8746 return_val_if_nok (error, FALSE);
8747 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
8749 return_val_if_nok (error, FALSE);
8751 #endif
8753 MONO_HANDLE_SET (delegate, target, target);
8754 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
8755 g_assert (callbacks.init_delegate);
8756 callbacks.init_delegate (delegate, error);
8757 return_val_if_nok (error, FALSE);
8758 return TRUE;
8762 * mono_delegate_ctor:
8763 * \param this pointer to an uninitialized delegate object
8764 * \param target target object
8765 * \param addr pointer to native code
8766 * \param error set on error.
8767 * This is used to initialize a delegate.
8768 * On failure returns FALSE and sets \p error.
8770 gboolean
8771 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
8773 MONO_REQ_GC_UNSAFE_MODE;
8775 error_init (error);
8776 MonoDomain *domain = mono_domain_get ();
8777 MonoJitInfo *ji;
8778 MonoMethod *method = NULL;
8780 g_assert (addr);
8782 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
8783 /* Shared code */
8784 if (!ji && domain != mono_get_root_domain ())
8785 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
8786 if (ji) {
8787 method = mono_jit_info_get_method (ji);
8788 g_assert (!mono_class_is_gtd (method->klass));
8791 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
8795 * mono_method_call_message_new:
8796 * \param method method to encapsulate
8797 * \param params parameters to the method
8798 * \param invoke optional, delegate invoke.
8799 * \param cb async callback delegate.
8800 * \param state state passed to the async callback.
8801 * \param error set on error.
8802 * Translates arguments pointers into a \c MonoMethodMessage.
8803 * On failure returns NULL and sets \p error.
8805 MonoMethodMessage *
8806 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
8807 MonoDelegate **cb, MonoObject **state, MonoError *error)
8809 MONO_REQ_GC_UNSAFE_MODE;
8811 error_init (error);
8813 MonoDomain *domain = mono_domain_get ();
8814 MonoMethodSignature *sig = mono_method_signature_internal (method);
8815 MonoMethodMessage *msg;
8816 int i, count;
8818 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8819 return_val_if_nok (error, NULL);
8821 if (invoke) {
8822 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8823 return_val_if_nok (error, NULL);
8824 mono_message_init (domain, msg, rm, NULL, error);
8825 return_val_if_nok (error, NULL);
8826 count = sig->param_count - 2;
8827 } else {
8828 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8829 return_val_if_nok (error, NULL);
8830 mono_message_init (domain, msg, rm, NULL, error);
8831 return_val_if_nok (error, NULL);
8832 count = sig->param_count;
8835 for (i = 0; i < count; i++) {
8836 gpointer vpos;
8837 MonoClass *klass;
8838 MonoObject *arg;
8840 if (sig->params [i]->byref)
8841 vpos = *((gpointer *)params [i]);
8842 else
8843 vpos = params [i];
8845 klass = mono_class_from_mono_type_internal (sig->params [i]);
8847 if (m_class_is_valuetype (klass)) {
8848 arg = mono_value_box_checked (domain, klass, vpos, error);
8849 return_val_if_nok (error, NULL);
8850 } else
8851 arg = *((MonoObject **)vpos);
8853 mono_array_setref_internal (msg->args, i, arg);
8856 if (cb != NULL && state != NULL) {
8857 *cb = *((MonoDelegate **)params [i]);
8858 i++;
8859 *state = *((MonoObject **)params [i]);
8862 return msg;
8866 * mono_method_return_message_restore:
8868 * Restore results from message based processing back to arguments pointers
8870 void
8871 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8873 MONO_REQ_GC_UNSAFE_MODE;
8875 error_init (error);
8877 MonoMethodSignature *sig = mono_method_signature_internal (method);
8878 int i, j, type, size, out_len;
8880 if (out_args == NULL)
8881 return;
8882 out_len = mono_array_length_internal (out_args);
8883 if (out_len == 0)
8884 return;
8886 for (i = 0, j = 0; i < sig->param_count; i++) {
8887 MonoType *pt = sig->params [i];
8889 if (pt->byref) {
8890 char *arg;
8891 if (j >= out_len) {
8892 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8893 return;
8896 arg = (char *)mono_array_get_internal (out_args, gpointer, j);
8897 type = pt->type;
8899 g_assert (type != MONO_TYPE_VOID);
8901 if (MONO_TYPE_IS_REFERENCE (pt)) {
8902 mono_gc_wbarrier_generic_store_internal (*((MonoObject ***)params [i]), (MonoObject *)arg);
8903 } else {
8904 if (arg) {
8905 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8906 size = mono_class_value_size (klass, NULL);
8907 if (m_class_has_references (klass))
8908 mono_gc_wbarrier_value_copy_internal (*((gpointer *)params [i]), mono_object_get_data ((MonoObject*)arg), 1, klass);
8909 else
8910 mono_gc_memmove_atomic (*((gpointer *)params [i]), mono_object_get_data ((MonoObject*)arg), size);
8911 } else {
8912 size = mono_class_value_size (mono_class_from_mono_type_internal (pt), NULL);
8913 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8917 j++;
8922 #ifndef DISABLE_REMOTING
8925 * mono_load_remote_field:
8926 * \param this pointer to an object
8927 * \param klass klass of the object containing \p field
8928 * \param field the field to load
8929 * \param res a storage to store the result
8930 * This method is called by the runtime on attempts to load fields of
8931 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8932 * the object containing \p field. \p res is a storage location which can be
8933 * used to store the result.
8934 * \returns an address pointing to the value of field.
8936 gpointer
8937 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8939 gpointer result;
8941 MONO_ENTER_GC_UNSAFE;
8943 ERROR_DECL (error);
8944 result = mono_load_remote_field_checked (this_obj, klass, field, res, error);
8945 mono_error_cleanup (error);
8947 MONO_EXIT_GC_UNSAFE;
8949 return result;
8953 * mono_load_remote_field_checked:
8954 * \param this pointer to an object
8955 * \param klass klass of the object containing \p field
8956 * \param field the field to load
8957 * \param res a storage to store the result
8958 * \param error set on error
8959 * This method is called by the runtime on attempts to load fields of
8960 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8961 * the object containing \p field. \p res is a storage location which can be
8962 * used to store the result.
8963 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8965 gpointer
8966 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8968 MONO_REQ_GC_UNSAFE_MODE;
8970 error_init (error);
8972 MonoDomain *domain = mono_domain_get ();
8973 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8975 MonoObject *exc = NULL;
8976 MonoClass *field_class = NULL;
8977 MonoString *field_name = NULL;
8978 char* full_name = NULL;
8979 MonoString *full_name_str = NULL;
8980 MonoMethodMessage *msg = NULL;
8981 MonoArray *out_args = NULL;
8982 MonoReflectionMethod *rm = NULL;
8984 g_assert (mono_object_is_transparent_proxy (this_obj));
8985 g_assert (res != NULL);
8987 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8988 mono_field_get_value_internal (tp->rp->unwrapped_server, field, res);
8989 goto exit;
8992 MONO_STATIC_POINTER_INIT (MonoMethod, getter)
8994 getter = mono_class_get_method_from_name_checked (mono_defaults.object_class, "FieldGetter", -1, 0, error);
8995 goto_if_nok (error, return_null);
8996 if (!getter) {
8997 mono_error_set_not_supported (error, "Linked away.");
8998 goto return_null;
9001 MONO_STATIC_POINTER_INIT_END (MonoMethod, getter)
9003 field_class = mono_class_from_mono_type_internal (field->type);
9005 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
9006 goto_if_nok (error, return_null);
9008 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
9009 goto_if_nok (error, return_null);
9011 rm = mono_method_get_object_checked (domain, getter, NULL, error);
9012 goto_if_nok (error, return_null);
9014 mono_message_init (domain, msg, rm, out_args, error);
9015 goto_if_nok (error, return_null);
9017 full_name = mono_type_get_full_name (klass);
9018 full_name_str = mono_string_new_checked (domain, full_name, error);
9019 goto_if_nok (error, return_null);
9021 mono_array_setref_internal (msg->args, 0, full_name_str);
9022 field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
9023 goto_if_nok (error, return_null);
9025 mono_array_setref_internal (msg->args, 1, field_name);
9027 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
9028 goto_if_nok (error, return_null);
9030 if (exc) {
9031 mono_error_set_exception_instance (error, (MonoException *)exc);
9032 goto return_null;
9035 if (mono_array_length_internal (out_args) == 0)
9036 goto return_null;
9038 mono_gc_wbarrier_generic_store_internal (res, mono_array_get_internal (out_args, MonoObject *, 0));
9040 if (m_class_is_valuetype (field_class)) {
9041 res = (gpointer*)mono_object_get_data ((MonoObject*)*res);
9044 goto exit;
9045 return_null:
9046 res = NULL;
9047 exit:
9048 g_free (full_name);
9049 return res;
9053 * mono_load_remote_field_new:
9054 * \param this
9055 * \param klass
9056 * \param field
9057 * Missing documentation.
9059 MonoObject *
9060 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
9062 MonoObject *result;
9064 ERROR_DECL (error);
9066 MONO_ENTER_GC_UNSAFE;
9068 result = mono_load_remote_field_new_checked (this_obj, klass, field, error);
9069 mono_error_cleanup (error);
9071 MONO_EXIT_GC_UNSAFE;
9073 return result;
9077 * mono_load_remote_field_new_checked:
9078 * \param this pointer to an object
9079 * \param klass klass of the object containing \p field
9080 * \param field the field to load
9081 * \param error set on error.
9082 * This method is called by the runtime on attempts to load fields of
9083 * transparent proxy objects. \p this points to such TP, \p klass is the class of
9084 * the object containing \p field.
9085 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
9087 MonoObject *
9088 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
9090 MONO_REQ_GC_UNSAFE_MODE;
9092 error_init (error);
9094 g_assert (mono_object_is_transparent_proxy (this_obj));
9096 MONO_STATIC_POINTER_INIT (MonoMethod, tp_load)
9098 tp_load = mono_class_get_method_from_name_checked (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1, 0, error);
9099 return_val_if_nok (error, NULL);
9100 if (!tp_load) {
9101 mono_error_set_not_supported (error, "Linked away.");
9102 return NULL;
9105 MONO_STATIC_POINTER_INIT_END (MonoMethod, tp_load)
9107 /* MonoType *type = m_class_get_byval_arg (klass); */
9109 gpointer args [ ] = { &klass, &field };
9111 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
9115 * mono_store_remote_field:
9116 * \param this_obj pointer to an object
9117 * \param klass klass of the object containing \p field
9118 * \param field the field to load
9119 * \param val the value/object to store
9120 * This method is called by the runtime on attempts to store fields of
9121 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
9122 * the object containing \p field. \p val is the new value to store in \p field.
9124 void
9125 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
9127 MONO_ENTER_GC_UNSAFE;
9129 ERROR_DECL (error);
9130 (void) mono_store_remote_field_checked (this_obj, klass, field, val, error);
9131 mono_error_cleanup (error);
9133 MONO_EXIT_GC_UNSAFE;
9137 * mono_store_remote_field_checked:
9138 * \param this_obj pointer to an object
9139 * \param klass klass of the object containing \p field
9140 * \param field the field to load
9141 * \param val the value/object to store
9142 * \param error set on error
9143 * This method is called by the runtime on attempts to store fields of
9144 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
9145 * the object containing \p field. \p val is the new value to store in \p field.
9146 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
9148 gboolean
9149 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
9151 MONO_REQ_GC_UNSAFE_MODE;
9153 error_init (error);
9155 MonoDomain *domain = mono_domain_get ();
9156 MonoClass *field_class;
9157 MonoObject *arg;
9159 g_assert (mono_object_is_transparent_proxy (this_obj));
9161 field_class = mono_class_from_mono_type_internal (field->type);
9163 if (m_class_is_valuetype (field_class)) {
9164 arg = mono_value_box_checked (domain, field_class, val, error);
9165 return_val_if_nok (error, FALSE);
9166 } else {
9167 arg = *((MonoObject**)val);
9170 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
9174 * mono_store_remote_field_new:
9175 * \param this_obj
9176 * \param klass
9177 * \param field
9178 * \param arg
9179 * Missing documentation
9181 void
9182 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
9184 MONO_ENTER_GC_UNSAFE;
9186 ERROR_DECL (error);
9187 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
9188 mono_error_cleanup (error);
9190 MONO_EXIT_GC_UNSAFE;
9194 * mono_store_remote_field_new_checked:
9195 * \param this_obj
9196 * \param klass
9197 * \param field
9198 * \param arg
9199 * \param error
9200 * Missing documentation
9202 gboolean
9203 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
9205 MONO_REQ_GC_UNSAFE_MODE;
9207 error_init (error);
9209 g_assert (mono_object_is_transparent_proxy (this_obj));
9211 MONO_STATIC_POINTER_INIT (MonoMethod, tp_store)
9213 tp_store = mono_class_get_method_from_name_checked (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1, 0, error);
9214 return_val_if_nok (error, FALSE);
9215 if (!tp_store) {
9216 mono_error_set_not_supported (error, "Linked away.");
9217 return FALSE;
9220 MONO_STATIC_POINTER_INIT_END (MonoMethod, tp_store)
9222 gpointer args [ ] = { &klass, &field, arg };
9224 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
9225 return is_ok (error);
9227 #endif
9230 * mono_create_ftnptr:
9232 * Given a function address, create a function descriptor for it.
9233 * This is only needed on some platforms.
9235 gpointer
9236 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
9238 return callbacks.create_ftnptr (domain, addr);
9242 * mono_get_addr_from_ftnptr:
9244 * Given a pointer to a function descriptor, return the function address.
9245 * This is only needed on some platforms.
9247 gpointer
9248 mono_get_addr_from_ftnptr (gpointer descr)
9250 return callbacks.get_addr_from_ftnptr (descr);
9254 * mono_string_chars:
9255 * \param s a \c MonoString
9256 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
9258 mono_unichar2*
9259 mono_string_chars (MonoString *s)
9261 MONO_EXTERNAL_ONLY (mono_unichar2*, mono_string_chars_internal (s));
9265 * mono_string_length:
9266 * \param s MonoString
9267 * \returns the length in characters of the string
9270 mono_string_length (MonoString *s)
9272 MONO_EXTERNAL_ONLY (int, mono_string_length_internal (s));
9276 * mono_array_length:
9277 * \param array a \c MonoArray*
9278 * \returns the total number of elements in the array. This works for
9279 * both vectors and multidimensional arrays.
9281 uintptr_t
9282 mono_array_length (MonoArray *array)
9284 MONO_EXTERNAL_ONLY (uintptr_t, mono_array_length_internal (array));
9287 #ifdef ENABLE_CHECKED_BUILD_GC
9290 * mono_string_handle_length:
9291 * \param s \c MonoString
9292 * \returns the length in characters of the string
9295 mono_string_handle_length (MonoStringHandle s)
9297 MONO_REQ_GC_UNSAFE_MODE;
9299 return MONO_HANDLE_GETVAL (s, length);
9302 #endif
9305 * mono_array_addr_with_size:
9306 * \param array a \c MonoArray*
9307 * \param size size of the array elements
9308 * \param idx index into the array
9309 * Use this function to obtain the address for the \p idx item on the
9310 * \p array containing elements of size \p size.
9312 * This method performs no bounds checking or type checking.
9313 * \returns the address of the \p idx element in the array.
9315 char*
9316 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
9318 MONO_EXTERNAL_ONLY (char*, mono_array_addr_with_size_internal (array, size, idx));
9321 MonoArray *
9322 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
9324 MonoDomain *domain = mono_domain_get ();
9325 MonoArray *res;
9326 int len, i;
9328 error_init (error);
9329 if (!list)
9330 return NULL;
9332 len = g_list_length (list);
9333 res = mono_array_new_checked (domain, eclass, len, error);
9334 return_val_if_nok (error, NULL);
9336 for (i = 0; list; list = list->next, i++)
9337 mono_array_set_internal (res, gpointer, i, list->data);
9339 return res;
9343 * mono_class_value_size:
9344 * \param klass a class
9346 * This function is used for value types, and return the
9347 * space and the alignment to store that kind of value object.
9349 * \returns the size of a value of kind \p klass
9351 gint32
9352 mono_class_value_size (MonoClass *klass, guint32 *align)
9354 gint32 size;
9356 /* fixme: check disable, because we still have external revereces to
9357 * mscorlib and Dummy Objects
9359 /*g_assert (klass->valuetype);*/
9361 size = mono_class_instance_size (klass) - MONO_ABI_SIZEOF (MonoObject);
9363 if (align)
9364 *align = m_class_get_min_align (klass);
9366 return size;
9370 * mono_vtype_get_field_addr:
9372 * Return the address of the FIELD in the valuetype VTYPE.
9374 gpointer
9375 mono_vtype_get_field_addr (gpointer vtype, MonoClassField *field)
9377 return ((char*)vtype) + field->offset - MONO_ABI_SIZEOF (MonoObject);
9381 #if NEVER_DEFINED
9383 * The following section is purely to declare prototypes and
9384 * document the API, as these C files are processed by our
9385 * tool
9389 * mono_array_set:
9390 * \param array array to alter
9391 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
9392 * \param index index into the array
9393 * \param value value to set
9394 * Value Type version: This sets the \p index's element of the \p array
9395 * with elements of size sizeof(type) to the provided \p value.
9397 * This macro does not attempt to perform type checking or bounds checking
9398 * and it doesn't execute any write barriers.
9400 * Use this to set value types in a \c MonoArray. This shouldn't be used if
9401 * the copied value types contain references. Use \c mono_gc_wbarrier_value_copy
9402 * instead when also copying references.
9404 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
9409 * mono_array_setref:
9410 * \param array array to alter
9411 * \param index index into the array
9412 * \param value value to set
9413 * Reference Type version. This sets the \p index's element of the
9414 * \p array with elements of size sizeof(type) to the provided \p value.
9416 * This macro does not attempt to perform type checking or bounds checking.
9418 * Use this to reference types in a \c MonoArray.
9420 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
9425 * mono_array_get:
9426 * \param array array on which to operate on
9427 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
9428 * \param index index into the array
9430 * Use this macro to retrieve the \p index element of an \p array and
9431 * extract the value assuming that the elements of the array match
9432 * the provided type value.
9434 * This method can be used with both arrays holding value types and
9435 * reference types. For reference types, the \p type parameter should
9436 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
9438 * This macro does not attempt to perform type checking or bounds checking.
9440 * \returns The element at the \p index position in the \p array.
9442 Type mono_array_get_internal (MonoArray *array, Type element_type, uintptr_t index)
9445 #endif