Completely replace mono_error_ok with is_ok and make first external_only. (#16217)
[mono-project.git] / mono / metadata / object.c
blob846a9551d2439c91643f84433b560e2e50ff1c4f
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, MonoError *error);
75 static MonoStringHandle
76 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, 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 ERROR_DECL (error);
114 mono_runtime_object_init_checked (this_obj, error);
115 mono_error_assert_ok (error);
119 * mono_runtime_object_init_handle:
120 * \param this_obj the object to initialize
121 * \param error set on error.
122 * This function calls the zero-argument constructor (which must
123 * exist) for the given object and returns TRUE on success, or FALSE
124 * on error and sets \p error.
126 gboolean
127 mono_runtime_object_init_handle (MonoObjectHandle this_obj, MonoError *error)
129 MONO_REQ_GC_UNSAFE_MODE;
131 HANDLE_FUNCTION_ENTER ();
132 error_init (error);
134 MonoClass * const klass = MONO_HANDLE_GETVAL (this_obj, vtable)->klass;
135 MonoMethod * const method = mono_class_get_method_from_name_checked (klass, ".ctor", 0, 0, error);
136 mono_error_assert_msg_ok (error, "Could not lookup zero argument constructor");
137 g_assertf (method, "Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
139 if (m_class_is_valuetype (method->klass)) {
140 guint gchandle = 0;
141 gpointer raw = mono_object_handle_pin_unbox (this_obj, &gchandle);
142 mono_runtime_invoke_checked (method, raw, NULL, error);
143 mono_gchandle_free_internal (gchandle);
144 } else {
145 mono_runtime_invoke_handle_void (method, this_obj, NULL, error);
148 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
152 * mono_runtime_object_init_checked:
153 * \param this_obj the object to initialize
154 * \param error set on error.
155 * This function calls the zero-argument constructor (which must
156 * exist) for the given object and returns TRUE on success, or FALSE
157 * on error and sets \p error.
159 gboolean
160 mono_runtime_object_init_checked (MonoObject *this_obj_raw, MonoError *error)
162 HANDLE_FUNCTION_ENTER ();
163 MONO_HANDLE_DCL (MonoObject, this_obj);
164 gboolean const result = mono_runtime_object_init_handle (this_obj, error);
165 HANDLE_FUNCTION_RETURN_VAL (result);
168 /* The pseudo algorithm for type initialization from the spec
169 Note it doesn't say anything about domains - only threads.
171 2. If the type is initialized you are done.
172 2.1. If the type is not yet initialized, try to take an
173 initialization lock.
174 2.2. If successful, record this thread as responsible for
175 initializing the type and proceed to step 2.3.
176 2.2.1. If not, see whether this thread or any thread
177 waiting for this thread to complete already holds the lock.
178 2.2.2. If so, return since blocking would create a deadlock. This thread
179 will now see an incompletely initialized state for the type,
180 but no deadlock will arise.
181 2.2.3 If not, block until the type is initialized then return.
182 2.3 Initialize the parent type and then all interfaces implemented
183 by this type.
184 2.4 Execute the type initialization code for this type.
185 2.5 Mark the type as initialized, release the initialization lock,
186 awaken any threads waiting for this type to be initialized,
187 and return.
191 typedef struct
193 MonoNativeThreadId initializing_tid;
194 guint32 waiting_count;
195 gboolean done;
196 MonoCoopMutex mutex;
197 /* condvar used to wait for 'done' becoming TRUE */
198 MonoCoopCond cond;
199 } TypeInitializationLock;
201 /* for locking access to type_initialization_hash and blocked_thread_hash */
202 static MonoCoopMutex type_initialization_section;
204 static inline void
205 mono_type_initialization_lock (void)
207 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
208 mono_coop_mutex_lock (&type_initialization_section);
211 static inline void
212 mono_type_initialization_unlock (void)
214 mono_coop_mutex_unlock (&type_initialization_section);
217 static void
218 mono_type_init_lock (TypeInitializationLock *lock)
220 MONO_REQ_GC_NEUTRAL_MODE;
222 mono_coop_mutex_lock (&lock->mutex);
225 static void
226 mono_type_init_unlock (TypeInitializationLock *lock)
228 mono_coop_mutex_unlock (&lock->mutex);
231 /* from vtable to lock */
232 static GHashTable *type_initialization_hash;
234 /* from thread id to thread id being waited on */
235 static GHashTable *blocked_thread_hash;
237 /* Main thread */
238 static MonoThread *main_thread;
240 /* Functions supplied by the runtime */
241 static MonoRuntimeCallbacks callbacks;
244 * mono_thread_set_main:
245 * \param thread thread to set as the main thread
246 * This function can be used to instruct the runtime to treat \p thread
247 * as the main thread, ie, the thread that would normally execute the \c Main
248 * method. This basically means that at the end of \p thread, the runtime will
249 * wait for the existing foreground threads to quit and other such details.
251 void
252 mono_thread_set_main (MonoThread *thread)
254 MONO_REQ_GC_UNSAFE_MODE;
256 static gboolean registered = FALSE;
258 if (!registered) {
259 void *key = thread->internal_thread ? (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread->internal_thread->tid) : NULL;
260 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, key, "Thread Main Object");
261 registered = TRUE;
264 main_thread = thread;
268 * mono_thread_get_main:
270 MonoThread*
271 mono_thread_get_main (void)
273 MONO_REQ_GC_UNSAFE_MODE;
275 return main_thread;
278 void
279 mono_type_initialization_init (void)
281 mono_coop_mutex_init_recursive (&type_initialization_section);
282 type_initialization_hash = g_hash_table_new (NULL, NULL);
283 blocked_thread_hash = g_hash_table_new (NULL, NULL);
284 mono_coop_mutex_init (&ldstr_section);
285 mono_register_jit_icall (ves_icall_string_alloc, mono_icall_sig_object_int, FALSE);
288 void
289 mono_type_initialization_cleanup (void)
291 #if 0
292 /* This is causing race conditions with
293 * mono_release_type_locks
295 mono_coop_mutex_destroy (&type_initialization_section);
296 g_hash_table_destroy (type_initialization_hash);
297 type_initialization_hash = NULL;
298 #endif
299 mono_coop_mutex_destroy (&ldstr_section);
300 g_hash_table_destroy (blocked_thread_hash);
301 blocked_thread_hash = NULL;
303 free_main_args ();
306 static MonoException*
307 mono_get_exception_type_initialization_checked (const gchar *type_name, MonoException* inner_raw, MonoError *error)
309 HANDLE_FUNCTION_ENTER ();
310 MONO_HANDLE_DCL (MonoException, inner);
311 HANDLE_FUNCTION_RETURN_OBJ (mono_get_exception_type_initialization_handle (type_name, inner, error));
315 * get_type_init_exception_for_vtable:
317 * Return the stored type initialization exception for VTABLE.
319 static MonoException*
320 get_type_init_exception_for_vtable (MonoVTable *vtable)
322 MONO_REQ_GC_UNSAFE_MODE;
324 ERROR_DECL (error);
325 MonoDomain *domain = vtable->domain;
326 MonoClass *klass = vtable->klass;
327 MonoException *ex;
328 gchar *full_name;
330 if (!vtable->init_failed)
331 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
334 * If the initializing thread was rudely aborted, the exception is not stored
335 * in the hash.
337 ex = NULL;
338 mono_domain_lock (domain);
339 if (domain->type_init_exception_hash)
340 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
341 mono_domain_unlock (domain);
343 if (!ex) {
344 const char *klass_name_space = m_class_get_name_space (klass);
345 const char *klass_name = m_class_get_name (klass);
346 if (klass_name_space && *klass_name_space)
347 full_name = g_strdup_printf ("%s.%s", klass_name_space, klass_name);
348 else
349 full_name = g_strdup (klass_name);
350 ex = mono_get_exception_type_initialization_checked (full_name, NULL, error);
351 g_free (full_name);
352 return_val_if_nok (error, NULL);
355 return ex;
359 * mono_runtime_class_init:
360 * \param vtable vtable that needs to be initialized
361 * This routine calls the class constructor for \p vtable.
363 void
364 mono_runtime_class_init (MonoVTable *vtable)
366 MONO_REQ_GC_UNSAFE_MODE;
367 ERROR_DECL (error);
369 mono_runtime_class_init_full (vtable, error);
370 mono_error_assert_ok (error);
374 * Returns TRUE if the lock was freed.
375 * LOCKING: Caller should hold type_initialization_lock.
377 static gboolean
378 unref_type_lock (TypeInitializationLock *lock)
380 --lock->waiting_count;
381 if (lock->waiting_count == 0) {
382 mono_coop_mutex_destroy (&lock->mutex);
383 mono_coop_cond_destroy (&lock->cond);
384 g_free (lock);
385 return TRUE;
386 } else {
387 return FALSE;
392 * mono_runtime_run_module_cctor:
393 * \param image the image whose module ctor to run
394 * \param domain the domain to load the module class vtable in
395 * \param error set on error
396 * This routine runs the module ctor for \p image, if it hasn't already run
398 gboolean
399 mono_runtime_run_module_cctor (MonoImage *image, MonoDomain *domain, MonoError *error) {
400 MONO_REQ_GC_UNSAFE_MODE;
402 if (!image->checked_module_cctor) {
403 mono_image_check_for_module_cctor (image);
404 if (image->has_module_cctor) {
405 MonoClass *module_klass;
406 MonoVTable *module_vtable;
408 module_klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | 1, error);
409 if (!module_klass) {
410 return FALSE;
413 module_vtable = mono_class_vtable_checked (domain, module_klass, error);
414 if (!module_vtable)
415 return FALSE;
416 if (!mono_runtime_class_init_full (module_vtable, error))
417 return FALSE;
420 return TRUE;
424 * mono_runtime_class_init_full:
425 * \param vtable that neeeds to be initialized
426 * \param error set on error
427 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
429 gboolean
430 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
432 MONO_REQ_GC_UNSAFE_MODE;
434 MonoMethod *method = NULL;
435 MonoClass *klass;
436 gchar *full_name;
437 MonoDomain *domain = vtable->domain;
438 TypeInitializationLock *lock;
439 MonoNativeThreadId tid;
440 int do_initialization = 0;
441 MonoDomain *last_domain = NULL;
442 gboolean pending_tae = FALSE;
444 error_init (error);
446 if (vtable->initialized)
447 return TRUE;
449 klass = vtable->klass;
451 MonoImage *klass_image = m_class_get_image (klass);
452 if (!mono_runtime_run_module_cctor(klass_image, vtable->domain, error)) {
453 return FALSE;
455 method = mono_class_get_cctor (klass);
456 if (!method) {
457 vtable->initialized = 1;
458 return TRUE;
461 tid = mono_native_thread_id_get ();
464 * Due some preprocessing inside a global lock. If we are the first thread
465 * trying to initialize this class, create a separate lock+cond var, and
466 * acquire it before leaving the global lock. The other threads will wait
467 * on this cond var.
470 mono_type_initialization_lock ();
471 /* double check... */
472 if (vtable->initialized) {
473 mono_type_initialization_unlock ();
474 return TRUE;
476 if (vtable->init_failed) {
477 /* The type initialization already failed once, rethrow the same exception */
478 MonoException *exp = get_type_init_exception_for_vtable (vtable);
479 /* Reset the stack_trace and trace_ips because the exception is reused */
480 exp->stack_trace = NULL;
481 exp->trace_ips = NULL;
482 mono_type_initialization_unlock ();
483 mono_error_set_exception_instance (error, exp);
484 return FALSE;
486 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
487 if (lock == NULL) {
488 /* This thread will get to do the initialization */
489 if (mono_domain_get () != domain) {
490 /* Transfer into the target domain */
491 last_domain = mono_domain_get ();
492 if (!mono_domain_set_fast (domain, FALSE)) {
493 vtable->initialized = 1;
494 mono_type_initialization_unlock ();
495 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
496 return FALSE;
499 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
500 mono_coop_mutex_init_recursive (&lock->mutex);
501 mono_coop_cond_init (&lock->cond);
502 lock->initializing_tid = tid;
503 lock->waiting_count = 1;
504 lock->done = FALSE;
505 g_hash_table_insert (type_initialization_hash, vtable, lock);
506 do_initialization = 1;
507 } else {
508 gpointer blocked;
509 TypeInitializationLock *pending_lock;
511 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
512 mono_type_initialization_unlock ();
513 return TRUE;
515 /* see if the thread doing the initialization is already blocked on this thread */
516 gboolean is_blocked = TRUE;
517 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
518 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
519 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
520 if (!pending_lock->done) {
521 mono_type_initialization_unlock ();
522 return TRUE;
523 } else {
524 /* the thread doing the initialization is blocked on this thread,
525 but on a lock that has already been freed. It just hasn't got
526 time to awake */
527 is_blocked = FALSE;
528 break;
531 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
533 ++lock->waiting_count;
534 /* record the fact that we are waiting on the initializing thread */
535 if (is_blocked)
536 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
538 mono_type_initialization_unlock ();
540 if (do_initialization) {
541 MonoException *exc = NULL;
543 /* We are holding the per-vtable lock, do the actual initialization */
545 mono_threads_begin_abort_protected_block ();
546 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
547 mono_threads_end_abort_protected_block ();
549 //exception extracted, error will be set to the right value later
550 if (exc == NULL && !is_ok (error))//invoking failed but exc was not set
551 exc = mono_error_convert_to_exception (error);
552 else
553 mono_error_cleanup (error);
555 error_init (error);
557 const char *klass_name_space = m_class_get_name_space (klass);
558 const char *klass_name = m_class_get_name (klass);
559 /* If the initialization failed, mark the class as unusable. */
560 /* Avoid infinite loops */
561 if (!(!exc ||
562 (klass_image == mono_defaults.corlib &&
563 !strcmp (klass_name_space, "System") &&
564 !strcmp (klass_name, "TypeInitializationException")))) {
565 vtable->init_failed = 1;
567 if (klass_name_space && *klass_name_space)
568 full_name = g_strdup_printf ("%s.%s", klass_name_space, klass_name);
569 else
570 full_name = g_strdup (klass_name);
572 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
573 g_free (full_name);
575 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
578 * Store the exception object so it could be thrown on subsequent
579 * accesses.
581 mono_domain_lock (domain);
582 if (!domain->type_init_exception_hash)
583 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");
584 mono_g_hash_table_insert_internal (domain->type_init_exception_hash, klass, exc_to_throw);
585 mono_domain_unlock (domain);
588 if (last_domain)
589 mono_domain_set_fast (last_domain, TRUE);
591 /* Signal to the other threads that we are done */
592 mono_type_init_lock (lock);
593 lock->done = TRUE;
594 mono_coop_cond_broadcast (&lock->cond);
595 mono_type_init_unlock (lock);
598 * This can happen if the cctor self-aborts. We need to reactivate tae
599 * (next interruption checkpoint will throw it) and make sure we won't
600 * throw tie for the type.
602 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
603 pending_tae = TRUE;
604 mono_thread_resume_interruption (FALSE);
606 } else {
607 /* this just blocks until the initializing thread is done */
608 mono_type_init_lock (lock);
609 while (!lock->done)
610 mono_coop_cond_wait (&lock->cond, &lock->mutex);
611 mono_type_init_unlock (lock);
614 /* Do cleanup and setting vtable->initialized inside the global lock again */
615 mono_type_initialization_lock ();
616 if (!do_initialization)
617 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
618 gboolean deleted = unref_type_lock (lock);
619 if (deleted)
620 g_hash_table_remove (type_initialization_hash, vtable);
621 /* Have to set this here since we check it inside the global lock */
622 if (do_initialization && !vtable->init_failed)
623 vtable->initialized = 1;
624 mono_type_initialization_unlock ();
626 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
627 if (vtable->init_failed && !pending_tae) {
628 /* Either we were the initializing thread or we waited for the initialization */
629 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
630 return FALSE;
632 return TRUE;
635 MonoDomain *
636 mono_vtable_domain_internal (MonoVTable *vtable)
638 return vtable->domain;
641 MonoDomain*
642 mono_vtable_domain (MonoVTable *vtable)
644 MONO_EXTERNAL_ONLY (MonoDomain*, mono_vtable_domain_internal (vtable));
647 MonoClass *
648 mono_vtable_class_internal (MonoVTable *vtable)
650 return vtable->klass;
653 MonoClass*
654 mono_vtable_class (MonoVTable *vtable)
656 MONO_EXTERNAL_ONLY (MonoClass*, mono_vtable_class_internal (vtable));
659 static
660 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
662 MONO_REQ_GC_NEUTRAL_MODE;
664 MonoVTable *vtable = (MonoVTable*)key;
666 TypeInitializationLock *lock = (TypeInitializationLock*) value;
667 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
668 lock->done = TRUE;
670 * Have to set this since it cannot be set by the normal code in
671 * mono_runtime_class_init (). In this case, the exception object is not stored,
672 * and get_type_init_exception_for_class () needs to be aware of this.
674 mono_type_init_lock (lock);
675 vtable->init_failed = 1;
676 mono_coop_cond_broadcast (&lock->cond);
677 mono_type_init_unlock (lock);
678 gboolean deleted = unref_type_lock (lock);
679 if (deleted)
680 return TRUE;
682 return FALSE;
685 void
686 mono_release_type_locks (MonoInternalThread *thread)
688 MONO_REQ_GC_UNSAFE_MODE;
690 mono_type_initialization_lock ();
691 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
692 mono_type_initialization_unlock ();
695 #ifndef DISABLE_REMOTING
697 static gpointer
698 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
700 if (!callbacks.create_remoting_trampoline)
701 g_error ("remoting not installed");
702 return callbacks.create_remoting_trampoline (domain, method, target, error);
705 #endif
707 static MonoImtTrampolineBuilder imt_trampoline_builder;
708 static gboolean always_build_imt_trampolines;
710 #if (MONO_IMT_SIZE > 32)
711 #error "MONO_IMT_SIZE cannot be larger than 32"
712 #endif
714 void
715 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
717 memcpy (&callbacks, cbs, sizeof (*cbs));
720 MonoRuntimeCallbacks*
721 mono_get_runtime_callbacks (void)
723 return &callbacks;
726 void
727 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
729 imt_trampoline_builder = func;
732 void
733 mono_set_always_build_imt_trampolines (gboolean value)
735 always_build_imt_trampolines = value;
739 * mono_compile_method:
740 * \param method The method to compile.
741 * This JIT-compiles the method, and returns the pointer to the native code
742 * produced.
744 gpointer
745 mono_compile_method (MonoMethod *method)
747 ERROR_DECL (error);
748 gpointer result = mono_compile_method_checked (method, error);
749 mono_error_cleanup (error);
750 return result;
754 * mono_compile_method_checked:
755 * \param method The method to compile.
756 * \param error set on error.
757 * This JIT-compiles the method, and returns the pointer to the native code
758 * produced. On failure returns NULL and sets \p error.
760 gpointer
761 mono_compile_method_checked (MonoMethod *method, MonoError *error)
763 gpointer res;
765 MONO_REQ_GC_NEUTRAL_MODE
767 error_init (error);
769 g_assert (callbacks.compile_method);
770 res = callbacks.compile_method (method, error);
771 return res;
774 gpointer
775 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
777 gpointer res;
779 MONO_REQ_GC_NEUTRAL_MODE;
781 error_init (error);
782 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
783 return res;
786 gpointer
787 mono_runtime_create_delegate_trampoline (MonoClass *klass)
789 MONO_REQ_GC_NEUTRAL_MODE
791 g_assert (callbacks.create_delegate_trampoline);
792 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
796 * mono_runtime_free_method:
797 * \param domain domain where the method is hosted
798 * \param method method to release
799 * This routine is invoked to free the resources associated with
800 * a method that has been JIT compiled. This is used to discard
801 * methods that were used only temporarily (for example, used in marshalling)
803 void
804 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
806 MONO_REQ_GC_NEUTRAL_MODE
808 if (callbacks.free_method)
809 callbacks.free_method (domain, method);
811 mono_method_clear_object (domain, method);
813 mono_free_method (method);
817 * The vtables in the root appdomain are assumed to be reachable by other
818 * roots, and we don't use typed allocation in the other domains.
821 /* The sync block is no longer a GC pointer */
822 #define GC_HEADER_BITMAP (0)
824 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
826 #define MONO_OBJECT_HEADER_BITS (MONO_ABI_SIZEOF (MonoObject) / MONO_ABI_SIZEOF (gpointer))
828 static gsize*
829 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
831 MONO_REQ_GC_NEUTRAL_MODE;
833 MonoClassField *field;
834 MonoClass *p;
835 guint32 pos;
836 int max_size, wordsize;
838 wordsize = TARGET_SIZEOF_VOID_P;
840 if (static_fields)
841 max_size = mono_class_data_size (klass) / wordsize;
842 else
843 max_size = m_class_get_instance_size (klass) / wordsize;
844 if (max_size > size) {
845 g_assert (offset <= 0);
846 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
847 size = max_size;
850 /* An Ephemeron cannot be marked by sgen */
851 if (mono_gc_is_moving () && !static_fields && m_class_get_image (klass) == mono_defaults.corlib && !strcmp ("Ephemeron", m_class_get_name (klass))) {
852 *max_set = 0;
853 memset (bitmap, 0, size / 8);
854 return bitmap;
857 for (p = klass; p != NULL; p = m_class_get_parent (p)) {
858 gpointer iter = NULL;
859 while ((field = mono_class_get_fields_internal (p, &iter))) {
860 MonoType *type;
862 if (static_fields) {
863 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
864 continue;
865 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
866 continue;
867 } else {
868 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
869 continue;
871 /* FIXME: should not happen, flag as type load error */
872 if (field->type->byref)
873 break;
875 if (static_fields && field->offset == -1)
876 /* special static */
877 continue;
879 pos = field->offset / TARGET_SIZEOF_VOID_P;
880 pos += offset;
882 type = mono_type_get_underlying_type (field->type);
883 switch (type->type) {
884 case MONO_TYPE_U:
885 case MONO_TYPE_I:
886 case MONO_TYPE_PTR:
887 case MONO_TYPE_FNPTR:
888 break;
889 case MONO_TYPE_STRING:
890 case MONO_TYPE_SZARRAY:
891 case MONO_TYPE_CLASS:
892 case MONO_TYPE_OBJECT:
893 case MONO_TYPE_ARRAY:
894 g_assert ((field->offset % wordsize) == 0);
896 g_assert (pos < size || pos <= max_size);
897 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
898 *max_set = MAX (*max_set, pos);
899 break;
900 case MONO_TYPE_GENERICINST:
901 if (!mono_type_generic_inst_is_valuetype (type)) {
902 g_assert ((field->offset % wordsize) == 0);
904 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
905 *max_set = MAX (*max_set, pos);
906 break;
907 } else {
908 /* fall through */
910 case MONO_TYPE_VALUETYPE: {
911 MonoClass *fclass = mono_class_from_mono_type_internal (field->type);
912 if (m_class_has_references (fclass)) {
913 /* remove the object header */
914 compute_class_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS, max_set, FALSE);
916 break;
918 case MONO_TYPE_I1:
919 case MONO_TYPE_U1:
920 case MONO_TYPE_I2:
921 case MONO_TYPE_U2:
922 case MONO_TYPE_I4:
923 case MONO_TYPE_U4:
924 case MONO_TYPE_I8:
925 case MONO_TYPE_U8:
926 case MONO_TYPE_R4:
927 case MONO_TYPE_R8:
928 case MONO_TYPE_BOOLEAN:
929 case MONO_TYPE_CHAR:
930 break;
931 default:
932 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
933 break;
936 if (static_fields)
937 break;
939 return bitmap;
943 * mono_class_compute_bitmap:
945 * Mono internal function to compute a bitmap of reference fields in a class.
947 gsize*
948 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
950 MONO_REQ_GC_NEUTRAL_MODE;
952 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
955 #if 0
957 * similar to the above, but sets the bits in the bitmap for any non-ref field
958 * and ignores static fields
960 static gsize*
961 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
963 MonoClassField *field;
964 MonoClass *p;
965 guint32 pos, pos2;
966 int max_size, wordsize;
968 wordsize = TARGET_SIZEOF_VOID_P;
970 max_size = class->instance_size / wordsize;
971 if (max_size >= size)
972 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
974 for (p = class; p != NULL; p = p->parent) {
975 gpointer iter = NULL;
976 while ((field = mono_class_get_fields_internal (p, &iter))) {
977 MonoType *type;
979 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
980 continue;
981 /* FIXME: should not happen, flag as type load error */
982 if (field->type->byref)
983 break;
985 pos = field->offset / wordsize;
986 pos += offset;
988 type = mono_type_get_underlying_type (field->type);
989 switch (type->type) {
990 #if SIZEOF_VOID_P == 8
991 case MONO_TYPE_I:
992 case MONO_TYPE_U:
993 case MONO_TYPE_PTR:
994 case MONO_TYPE_FNPTR:
995 #endif
996 case MONO_TYPE_I8:
997 case MONO_TYPE_U8:
998 case MONO_TYPE_R8:
999 if ((((field->offset + 7) / wordsize) + offset) != pos) {
1000 pos2 = ((field->offset + 7) / wordsize) + offset;
1001 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
1003 /* fall through */
1004 #if SIZEOF_VOID_P == 4
1005 case MONO_TYPE_I:
1006 case MONO_TYPE_U:
1007 case MONO_TYPE_PTR:
1008 case MONO_TYPE_FNPTR:
1009 #endif
1010 case MONO_TYPE_I4:
1011 case MONO_TYPE_U4:
1012 case MONO_TYPE_R4:
1013 if ((((field->offset + 3) / wordsize) + offset) != pos) {
1014 pos2 = ((field->offset + 3) / wordsize) + offset;
1015 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
1017 /* fall through */
1018 case MONO_TYPE_CHAR:
1019 case MONO_TYPE_I2:
1020 case MONO_TYPE_U2:
1021 if ((((field->offset + 1) / wordsize) + offset) != pos) {
1022 pos2 = ((field->offset + 1) / wordsize) + offset;
1023 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
1025 /* fall through */
1026 case MONO_TYPE_BOOLEAN:
1027 case MONO_TYPE_I1:
1028 case MONO_TYPE_U1:
1029 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
1030 break;
1031 case MONO_TYPE_STRING:
1032 case MONO_TYPE_SZARRAY:
1033 case MONO_TYPE_CLASS:
1034 case MONO_TYPE_OBJECT:
1035 case MONO_TYPE_ARRAY:
1036 break;
1037 case MONO_TYPE_GENERICINST:
1038 if (!mono_type_generic_inst_is_valuetype (type)) {
1039 break;
1040 } else {
1041 /* fall through */
1043 case MONO_TYPE_VALUETYPE: {
1044 MonoClass *fclass = mono_class_from_mono_type_internal (field->type);
1045 /* remove the object header */
1046 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS);
1047 break;
1049 default:
1050 g_assert_not_reached ();
1051 break;
1055 return bitmap;
1059 * mono_class_insecure_overlapping:
1060 * check if a class with explicit layout has references and non-references
1061 * fields overlapping.
1063 * Returns: TRUE if it is insecure to load the type.
1065 gboolean
1066 mono_class_insecure_overlapping (MonoClass *klass)
1068 int max_set = 0;
1069 gsize *bitmap;
1070 gsize default_bitmap [4] = {0};
1071 gsize *nrbitmap;
1072 gsize default_nrbitmap [4] = {0};
1073 int i, insecure = FALSE;
1074 return FALSE;
1076 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1077 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
1079 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
1080 int idx = i % (sizeof (bitmap [0]) * 8);
1081 if (bitmap [idx] & nrbitmap [idx]) {
1082 insecure = TRUE;
1083 break;
1086 if (bitmap != default_bitmap)
1087 g_free (bitmap);
1088 if (nrbitmap != default_nrbitmap)
1089 g_free (nrbitmap);
1090 if (insecure) {
1091 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1092 return FALSE;
1094 return insecure;
1096 #endif
1098 MonoStringHandle
1099 ves_icall_string_alloc_impl (int length, MonoError *error)
1101 MonoString *s = mono_string_new_size_checked (mono_domain_get (), length, error);
1102 return_val_if_nok (error, NULL_HANDLE_STRING);
1103 return MONO_HANDLE_NEW (MonoString, s);
1106 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
1108 /* LOCKING: Acquires the loader lock */
1110 * Sets the following fields in KLASS:
1111 * - gc_desc
1112 * - gc_descr_inited
1114 void
1115 mono_class_compute_gc_descriptor (MonoClass *klass)
1117 MONO_REQ_GC_NEUTRAL_MODE;
1119 int max_set = 0;
1120 gsize *bitmap;
1121 gsize default_bitmap [4] = {0};
1122 MonoGCDescriptor gc_descr;
1124 if (!m_class_is_inited (klass))
1125 mono_class_init_internal (klass);
1127 if (m_class_is_gc_descr_inited (klass))
1128 return;
1130 bitmap = default_bitmap;
1131 if (klass == mono_defaults.string_class) {
1132 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1133 } else if (m_class_get_rank (klass)) {
1134 MonoClass *klass_element_class = m_class_get_element_class (klass);
1135 mono_class_compute_gc_descriptor (klass_element_class);
1136 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass_element_class))) {
1137 gsize abm = 1;
1138 gc_descr = mono_gc_make_descr_for_array (m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1139 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1140 class->name_space, class->name);*/
1141 } else {
1142 /* remove the object header */
1143 bitmap = mono_class_compute_bitmap (klass_element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(MONO_OBJECT_HEADER_BITS), &max_set, FALSE);
1144 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));
1145 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1146 class->name_space, class->name);*/
1148 } else {
1149 /*static int count = 0;
1150 if (count++ > 58)
1151 return;*/
1152 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1154 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1155 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1157 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1159 if (m_class_has_weak_fields (klass)) {
1160 gsize *weak_bitmap = NULL;
1161 int weak_bitmap_nbits = 0;
1163 weak_bitmap = (gsize *)mono_class_alloc0 (klass, m_class_get_instance_size (klass) / sizeof (gsize));
1164 if (mono_class_has_static_metadata (klass)) {
1165 for (MonoClass *p = klass; p != NULL; p = m_class_get_parent (p)) {
1166 gpointer iter = NULL;
1167 guint32 first_field_idx = mono_class_get_first_field_idx (p);
1168 MonoClassField *field;
1170 MonoClassField *p_fields = m_class_get_fields (p);
1171 MonoImage *p_image = m_class_get_image (p);
1172 while ((field = mono_class_get_fields_internal (p, &iter))) {
1173 guint32 field_idx = first_field_idx + (field - p_fields);
1174 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p_image, field_idx + 1)) {
1175 int pos = field->offset / sizeof (gpointer);
1176 if (pos + 1 > weak_bitmap_nbits)
1177 weak_bitmap_nbits = pos + 1;
1178 weak_bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
1184 for (int pos = 0; pos < weak_bitmap_nbits; ++pos) {
1185 if (weak_bitmap [pos / BITMAP_EL_SIZE] & ((gsize)1) << (pos % BITMAP_EL_SIZE)) {
1186 /* Clear the normal bitmap so these refs don't keep an object alive */
1187 bitmap [pos / BITMAP_EL_SIZE] &= ~(((gsize)1) << (pos % BITMAP_EL_SIZE));
1191 mono_loader_lock ();
1192 mono_class_set_weak_bitmap (klass, weak_bitmap_nbits, weak_bitmap);
1193 mono_loader_unlock ();
1196 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, m_class_get_instance_size (klass));
1199 if (bitmap != default_bitmap)
1200 g_free (bitmap);
1202 /* Publish the data */
1203 mono_class_publish_gc_descriptor (klass, gc_descr);
1207 * field_is_special_static:
1208 * @fklass: The MonoClass to look up.
1209 * @field: The MonoClassField describing the field.
1211 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1212 * SPECIAL_STATIC_NONE otherwise.
1214 static gint32
1215 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1217 MONO_REQ_GC_NEUTRAL_MODE;
1219 ERROR_DECL (error);
1220 MonoCustomAttrInfo *ainfo;
1221 int i;
1222 ainfo = mono_custom_attrs_from_field_checked (fklass, field, error);
1223 mono_error_cleanup (error); /* FIXME don't swallow the error? */
1224 if (!ainfo)
1225 return FALSE;
1226 for (i = 0; i < ainfo->num_attrs; ++i) {
1227 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1228 if (m_class_get_image (klass) == mono_defaults.corlib) {
1229 const char *klass_name = m_class_get_name (klass);
1230 if (strcmp (klass_name, "ThreadStaticAttribute") == 0) {
1231 mono_custom_attrs_free (ainfo);
1232 return SPECIAL_STATIC_THREAD;
1234 else if (strcmp (klass_name, "ContextStaticAttribute") == 0) {
1235 mono_custom_attrs_free (ainfo);
1236 return SPECIAL_STATIC_CONTEXT;
1240 mono_custom_attrs_free (ainfo);
1241 return SPECIAL_STATIC_NONE;
1244 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1245 #define mix(a,b,c) { \
1246 a -= c; a ^= rot(c, 4); c += b; \
1247 b -= a; b ^= rot(a, 6); a += c; \
1248 c -= b; c ^= rot(b, 8); b += a; \
1249 a -= c; a ^= rot(c,16); c += b; \
1250 b -= a; b ^= rot(a,19); a += c; \
1251 c -= b; c ^= rot(b, 4); b += a; \
1253 #define mono_final(a,b,c) { \
1254 c ^= b; c -= rot(b,14); \
1255 a ^= c; a -= rot(c,11); \
1256 b ^= a; b -= rot(a,25); \
1257 c ^= b; c -= rot(b,16); \
1258 a ^= c; a -= rot(c,4); \
1259 b ^= a; b -= rot(a,14); \
1260 c ^= b; c -= rot(b,24); \
1264 * mono_method_get_imt_slot:
1266 * The IMT slot is embedded into AOTed code, so this must return the same value
1267 * for the same method across all executions. This means:
1268 * - pointers shouldn't be used as hash values.
1269 * - mono_metadata_str_hash () should be used for hashing strings.
1271 guint32
1272 mono_method_get_imt_slot (MonoMethod *method)
1274 MONO_REQ_GC_NEUTRAL_MODE;
1276 MonoMethodSignature *sig;
1277 int hashes_count;
1278 guint32 *hashes_start, *hashes;
1279 guint32 a, b, c;
1280 int i;
1282 /* This can be used to stress tests the collision code */
1283 //return 0;
1286 * We do this to simplify generic sharing. It will hurt
1287 * performance in cases where a class implements two different
1288 * instantiations of the same generic interface.
1289 * The code in build_imt_slots () depends on this.
1291 if (method->is_inflated)
1292 method = ((MonoMethodInflated*)method)->declaring;
1294 sig = mono_method_signature_internal (method);
1295 hashes_count = sig->param_count + 4;
1296 hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1297 hashes = hashes_start;
1299 if (! MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass)) {
1300 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1301 m_class_get_name_space (method->klass), m_class_get_name (method->klass), method->name);
1304 /* Initialize hashes */
1305 hashes [0] = mono_metadata_str_hash (m_class_get_name (method->klass));
1306 hashes [1] = mono_metadata_str_hash (m_class_get_name_space (method->klass));
1307 hashes [2] = mono_metadata_str_hash (method->name);
1308 hashes [3] = mono_metadata_type_hash (sig->ret);
1309 for (i = 0; i < sig->param_count; i++) {
1310 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1313 /* Setup internal state */
1314 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1316 /* Handle most of the hashes */
1317 while (hashes_count > 3) {
1318 a += hashes [0];
1319 b += hashes [1];
1320 c += hashes [2];
1321 mix (a,b,c);
1322 hashes_count -= 3;
1323 hashes += 3;
1326 /* Handle the last 3 hashes (all the case statements fall through) */
1327 switch (hashes_count) {
1328 case 3 : c += hashes [2];
1329 case 2 : b += hashes [1];
1330 case 1 : a += hashes [0];
1331 mono_final (a,b,c);
1332 case 0: /* nothing left to add */
1333 break;
1336 g_free (hashes_start);
1337 /* Report the result */
1338 return c % MONO_IMT_SIZE;
1340 #undef rot
1341 #undef mix
1342 #undef mono_final
1344 #define DEBUG_IMT 0
1346 static void
1347 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1348 MONO_REQ_GC_NEUTRAL_MODE;
1350 guint32 imt_slot = mono_method_get_imt_slot (method);
1351 MonoImtBuilderEntry *entry;
1353 if (slot_num >= 0 && imt_slot != slot_num) {
1354 /* we build just a single imt slot and this is not it */
1355 return;
1358 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1359 entry->key = method;
1360 entry->value.vtable_slot = vtable_slot;
1361 entry->next = imt_builder [imt_slot];
1362 if (imt_builder [imt_slot] != NULL) {
1363 entry->children = imt_builder [imt_slot]->children + 1;
1364 if (entry->children == 1) {
1365 UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1366 *imt_collisions_bitmap |= (1 << imt_slot);
1368 } else {
1369 entry->children = 0;
1370 UnlockedIncrement (&mono_stats.imt_used_slots);
1372 imt_builder [imt_slot] = entry;
1373 #if DEBUG_IMT
1375 char *method_name = mono_method_full_name (method, TRUE);
1376 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1377 method, method_name, imt_slot, vtable_slot, entry->children);
1378 g_free (method_name);
1380 #endif
1383 #if DEBUG_IMT
1384 static void
1385 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1386 if (e != NULL) {
1387 MonoMethod *method = e->key;
1388 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1389 message,
1390 num,
1391 method,
1392 method->klass->name_space,
1393 method->klass->name,
1394 method->name);
1395 } else {
1396 printf (" * %s: NULL\n", message);
1399 #endif
1401 static int
1402 compare_imt_builder_entries (const void *p1, const void *p2) {
1403 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1404 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1406 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1409 static int
1410 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1412 MONO_REQ_GC_NEUTRAL_MODE;
1414 int count = end - start;
1415 int chunk_start = out_array->len;
1416 if (count < 4) {
1417 int i;
1418 for (i = start; i < end; ++i) {
1419 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1420 item->key = sorted_array [i]->key;
1421 item->value = sorted_array [i]->value;
1422 item->has_target_code = sorted_array [i]->has_target_code;
1423 item->is_equals = TRUE;
1424 if (i < end - 1)
1425 item->check_target_idx = out_array->len + 1;
1426 else
1427 item->check_target_idx = 0;
1428 g_ptr_array_add (out_array, item);
1430 } else {
1431 int middle = start + count / 2;
1432 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1434 item->key = sorted_array [middle]->key;
1435 item->is_equals = FALSE;
1436 g_ptr_array_add (out_array, item);
1437 imt_emit_ir (sorted_array, start, middle, out_array);
1438 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1440 return chunk_start;
1443 static GPtrArray*
1444 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1445 MONO_REQ_GC_NEUTRAL_MODE;
1447 int number_of_entries = entries->children + 1;
1448 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1449 GPtrArray *result = g_ptr_array_new ();
1450 MonoImtBuilderEntry *current_entry;
1451 int i;
1453 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1454 sorted_array [i] = current_entry;
1456 mono_qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1458 /*for (i = 0; i < number_of_entries; i++) {
1459 print_imt_entry (" sorted array:", sorted_array [i], i);
1462 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1464 g_free (sorted_array);
1465 return result;
1468 static gpointer
1469 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1471 MONO_REQ_GC_NEUTRAL_MODE;
1473 if (imt_builder_entry != NULL) {
1474 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1475 /* No collision, return the vtable slot contents */
1476 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1477 } else {
1478 /* Collision, build the trampoline */
1479 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1480 gpointer result;
1481 int i;
1482 result = imt_trampoline_builder (vtable, domain,
1483 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1484 for (i = 0; i < imt_ir->len; ++i)
1485 g_free (g_ptr_array_index (imt_ir, i));
1486 g_ptr_array_free (imt_ir, TRUE);
1487 return result;
1489 } else {
1490 if (fail_tramp)
1491 return fail_tramp;
1492 else
1493 /* Empty slot */
1494 return NULL;
1498 static MonoImtBuilderEntry*
1499 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1502 * LOCKING: requires the loader and domain locks.
1505 static void
1506 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1508 MONO_REQ_GC_NEUTRAL_MODE;
1510 int i;
1511 GSList *list_item;
1512 guint32 imt_collisions_bitmap = 0;
1513 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1514 int method_count = 0;
1515 gboolean record_method_count_for_max_collisions = FALSE;
1516 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1518 #if DEBUG_IMT
1519 printf ("Building IMT for class %s.%s slot %d\n", m_class_get_name_space (klass), m_class_get_name (klass), slot_num);
1520 #endif
1521 int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass);
1522 MonoClass **klass_interfaces_packed = m_class_get_interfaces_packed (klass);
1523 guint16 *klass_interface_offsets_packed = m_class_get_interface_offsets_packed (klass);
1524 for (i = 0; i < klass_interface_offsets_count; ++i) {
1525 MonoClass *iface = klass_interfaces_packed [i];
1526 int interface_offset = klass_interface_offsets_packed [i];
1527 int method_slot_in_interface, vt_slot;
1529 if (mono_class_has_variant_generic_params (iface))
1530 has_variant_iface = TRUE;
1532 mono_class_setup_methods (iface);
1533 vt_slot = interface_offset;
1534 int mcount = mono_class_get_method_count (iface);
1535 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1536 MonoMethod *method;
1538 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1540 * The imt slot of the method is the same as for its declaring method,
1541 * see the comment in mono_method_get_imt_slot (), so we can
1542 * avoid inflating methods which will be discarded by
1543 * add_imt_builder_entry anyway.
1545 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1546 if (mono_method_get_imt_slot (method) != slot_num) {
1547 vt_slot ++;
1548 continue;
1551 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1552 if (method->is_generic) {
1553 has_generic_virtual = TRUE;
1554 vt_slot ++;
1555 continue;
1558 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL) {
1559 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1560 vt_slot ++;
1564 if (extra_interfaces) {
1565 int interface_offset = m_class_get_vtable_size (klass);
1567 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1568 MonoClass* iface = (MonoClass *)list_item->data;
1569 int method_slot_in_interface;
1570 int mcount = mono_class_get_method_count (iface);
1571 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1572 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1574 if (method->is_generic)
1575 has_generic_virtual = TRUE;
1576 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1578 interface_offset += mcount;
1581 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1582 /* overwrite the imt slot only if we're building all the entries or if
1583 * we're building this specific one
1585 if (slot_num < 0 || i == slot_num) {
1586 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1588 if (entries) {
1589 if (imt_builder [i]) {
1590 MonoImtBuilderEntry *entry;
1592 /* Link entries with imt_builder [i] */
1593 for (entry = entries; entry->next; entry = entry->next) {
1594 #if DEBUG_IMT
1595 MonoMethod *method = (MonoMethod*)entry->key;
1596 char *method_name = mono_method_full_name (method, TRUE);
1597 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1598 g_free (method_name);
1599 #endif
1601 entry->next = imt_builder [i];
1602 entries->children += imt_builder [i]->children + 1;
1604 imt_builder [i] = entries;
1607 if (has_generic_virtual || has_variant_iface) {
1609 * There might be collisions later when the the trampoline is expanded.
1611 imt_collisions_bitmap |= (1 << i);
1614 * The IMT trampoline might be called with an instance of one of the
1615 * generic virtual methods, so has to fallback to the IMT trampoline.
1617 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1618 } else {
1619 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1621 #if DEBUG_IMT
1622 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1623 #endif
1626 if (imt_builder [i] != NULL) {
1627 int methods_in_slot = imt_builder [i]->children + 1;
1628 if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1629 UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1630 record_method_count_for_max_collisions = TRUE;
1632 method_count += methods_in_slot;
1636 UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1637 if (record_method_count_for_max_collisions) {
1638 UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1641 for (i = 0; i < MONO_IMT_SIZE; i++) {
1642 MonoImtBuilderEntry* entry = imt_builder [i];
1643 while (entry != NULL) {
1644 MonoImtBuilderEntry* next = entry->next;
1645 g_free (entry);
1646 entry = next;
1649 g_free (imt_builder);
1650 /* we OR the bitmap since we may build just a single imt slot at a time */
1651 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1654 static void
1655 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1656 MONO_REQ_GC_NEUTRAL_MODE;
1658 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1662 * mono_vtable_build_imt_slot:
1663 * \param vtable virtual object table struct
1664 * \param imt_slot slot in the IMT table
1665 * Fill the given \p imt_slot in the IMT table of \p vtable with
1666 * a trampoline or a trampoline for the case of collisions.
1667 * This is part of the internal mono API.
1668 * LOCKING: Take the domain lock.
1670 void
1671 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1673 MONO_REQ_GC_NEUTRAL_MODE;
1675 gpointer *imt = (gpointer*)vtable;
1676 imt -= MONO_IMT_SIZE;
1677 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1679 /* no support for extra interfaces: the proxy objects will need
1680 * to build the complete IMT
1681 * Update and heck needs to ahppen inside the proper domain lock, as all
1682 * the changes made to a MonoVTable.
1684 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1685 mono_domain_lock (vtable->domain);
1686 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1687 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1688 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1689 mono_domain_unlock (vtable->domain);
1690 mono_loader_unlock ();
1693 #define THUNK_THRESHOLD 10
1696 * mono_method_alloc_generic_virtual_trampoline:
1697 * \param domain a domain
1698 * \param size size in bytes
1699 * Allocs \p size bytes to be used for the code of a generic virtual
1700 * trampoline. It's either allocated from the domain's code manager or
1701 * reused from a previously invalidated piece.
1702 * LOCKING: The domain lock must be held.
1704 gpointer
1705 (mono_method_alloc_generic_virtual_trampoline) (MonoDomain *domain, int size)
1707 MONO_REQ_GC_NEUTRAL_MODE;
1709 static gboolean inited = FALSE;
1710 static int generic_virtual_trampolines_size = 0;
1712 if (!inited) {
1713 mono_counters_register ("Generic virtual trampoline bytes",
1714 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1715 inited = TRUE;
1717 generic_virtual_trampolines_size += size;
1719 return mono_domain_code_reserve (domain, size);
1722 typedef struct _GenericVirtualCase {
1723 MonoMethod *method;
1724 gpointer code;
1725 int count;
1726 struct _GenericVirtualCase *next;
1727 } GenericVirtualCase;
1730 * get_generic_virtual_entries:
1732 * Return IMT entries for the generic virtual method instances and
1733 * variant interface methods for vtable slot
1734 * VTABLE_SLOT.
1736 static MonoImtBuilderEntry*
1737 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1739 MONO_REQ_GC_NEUTRAL_MODE;
1741 GenericVirtualCase *list;
1742 MonoImtBuilderEntry *entries;
1744 mono_domain_lock (domain);
1745 if (!domain->generic_virtual_cases)
1746 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1748 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1750 entries = NULL;
1751 for (; list; list = list->next) {
1752 MonoImtBuilderEntry *entry;
1754 if (list->count < THUNK_THRESHOLD)
1755 continue;
1757 entry = g_new0 (MonoImtBuilderEntry, 1);
1758 entry->key = list->method;
1759 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1760 entry->has_target_code = 1;
1761 if (entries)
1762 entry->children = entries->children + 1;
1763 entry->next = entries;
1764 entries = entry;
1767 mono_domain_unlock (domain);
1769 /* FIXME: Leaking memory ? */
1770 return entries;
1774 * \param domain a domain
1775 * \param vtable_slot pointer to the vtable slot
1776 * \param method the inflated generic virtual method
1777 * \param code the method's code
1779 * Registers a call via unmanaged code to a generic virtual method
1780 * instantiation or variant interface method. If the number of calls reaches a threshold
1781 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1782 * virtual method trampoline.
1784 void
1785 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1786 gpointer *vtable_slot,
1787 MonoMethod *method, gpointer code)
1789 MONO_REQ_GC_NEUTRAL_MODE;
1791 static gboolean inited = FALSE;
1792 static int num_added = 0;
1793 static int num_freed = 0;
1795 GenericVirtualCase *gvc, *list;
1796 MonoImtBuilderEntry *entries;
1797 int i;
1798 GPtrArray *sorted;
1800 mono_domain_lock (domain);
1801 if (!domain->generic_virtual_cases)
1802 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1804 if (!inited) {
1805 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1806 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1807 inited = TRUE;
1810 /* Check whether the case was already added */
1811 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1812 gvc = list;
1813 while (gvc) {
1814 if (gvc->method == method)
1815 break;
1816 gvc = gvc->next;
1819 /* If not found, make a new one */
1820 if (!gvc) {
1821 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1822 gvc->method = method;
1823 gvc->code = code;
1824 gvc->count = 0;
1825 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1827 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1829 num_added++;
1832 if (++gvc->count == THUNK_THRESHOLD) {
1833 gpointer *old_thunk = (void **)*vtable_slot;
1834 gpointer vtable_trampoline = NULL;
1835 gpointer imt_trampoline = NULL;
1837 if ((gpointer)vtable_slot < (gpointer)vtable) {
1838 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1839 int imt_slot = MONO_IMT_SIZE + displacement;
1841 /* Force the rebuild of the trampoline at the next call */
1842 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1843 *vtable_slot = imt_trampoline;
1844 } else {
1845 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1847 entries = get_generic_virtual_entries (domain, vtable_slot);
1849 sorted = imt_sort_slot_entries (entries);
1851 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1852 vtable_trampoline);
1854 while (entries) {
1855 MonoImtBuilderEntry *next = entries->next;
1856 g_free (entries);
1857 entries = next;
1860 for (i = 0; i < sorted->len; ++i)
1861 g_free (g_ptr_array_index (sorted, i));
1862 g_ptr_array_free (sorted, TRUE);
1864 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1865 num_freed ++;
1869 mono_domain_unlock (domain);
1872 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1875 * mono_class_vtable:
1876 * \param domain the application domain
1877 * \param class the class to initialize
1878 * VTables are domain specific because we create domain specific code, and
1879 * they contain the domain specific static class data.
1880 * On failure, NULL is returned, and \c class->exception_type is set.
1882 MonoVTable *
1883 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1885 MonoVTable* vtable;
1886 MONO_ENTER_GC_UNSAFE;
1887 ERROR_DECL (error);
1888 vtable = mono_class_vtable_checked (domain, klass, error);
1889 mono_error_cleanup (error);
1890 MONO_EXIT_GC_UNSAFE;
1891 return vtable;
1895 * mono_class_vtable_checked:
1896 * \param domain the application domain
1897 * \param class the class to initialize
1898 * \param error set on failure.
1899 * VTables are domain specific because we create domain specific code, and
1900 * they contain the domain specific static class data.
1902 MonoVTable *
1903 mono_class_vtable_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
1905 MONO_REQ_GC_UNSAFE_MODE;
1907 MonoClassRuntimeInfo *runtime_info;
1909 error_init (error);
1911 g_assert (klass);
1913 if (mono_class_has_failure (klass)) {
1914 mono_error_set_for_class_failure (error, klass);
1915 return NULL;
1918 /* this check can be inlined in jitted code, too */
1919 runtime_info = m_class_get_runtime_info (klass);
1920 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1921 return runtime_info->domain_vtables [domain->domain_id];
1922 return mono_class_create_runtime_vtable (domain, klass, error);
1926 * mono_class_try_get_vtable:
1927 * \param domain the application domain
1928 * \param class the class to initialize
1929 * This function tries to get the associated vtable from \p class if
1930 * it was already created.
1932 MonoVTable *
1933 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1935 MONO_REQ_GC_NEUTRAL_MODE;
1937 MonoClassRuntimeInfo *runtime_info;
1939 g_assert (klass);
1941 runtime_info = m_class_get_runtime_info (klass);
1942 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1943 return runtime_info->domain_vtables [domain->domain_id];
1944 return NULL;
1947 static gpointer*
1948 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1950 MONO_REQ_GC_NEUTRAL_MODE;
1952 size_t alloc_offset;
1955 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1956 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1957 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1959 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1960 g_assert ((imt_table_bytes & 7) == 4);
1961 vtable_size += 4;
1962 alloc_offset = 4;
1963 } else {
1964 alloc_offset = 0;
1967 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1970 static MonoVTable *
1971 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1973 MONO_REQ_GC_UNSAFE_MODE;
1975 HANDLE_FUNCTION_ENTER ();
1977 MonoVTable *vt;
1978 MonoClassRuntimeInfo *runtime_info;
1979 MonoClassField *field;
1980 char *t;
1981 int i, vtable_slots;
1982 size_t imt_table_bytes;
1983 int gc_bits;
1984 guint32 vtable_size, class_size;
1985 gpointer iter;
1986 gpointer *interface_offsets;
1987 gboolean use_interpreter = callbacks.is_interpreter_enabled ();
1989 mono_loader_lock (); /*FIXME mono_class_init_internal acquires it*/
1990 mono_domain_lock (domain);
1992 runtime_info = m_class_get_runtime_info (klass);
1993 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1994 mono_domain_unlock (domain);
1995 mono_loader_unlock ();
1996 vt = runtime_info->domain_vtables [domain->domain_id];
1997 goto exit;
1999 if (!m_class_is_inited (klass) || mono_class_has_failure (klass)) {
2000 if (!mono_class_init_internal (klass) || mono_class_has_failure (klass)) {
2001 mono_domain_unlock (domain);
2002 mono_loader_unlock ();
2003 mono_error_set_for_class_failure (error, klass);
2004 goto return_null;
2008 /* Array types require that their element type be valid*/
2009 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_ARRAY || m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
2010 MonoClass *element_class = m_class_get_element_class (klass);
2011 if (!m_class_is_inited (element_class))
2012 mono_class_init_internal (element_class);
2014 /*mono_class_init_internal can leave the vtable layout to be lazily done and we can't afford this here*/
2015 if (!mono_class_has_failure (element_class) && !m_class_get_vtable_size (element_class))
2016 mono_class_setup_vtable (element_class);
2018 if (mono_class_has_failure (element_class)) {
2019 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2020 if (!mono_class_has_failure (klass))
2021 mono_class_set_type_load_failure (klass, "");
2022 mono_domain_unlock (domain);
2023 mono_loader_unlock ();
2024 mono_error_set_for_class_failure (error, klass);
2025 goto return_null;
2030 * For some classes, mono_class_init_internal () already computed klass->vtable_size, and
2031 * that is all that is needed because of the vtable trampolines.
2033 if (!m_class_get_vtable_size (klass))
2034 mono_class_setup_vtable (klass);
2036 if (mono_class_is_ginst (klass) && !m_class_get_vtable (klass))
2037 mono_class_check_vtable_constraints (klass, NULL);
2039 /* Initialize klass->has_finalize */
2040 mono_class_has_finalizer (klass);
2042 if (mono_class_has_failure (klass)) {
2043 mono_domain_unlock (domain);
2044 mono_loader_unlock ();
2045 mono_error_set_for_class_failure (error, klass);
2046 goto return_null;
2049 vtable_slots = m_class_get_vtable_size (klass);
2050 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2051 class_size = mono_class_data_size (klass);
2052 if (class_size)
2053 vtable_slots++;
2055 if (m_class_get_interface_offsets_count (klass)) {
2056 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2057 /* Interface table for the interpreter */
2058 if (use_interpreter)
2059 imt_table_bytes *= 2;
2060 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2061 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2062 } else {
2063 imt_table_bytes = 0;
2066 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2068 UnlockedIncrement (&mono_stats.used_class_count);
2069 UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
2071 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2072 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2073 /* If on interp, skip the interp interface table */
2074 if (use_interpreter)
2075 interface_offsets = (gpointer*)((char*)interface_offsets + imt_table_bytes / 2);
2076 g_assert (!((gsize)vt & 7));
2078 vt->klass = klass;
2079 vt->rank = m_class_get_rank (klass);
2080 vt->domain = domain;
2081 if ((vt->rank > 0) || klass == mono_get_string_class ())
2082 vt->flags |= MONO_VT_FLAG_ARRAY_OR_STRING;
2084 MONO_PROFILER_RAISE (vtable_loading, (vt));
2086 mono_class_compute_gc_descriptor (klass);
2088 * For Boehm:
2089 * We can't use typed allocation in the non-root domains, since the
2090 * collector needs the GC descriptor stored in the vtable even after
2091 * the mempool containing the vtable is destroyed when the domain is
2092 * unloaded. An alternative might be to allocate vtables in the GC
2093 * heap, but this does not seem to work (it leads to crashes inside
2094 * libgc). If that approach is tried, two gc descriptors need to be
2095 * allocated for each class: one for the root domain, and one for all
2096 * other domains. The second descriptor should contain a bit for the
2097 * vtable field in MonoObject, since we can no longer assume the
2098 * vtable is reachable by other roots after the appdomain is unloaded.
2100 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
2101 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2102 else
2103 vt->gc_descr = m_class_get_gc_descr (klass);
2105 gc_bits = mono_gc_get_vtable_bits (klass);
2106 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2108 vt->gc_bits = gc_bits;
2110 if (class_size) {
2111 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2112 if (m_class_has_static_refs (klass)) {
2113 MonoGCDescriptor statics_gc_descr;
2114 int max_set = 0;
2115 gsize default_bitmap [4] = {0};
2116 gsize *bitmap;
2118 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2119 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2120 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2121 vt->vtable [m_class_get_vtable_size (klass)] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, vt, "Static Fields");
2123 if (bitmap != default_bitmap)
2124 g_free (bitmap);
2125 } else {
2126 vt->vtable [m_class_get_vtable_size (klass)] = mono_domain_alloc0 (domain, class_size);
2128 vt->has_static_fields = TRUE;
2129 UnlockedAdd (&mono_stats.class_static_data_size, class_size);
2132 iter = NULL;
2133 while ((field = mono_class_get_fields_internal (klass, &iter))) {
2134 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2135 continue;
2136 if (mono_field_is_deleted (field))
2137 continue;
2138 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2139 gint32 special_static = m_class_has_no_special_static_fields (klass) ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2140 if (special_static != SPECIAL_STATIC_NONE) {
2141 guint32 size, offset;
2142 gint32 align;
2143 gsize default_bitmap [4] = {0};
2144 gsize *bitmap;
2145 int max_set = 0;
2146 int numbits;
2147 MonoClass *fclass;
2148 if (mono_type_is_reference (field->type)) {
2149 default_bitmap [0] = 1;
2150 numbits = 1;
2151 bitmap = default_bitmap;
2152 } else if (mono_type_is_struct (field->type)) {
2153 fclass = mono_class_from_mono_type_internal (field->type);
2154 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(MONO_OBJECT_HEADER_BITS), &max_set, FALSE);
2155 numbits = max_set + 1;
2156 } else {
2157 default_bitmap [0] = 0;
2158 numbits = 0;
2159 bitmap = default_bitmap;
2161 size = mono_type_size (field->type, &align);
2162 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2163 if (!domain->special_static_fields)
2164 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2165 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2166 if (bitmap != default_bitmap)
2167 g_free (bitmap);
2169 * This marks the field as special static to speed up the
2170 * checks in mono_field_static_get/set_value ().
2172 field->offset = -1;
2173 continue;
2176 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2177 MonoClass *fklass = mono_class_from_mono_type_internal (field->type);
2178 const char *data = mono_field_get_data (field);
2180 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2181 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2182 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2183 if (!data)
2184 continue;
2185 if (m_class_is_valuetype (fklass)) {
2186 memcpy (t, data, mono_class_value_size (fklass, NULL));
2187 } else {
2188 /* it's a pointer type: add check */
2189 g_assert ((m_class_get_byval_arg (fklass)->type == MONO_TYPE_PTR) || (m_class_get_byval_arg (fklass)->type == MONO_TYPE_FNPTR));
2190 *t = *(char *)data;
2192 continue;
2196 vt->max_interface_id = m_class_get_max_interface_id (klass);
2197 vt->interface_bitmap = m_class_get_interface_bitmap (klass);
2199 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2200 // class->name, klass->interface_offsets_count);
2202 /* Initialize vtable */
2203 if (callbacks.get_vtable_trampoline) {
2204 // This also covers the AOT case
2205 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2206 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2208 } else {
2209 mono_class_setup_vtable (klass);
2211 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2212 MonoMethod *cm;
2214 cm = m_class_get_vtable (klass) [i];
2215 if (cm) {
2216 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2217 if (!is_ok (error)) {
2218 mono_domain_unlock (domain);
2219 mono_loader_unlock ();
2220 MONO_PROFILER_RAISE (vtable_failed, (vt));
2221 goto return_null;
2227 if (imt_table_bytes) {
2228 /* Now that the vtable is full, we can actually fill up the IMT */
2229 for (i = 0; i < MONO_IMT_SIZE; ++i)
2230 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2234 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2235 * re-acquire them and check if another thread has created the vtable in the meantime.
2237 /* Special case System.MonoType to avoid infinite recursion */
2238 if (klass != mono_defaults.runtimetype_class) {
2239 MonoReflectionTypeHandle vt_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
2240 vt->type = MONO_HANDLE_RAW (vt_type);
2241 if (!is_ok (error)) {
2242 mono_domain_unlock (domain);
2243 mono_loader_unlock ();
2244 MONO_PROFILER_RAISE (vtable_failed, (vt));
2245 goto return_null;
2247 if (mono_handle_class (vt_type) != mono_defaults.runtimetype_class)
2248 /* This is unregistered in
2249 unregister_vtable_reflection_type() in
2250 domain.c. */
2251 MONO_GC_REGISTER_ROOT_IF_MOVING (vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object");
2254 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2256 /* class_vtable_array keeps an array of created vtables
2258 g_ptr_array_add (domain->class_vtable_array, vt);
2259 /* klass->runtime_info is protected by the loader lock, both when
2260 * it it enlarged and when it is stored info.
2264 * Store the vtable in klass->runtime_info.
2265 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2267 mono_memory_barrier ();
2269 mono_class_setup_runtime_info (klass, domain, vt);
2271 if (klass == mono_defaults.runtimetype_class) {
2272 MonoReflectionTypeHandle vt_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
2273 vt->type = MONO_HANDLE_RAW (vt_type);
2274 if (!is_ok (error)) {
2275 mono_domain_unlock (domain);
2276 mono_loader_unlock ();
2277 MONO_PROFILER_RAISE (vtable_failed, (vt));
2278 goto return_null;
2281 if (mono_handle_class (vt_type) != mono_defaults.runtimetype_class)
2282 /* This is unregistered in
2283 unregister_vtable_reflection_type() in
2284 domain.c. */
2285 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object");
2288 mono_domain_unlock (domain);
2289 mono_loader_unlock ();
2291 /* make sure the parent is initialized */
2292 /*FIXME shouldn't this fail the current type?*/
2293 if (m_class_get_parent (klass))
2294 mono_class_vtable_checked (domain, m_class_get_parent (klass), error);
2296 MONO_PROFILER_RAISE (vtable_loaded, (vt));
2298 goto exit;
2299 return_null:
2300 vt = NULL;
2301 exit:
2302 HANDLE_FUNCTION_RETURN_VAL (vt);
2305 #ifndef DISABLE_REMOTING
2307 * mono_remote_class_is_interface_proxy:
2308 * \param remote_class
2310 * Returns TRUE if the given remote class is a proxying an interface (as
2311 * opposed to a class deriving from MarshalByRefObject).
2313 gboolean
2314 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2316 /* This if condition is taking advantage of how mono_remote_class ()
2317 * works: if that code changes, this needs to change too. */
2318 return (remote_class->interface_count >= 1 &&
2319 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2323 * mono_class_proxy_vtable:
2324 * \param domain the application domain
2325 * \param remove_class the remote class
2326 * \param error set on error
2327 * Creates a vtable for transparent proxies. It is basically
2328 * a copy of the real vtable of the class wrapped in \p remote_class,
2329 * but all function pointers invoke the remoting functions, and
2330 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2332 * On failure returns NULL and sets \p error
2334 static MonoVTable *
2335 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2337 MONO_REQ_GC_UNSAFE_MODE;
2339 MonoVTable *vt, *pvt = NULL;
2340 int i, j, vtsize, extra_interface_vtsize = 0;
2341 guint32 max_interface_id;
2342 MonoClass *k;
2343 GSList *extra_interfaces = NULL;
2344 MonoClass *klass = remote_class->proxy_class;
2345 gpointer *interface_offsets;
2346 uint8_t *bitmap = NULL;
2347 int bsize;
2348 size_t imt_table_bytes;
2349 gboolean use_interpreter = callbacks.is_interpreter_enabled ();
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2352 int bcsize;
2353 #endif
2355 error_init (error);
2357 vt = mono_class_vtable_checked (domain, klass, error);
2358 if (!is_ok (error))
2359 return NULL;
2360 max_interface_id = vt->max_interface_id;
2362 /* Calculate vtable space for extra interfaces */
2363 for (j = 0; j < remote_class->interface_count; j++) {
2364 MonoClass* iclass = remote_class->interfaces[j];
2365 GPtrArray *ifaces;
2366 int method_count;
2368 /*FIXME test for interfaces with variant generic arguments*/
2369 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (iclass)))
2370 continue; /* interface implemented by the class */
2371 if (g_slist_find (extra_interfaces, iclass))
2372 continue;
2374 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2376 method_count = mono_class_num_methods (iclass);
2378 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2379 goto_if_nok (error, failure);
2380 if (ifaces) {
2381 for (i = 0; i < ifaces->len; ++i) {
2382 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2383 /*FIXME test for interfaces with variant generic arguments*/
2384 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (ic)))
2385 continue; /* interface implemented by the class */
2386 if (g_slist_find (extra_interfaces, ic))
2387 continue;
2388 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2389 method_count += mono_class_num_methods (ic);
2391 g_ptr_array_free (ifaces, TRUE);
2392 ifaces = NULL;
2395 extra_interface_vtsize += method_count * sizeof (gpointer);
2396 if (m_class_get_max_interface_id (iclass) > max_interface_id) max_interface_id = m_class_get_max_interface_id (iclass);
2399 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2400 if (use_interpreter)
2401 imt_table_bytes *= 2;
2402 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2403 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2405 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + m_class_get_vtable_size (klass) * sizeof (gpointer);
2407 UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2409 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2410 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2411 g_assert (!((gsize)pvt & 7));
2413 if (use_interpreter)
2414 interface_offsets = (gpointer*)((char*)interface_offsets + imt_table_bytes / 2);
2416 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + m_class_get_vtable_size (klass) * sizeof (gpointer));
2418 pvt->interp_vtable = NULL;
2419 pvt->klass = mono_defaults.transparent_proxy_class;
2421 MONO_PROFILER_RAISE (vtable_loading, (pvt));
2423 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2424 pvt->gc_descr = m_class_get_gc_descr (mono_defaults.transparent_proxy_class);
2426 if (mono_remote_class_is_interface_proxy (remote_class)) {
2427 /* If it's a transparent proxy for an interface, set the
2428 * MonoVTable:type to the interface type, not the placeholder
2429 * MarshalByRefObject class. This is used when mini JITs calls
2430 * to Object.GetType ()
2432 MonoType *itf_proxy_type = m_class_get_byval_arg (remote_class->interfaces[0]);
2433 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2434 goto_if_nok (error, failure);
2437 /* initialize vtable */
2438 mono_class_setup_vtable (klass);
2439 MonoMethod **klass_vtable;
2440 klass_vtable = m_class_get_vtable (klass);
2441 for (i = 0; i < m_class_get_vtable_size (klass); ++i) {
2442 MonoMethod *cm;
2444 if ((cm = klass_vtable [i])) {
2445 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2446 goto_if_nok (error, failure);
2447 } else
2448 pvt->vtable [i] = NULL;
2451 if (mono_class_is_abstract (klass)) {
2452 /* create trampolines for abstract methods */
2453 for (k = klass; k; k = m_class_get_parent (k)) {
2454 MonoMethod* m;
2455 gpointer iter = NULL;
2456 while ((m = mono_class_get_methods (k, &iter)))
2457 if (!pvt->vtable [m->slot]) {
2458 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2459 goto_if_nok (error, failure);
2464 pvt->max_interface_id = max_interface_id;
2465 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2466 #ifdef COMPRESSED_INTERFACE_BITMAP
2467 bitmap = (uint8_t *)g_malloc0 (bsize);
2468 #else
2469 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2470 #endif
2472 for (i = 0; i < m_class_get_interface_offsets_count (klass); ++i) {
2473 int interface_id = m_class_get_interface_id (m_class_get_interfaces_packed (klass) [i]);
2474 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2477 if (extra_interfaces) {
2478 int slot = m_class_get_vtable_size (klass);
2479 MonoClass* interf;
2480 gpointer iter;
2481 MonoMethod* cm;
2482 GSList *list_item;
2484 /* Create trampolines for the methods of the interfaces */
2485 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2486 interf = (MonoClass *)list_item->data;
2488 guint32 interf_interface_id = m_class_get_interface_id (interf);
2489 bitmap [interf_interface_id >> 3] |= (1 << (interf_interface_id & 7));
2491 iter = NULL;
2492 j = 0;
2493 while ((cm = mono_class_get_methods (interf, &iter))) {
2494 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2495 goto_if_nok (error, failure);
2498 slot += mono_class_num_methods (interf);
2502 /* Now that the vtable is full, we can actually fill up the IMT */
2503 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2504 if (extra_interfaces) {
2505 g_slist_free (extra_interfaces);
2508 #ifdef COMPRESSED_INTERFACE_BITMAP
2509 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2510 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2511 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2512 g_free (bitmap);
2513 #else
2514 pvt->interface_bitmap = bitmap;
2515 #endif
2516 MONO_PROFILER_RAISE (vtable_loaded, (pvt));
2517 return pvt;
2518 failure:
2519 if (extra_interfaces)
2520 g_slist_free (extra_interfaces);
2521 #ifdef COMPRESSED_INTERFACE_BITMAP
2522 g_free (bitmap);
2523 #endif
2524 MONO_PROFILER_RAISE (vtable_failed, (pvt));
2525 return NULL;
2528 #endif /* DISABLE_REMOTING */
2531 * mono_class_field_is_special_static:
2532 * \returns whether \p field is a thread/context static field.
2534 gboolean
2535 mono_class_field_is_special_static (MonoClassField *field)
2537 MONO_REQ_GC_NEUTRAL_MODE
2539 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2540 return FALSE;
2541 if (mono_field_is_deleted (field))
2542 return FALSE;
2543 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2544 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2545 return TRUE;
2547 return FALSE;
2551 * mono_class_field_get_special_static_type:
2552 * \param field The \c MonoClassField describing the field.
2553 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2554 * \c SPECIAL_STATIC_NONE otherwise.
2556 guint32
2557 mono_class_field_get_special_static_type (MonoClassField *field)
2559 MONO_REQ_GC_NEUTRAL_MODE
2561 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2562 return SPECIAL_STATIC_NONE;
2563 if (mono_field_is_deleted (field))
2564 return SPECIAL_STATIC_NONE;
2565 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2566 return field_is_special_static (field->parent, field);
2567 return SPECIAL_STATIC_NONE;
2571 * mono_class_has_special_static_fields:
2572 * \returns whether \p klass has any thread/context static fields.
2574 gboolean
2575 mono_class_has_special_static_fields (MonoClass *klass)
2577 MONO_REQ_GC_NEUTRAL_MODE
2579 MonoClassField *field;
2580 gpointer iter;
2582 iter = NULL;
2583 while ((field = mono_class_get_fields_internal (klass, &iter))) {
2584 g_assert (field->parent == klass);
2585 if (mono_class_field_is_special_static (field))
2586 return TRUE;
2589 return FALSE;
2592 #ifndef DISABLE_REMOTING
2594 * create_remote_class_key:
2595 * Creates an array of pointers that can be used as a hash key for a remote class.
2596 * The first element of the array is the number of pointers.
2598 static gpointer*
2599 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2601 MONO_REQ_GC_NEUTRAL_MODE;
2603 gpointer *key;
2604 int i, j;
2606 if (remote_class == NULL) {
2607 if (mono_class_is_interface (extra_class)) {
2608 key = (void **)g_malloc (sizeof(gpointer) * 3);
2609 key [0] = GINT_TO_POINTER (2);
2610 key [1] = mono_defaults.marshalbyrefobject_class;
2611 key [2] = extra_class;
2612 } else {
2613 key = (void **)g_malloc (sizeof(gpointer) * 2);
2614 key [0] = GINT_TO_POINTER (1);
2615 key [1] = extra_class;
2617 } else {
2618 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2619 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2620 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2621 key [1] = remote_class->proxy_class;
2623 // Keep the list of interfaces sorted
2624 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2625 if (extra_class && remote_class->interfaces [i] > extra_class) {
2626 key [j++] = extra_class;
2627 extra_class = NULL;
2629 key [j] = remote_class->interfaces [i];
2631 if (extra_class)
2632 key [j] = extra_class;
2633 } else {
2634 // Replace the old class. The interface list is the same
2635 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2636 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2637 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2638 for (i = 0; i < remote_class->interface_count; i++)
2639 key [2 + i] = remote_class->interfaces [i];
2643 return key;
2647 * copy_remote_class_key:
2649 * Make a copy of KEY in the domain and return the copy.
2651 static gpointer*
2652 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2654 MONO_REQ_GC_NEUTRAL_MODE
2656 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2657 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2659 memcpy (mp_key, key, key_size);
2661 return mp_key;
2665 * mono_remote_class:
2666 * \param domain the application domain
2667 * \param class_name name of the remote class
2668 * \param error set on error
2669 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2670 * On failure returns NULL and sets \p error
2672 MonoRemoteClass*
2673 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2675 MONO_REQ_GC_UNSAFE_MODE;
2677 MonoRemoteClass *rc;
2678 gpointer* key, *mp_key;
2679 char *name;
2681 error_init (error);
2683 key = create_remote_class_key (NULL, proxy_class);
2685 mono_domain_lock (domain);
2686 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2688 if (rc) {
2689 g_free (key);
2690 mono_domain_unlock (domain);
2691 return rc;
2694 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2695 if (!is_ok (error)) {
2696 g_free (key);
2697 mono_domain_unlock (domain);
2698 return NULL;
2701 mp_key = copy_remote_class_key (domain, key);
2702 g_free (key);
2703 key = mp_key;
2705 if (mono_class_is_interface (proxy_class)) {
2706 /* If we need to proxy an interface, we use this stylized
2707 * representation (interface_count >= 1, proxy_class is
2708 * MarshalByRefObject). The code in
2709 * mono_remote_class_is_interface_proxy () depends on being
2710 * able to detect that we're doing this, so if this
2711 * representation changes, change GetType, too. */
2712 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2713 rc->interface_count = 1;
2714 rc->interfaces [0] = proxy_class;
2715 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2716 } else {
2717 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2718 rc->interface_count = 0;
2719 rc->proxy_class = proxy_class;
2722 rc->default_vtable = NULL;
2723 rc->xdomain_vtable = NULL;
2724 rc->proxy_class_name = name;
2725 #ifndef DISABLE_PERFCOUNTERS
2726 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, mono_string_length_internal (MONO_HANDLE_RAW (class_name)) + 1);
2727 #endif
2729 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2731 mono_domain_unlock (domain);
2732 return rc;
2736 * clone_remote_class:
2737 * Creates a copy of the remote_class, adding the provided class or interface
2739 static MonoRemoteClass*
2740 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2742 MONO_REQ_GC_NEUTRAL_MODE;
2744 MonoRemoteClass *rc;
2745 gpointer* key, *mp_key;
2747 key = create_remote_class_key (remote_class, extra_class);
2748 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2749 if (rc != NULL) {
2750 g_free (key);
2751 return rc;
2754 mp_key = copy_remote_class_key (domain, key);
2755 g_free (key);
2756 key = mp_key;
2758 if (mono_class_is_interface (extra_class)) {
2759 int i,j;
2760 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2761 rc->proxy_class = remote_class->proxy_class;
2762 rc->interface_count = remote_class->interface_count + 1;
2764 // Keep the list of interfaces sorted, since the hash key of
2765 // the remote class depends on this
2766 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2767 if (remote_class->interfaces [i] > extra_class && i == j)
2768 rc->interfaces [j++] = extra_class;
2769 rc->interfaces [j] = remote_class->interfaces [i];
2771 if (i == j)
2772 rc->interfaces [j] = extra_class;
2773 } else {
2774 // Replace the old class. The interface array is the same
2775 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2776 rc->proxy_class = extra_class;
2777 rc->interface_count = remote_class->interface_count;
2778 if (rc->interface_count > 0)
2779 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2782 rc->default_vtable = NULL;
2783 rc->xdomain_vtable = NULL;
2784 rc->proxy_class_name = remote_class->proxy_class_name;
2786 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2788 return rc;
2791 gpointer
2792 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2794 MONO_REQ_GC_UNSAFE_MODE;
2796 gpointer result = NULL;
2797 error_init (error);
2799 mono_loader_lock (); /*FIXME mono_class_from_mono_type_internal and mono_class_proxy_vtable take it*/
2800 mono_domain_lock (domain);
2801 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2802 if (target_domain_id != -1) {
2803 if (remote_class->xdomain_vtable == NULL)
2804 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2805 goto_if_nok (error, leave);
2806 result = remote_class->xdomain_vtable;
2807 goto leave;
2809 if (remote_class->default_vtable == NULL) {
2810 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2811 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2813 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2814 MonoClass *klass = mono_class_from_mono_type_internal (type);
2815 #ifndef DISABLE_COM
2816 gboolean target_is_com = FALSE;
2817 if (mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) {
2818 MonoVTable *klass_vtable = mono_class_vtable_checked (mono_domain_get (), klass, error);
2819 goto_if_nok (error, leave);
2820 if (!mono_vtable_is_remote (klass_vtable))
2821 target_is_com = TRUE;
2823 if (target_is_com)
2824 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2825 else
2826 #endif
2827 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2828 /* N.B. both branches of the if modify error */
2829 goto_if_nok (error, leave);
2833 result = remote_class->default_vtable;
2834 leave:
2835 mono_domain_unlock (domain);
2836 mono_loader_unlock ();
2837 return result;
2841 * mono_upgrade_remote_class:
2842 * \param domain the application domain
2843 * \param tproxy the proxy whose remote class has to be upgraded.
2844 * \param klass class to which the remote class can be casted.
2845 * \param error set on error
2846 * Updates the vtable of the remote class by adding the necessary method slots
2847 * and interface offsets so it can be safely casted to klass. klass can be a
2848 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2850 gboolean
2851 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2853 MONO_REQ_GC_UNSAFE_MODE;
2855 error_init (error);
2857 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2858 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2860 gboolean redo_vtable;
2861 if (mono_class_is_interface (klass)) {
2862 int i;
2863 redo_vtable = TRUE;
2864 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2865 if (remote_class->interfaces [i] == klass)
2866 redo_vtable = FALSE;
2868 else {
2869 redo_vtable = (remote_class->proxy_class != klass);
2872 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2873 mono_domain_lock (domain);
2874 if (redo_vtable) {
2875 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2876 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2877 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2878 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2879 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, (MonoVTable*)mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2880 goto_if_nok (error, leave);
2883 leave:
2884 mono_domain_unlock (domain);
2885 mono_loader_unlock ();
2886 return is_ok (error);
2888 #endif /* DISABLE_REMOTING */
2890 MonoMethod*
2891 mono_object_get_virtual_method_internal (MonoObject *obj_raw, MonoMethod *method)
2893 HANDLE_FUNCTION_ENTER ();
2894 MonoMethod *result;
2895 ERROR_DECL (error);
2896 MONO_HANDLE_DCL (MonoObject, obj);
2897 result = mono_object_handle_get_virtual_method (obj, method, error);
2898 mono_error_assert_ok (error);
2899 HANDLE_FUNCTION_RETURN_VAL (result);
2903 * mono_object_get_virtual_method:
2904 * \param obj object to operate on.
2905 * \param method method
2906 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2907 * the instance of a callvirt of \p method.
2909 MonoMethod*
2910 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2912 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoMethod*, mono_object_get_virtual_method_internal (obj, method));
2916 * mono_object_handle_get_virtual_method:
2917 * \param obj object to operate on.
2918 * \param method method
2919 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2920 * the instance of a callvirt of \p method.
2922 MonoMethod*
2923 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2925 error_init (error);
2927 gboolean is_proxy = FALSE;
2928 MonoClass *klass = mono_handle_class (obj);
2929 if (mono_class_is_transparent_proxy (klass)) {
2930 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2931 klass = remote_class->proxy_class;
2932 is_proxy = TRUE;
2934 return mono_class_get_virtual_method (klass, method, is_proxy, error);
2937 MonoMethod*
2938 mono_class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2940 MONO_REQ_GC_NEUTRAL_MODE;
2941 error_init (error);
2943 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2944 return method;
2946 mono_class_setup_vtable (klass);
2947 MonoMethod **vtable = m_class_get_vtable (klass);
2949 if (method->slot == -1) {
2950 /* method->slot might not be set for instances of generic methods */
2951 if (method->is_inflated) {
2952 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2953 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2954 } else {
2955 if (!is_proxy)
2956 g_assert_not_reached ();
2960 MonoMethod *res = NULL;
2961 /* check method->slot is a valid index: perform isinstance? */
2962 if (method->slot != -1) {
2963 if (mono_class_is_interface (method->klass)) {
2964 if (!is_proxy) {
2965 gboolean variance_used = FALSE;
2966 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2967 g_assert (iface_offset > 0);
2968 res = vtable [iface_offset + method->slot];
2970 } else {
2971 res = vtable [method->slot];
2975 #ifndef DISABLE_REMOTING
2976 if (is_proxy) {
2977 /* It may be an interface, abstract class method or generic method */
2978 if (!res || mono_method_signature_internal (res)->generic_param_count)
2979 res = method;
2981 /* generic methods demand invoke_with_check */
2982 if (mono_method_signature_internal (res)->generic_param_count)
2983 res = mono_marshal_get_remoting_invoke_with_check (res, error);
2984 else {
2985 #ifndef DISABLE_COM
2986 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2987 res = mono_cominterop_get_invoke (res);
2988 else
2989 #endif
2990 res = mono_marshal_get_remoting_invoke (res, error);
2992 } else
2993 #endif
2995 if (method->is_inflated) {
2996 /* Have to inflate the result */
2997 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
3001 return res;
3004 static MonoObject*
3005 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
3007 MONO_REQ_GC_UNSAFE_MODE;
3009 MonoObject *result = NULL;
3011 g_assert (callbacks.runtime_invoke);
3013 error_init (error);
3015 MONO_PROFILER_RAISE (method_begin_invoke, (method));
3017 result = callbacks.runtime_invoke (method, obj, params, exc, error);
3019 MONO_PROFILER_RAISE (method_end_invoke, (method));
3021 if (!is_ok (error))
3022 return NULL;
3024 return result;
3028 * mono_runtime_invoke:
3029 * \param method method to invoke
3030 * \param obj object instance
3031 * \param params arguments to the method
3032 * \param exc exception information.
3033 * Invokes the method represented by \p method on the object \p obj.
3034 * \p obj is the \c this pointer, it should be NULL for static
3035 * methods, a \c MonoObject* for object instances and a pointer to
3036 * the value type for value types.
3038 * The params array contains the arguments to the method with the
3039 * same convention: \c MonoObject* pointers for object instances and
3040 * pointers to the value type otherwise.
3042 * From unmanaged code you'll usually use the
3043 * \c mono_runtime_invoke variant.
3045 * Note that this function doesn't handle virtual methods for
3046 * you, it will exec the exact method you pass: we still need to
3047 * expose a function to lookup the derived class implementation
3048 * of a virtual method (there are examples of this in the code,
3049 * though).
3051 * You can pass NULL as the \p exc argument if you don't want to
3052 * catch exceptions, otherwise, \c *exc will be set to the exception
3053 * thrown, if any. if an exception is thrown, you can't use the
3054 * \c MonoObject* result from the function.
3056 * If the method returns a value type, it is boxed in an object
3057 * reference.
3059 MonoObject*
3060 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
3062 MonoObject *res;
3063 MONO_ENTER_GC_UNSAFE;
3064 ERROR_DECL (error);
3065 if (exc) {
3066 res = mono_runtime_try_invoke (method, obj, params, exc, error);
3067 if (*exc == NULL && !is_ok(error)) {
3068 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3069 } else
3070 mono_error_cleanup (error);
3071 } else {
3072 res = mono_runtime_invoke_checked (method, obj, params, error);
3073 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
3075 MONO_EXIT_GC_UNSAFE;
3076 return res;
3080 * mono_runtime_try_invoke:
3081 * \param method method to invoke
3082 * \param obj object instance
3083 * \param params arguments to the method
3084 * \param exc exception information.
3085 * \param error set on error
3086 * Invokes the method represented by \p method on the object \p obj.
3088 * \p obj is the \c this pointer, it should be NULL for static
3089 * methods, a \c MonoObject* for object instances and a pointer to
3090 * the value type for value types.
3092 * The params array contains the arguments to the method with the
3093 * same convention: \c MonoObject* pointers for object instances and
3094 * pointers to the value type otherwise.
3096 * From unmanaged code you'll usually use the
3097 * mono_runtime_invoke() variant.
3099 * Note that this function doesn't handle virtual methods for
3100 * you, it will exec the exact method you pass: we still need to
3101 * expose a function to lookup the derived class implementation
3102 * of a virtual method (there are examples of this in the code,
3103 * though).
3105 * For this function, you must not pass NULL as the \p exc argument if
3106 * you don't want to catch exceptions, use
3107 * mono_runtime_invoke_checked(). If an exception is thrown, you
3108 * can't use the \c MonoObject* result from the function.
3110 * If this method cannot be invoked, \p error will be set and \p exc and
3111 * the return value must not be used.
3113 * If the method returns a value type, it is boxed in an object
3114 * reference.
3116 MonoObject*
3117 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3119 MONO_REQ_GC_UNSAFE_MODE;
3121 g_assert (exc != NULL);
3123 if (mono_runtime_get_no_exec ())
3124 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3126 return do_runtime_invoke (method, obj, params, exc, error);
3129 MonoObjectHandle
3130 mono_runtime_try_invoke_handle (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3132 // FIXME? typing of params
3133 MonoException *exc = NULL;
3134 MonoObject *obj_raw = mono_runtime_try_invoke (method, MONO_HANDLE_RAW (obj), params, (MonoObject**)&exc, error);
3136 if (exc && is_ok (error))
3137 mono_error_set_exception_instance (error, exc);
3139 return MONO_HANDLE_NEW (MonoObject, obj_raw);
3143 * mono_runtime_invoke_checked:
3144 * \param method method to invoke
3145 * \param obj object instance
3146 * \param params arguments to the method
3147 * \param error set on error
3148 * Invokes the method represented by \p method on the object \p obj.
3150 * \p obj is the \c this pointer, it should be NULL for static
3151 * methods, a \c MonoObject* for object instances and a pointer to
3152 * the value type for value types.
3154 * The \p params array contains the arguments to the method with the
3155 * same convention: \c MonoObject* pointers for object instances and
3156 * pointers to the value type otherwise.
3158 * From unmanaged code you'll usually use the
3159 * mono_runtime_invoke() variant.
3161 * Note that this function doesn't handle virtual methods for
3162 * you, it will exec the exact method you pass: we still need to
3163 * expose a function to lookup the derived class implementation
3164 * of a virtual method (there are examples of this in the code,
3165 * though).
3167 * If an exception is thrown, you can't use the \c MonoObject* result
3168 * from the function.
3170 * If this method cannot be invoked, \p error will be set. If the
3171 * method throws an exception (and we're in coop mode) the exception
3172 * will be set in \p error.
3174 * If the method returns a value type, it is boxed in an object
3175 * reference.
3177 MonoObject*
3178 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3180 MONO_REQ_GC_UNSAFE_MODE;
3182 if (mono_runtime_get_no_exec ())
3183 g_error ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3185 return do_runtime_invoke (method, obj, params, NULL, error);
3188 MonoObjectHandle
3189 mono_runtime_invoke_handle (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3191 return MONO_HANDLE_NEW (MonoObject, mono_runtime_invoke_checked (method, MONO_HANDLE_RAW (obj), params, error));
3194 void
3195 mono_runtime_invoke_handle_void (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error)
3197 mono_runtime_invoke_checked (method, MONO_HANDLE_RAW (obj), params, error);
3201 * mono_method_get_unmanaged_thunk:
3202 * \param method method to generate a thunk for.
3204 * Returns an \c unmanaged->managed thunk that can be used to call
3205 * a managed method directly from C.
3207 * The thunk's C signature closely matches the managed signature:
3209 * C#: <code>public bool Equals (object obj);</code>
3211 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3213 * The 1st (<code>this</code>) parameter must not be used with static methods:
3215 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3217 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3219 * The last argument must be a non-null \c MonoException* pointer.
3220 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3221 * exception has been thrown in managed code. Otherwise it will point
3222 * to the \c MonoException* caught by the thunk. In this case, the result of
3223 * the thunk is undefined:
3225 * <pre>
3226 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3228 * MonoException *ex = NULL;
3230 * Equals func = mono_method_get_unmanaged_thunk (method);
3232 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3234 * if (ex) {
3236 * // handle exception
3239 * </pre>
3241 * The calling convention of the thunk matches the platform's default
3242 * convention. This means that under Windows, C declarations must
3243 * contain the \c __stdcall attribute:
3245 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3247 * LIMITATIONS
3249 * Value type arguments and return values are treated as they were objects:
3251 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3252 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3254 * Arguments must be properly boxed upon trunk's invocation, while return
3255 * values must be unboxed.
3257 gpointer
3258 mono_method_get_unmanaged_thunk (MonoMethod *method)
3260 MONO_REQ_GC_NEUTRAL_MODE;
3261 MONO_REQ_API_ENTRYPOINT;
3263 ERROR_DECL (error);
3264 gpointer res;
3266 MONO_ENTER_GC_UNSAFE;
3267 method = mono_marshal_get_thunk_invoke_wrapper (method);
3268 res = mono_compile_method_checked (method, error);
3269 mono_error_cleanup (error);
3270 MONO_EXIT_GC_UNSAFE;
3272 return res;
3275 void
3276 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3278 MONO_REQ_GC_UNSAFE_MODE;
3280 int t;
3281 if (type->byref) {
3282 /* object fields cannot be byref, so we don't need a
3283 wbarrier here */
3284 gpointer *p = (gpointer*)dest;
3285 *p = value;
3286 return;
3288 t = type->type;
3289 handle_enum:
3290 switch (t) {
3291 case MONO_TYPE_BOOLEAN:
3292 case MONO_TYPE_I1:
3293 case MONO_TYPE_U1: {
3294 guint8 *p = (guint8*)dest;
3295 *p = value ? *(guint8*)value : 0;
3296 return;
3298 case MONO_TYPE_I2:
3299 case MONO_TYPE_U2:
3300 case MONO_TYPE_CHAR: {
3301 guint16 *p = (guint16*)dest;
3302 *p = value ? *(guint16*)value : 0;
3303 return;
3305 #if SIZEOF_VOID_P == 4
3306 case MONO_TYPE_I:
3307 case MONO_TYPE_U:
3308 #endif
3309 case MONO_TYPE_I4:
3310 case MONO_TYPE_U4: {
3311 gint32 *p = (gint32*)dest;
3312 *p = value ? *(gint32*)value : 0;
3313 return;
3315 #if SIZEOF_VOID_P == 8
3316 case MONO_TYPE_I:
3317 case MONO_TYPE_U:
3318 #endif
3319 case MONO_TYPE_I8:
3320 case MONO_TYPE_U8: {
3321 gint64 *p = (gint64*)dest;
3322 *p = value ? *(gint64*)value : 0;
3323 return;
3325 case MONO_TYPE_R4: {
3326 float *p = (float*)dest;
3327 *p = value ? *(float*)value : 0;
3328 return;
3330 case MONO_TYPE_R8: {
3331 double *p = (double*)dest;
3332 *p = value ? *(double*)value : 0;
3333 return;
3335 case MONO_TYPE_STRING:
3336 case MONO_TYPE_SZARRAY:
3337 case MONO_TYPE_CLASS:
3338 case MONO_TYPE_OBJECT:
3339 case MONO_TYPE_ARRAY:
3340 mono_gc_wbarrier_generic_store_internal (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3341 return;
3342 case MONO_TYPE_FNPTR:
3343 case MONO_TYPE_PTR: {
3344 gpointer *p = (gpointer*)dest;
3345 *p = deref_pointer? *(gpointer*)value: value;
3346 return;
3348 case MONO_TYPE_VALUETYPE:
3349 /* note that 't' and 'type->type' can be different */
3350 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass)) {
3351 t = mono_class_enum_basetype_internal (type->data.klass)->type;
3352 goto handle_enum;
3353 } else {
3354 MonoClass *klass = mono_class_from_mono_type_internal (type);
3355 int size = mono_class_value_size (klass, NULL);
3356 if (value == NULL)
3357 mono_gc_bzero_atomic (dest, size);
3358 else
3359 mono_gc_wbarrier_value_copy_internal (dest, value, 1, klass);
3361 return;
3362 case MONO_TYPE_GENERICINST:
3363 t = m_class_get_byval_arg (type->data.generic_class->container_class)->type;
3364 goto handle_enum;
3365 default:
3366 g_error ("got type %x", type->type);
3370 void
3371 mono_field_set_value_internal (MonoObject *obj, MonoClassField *field, void *value)
3373 void *dest;
3375 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3376 return;
3378 dest = (char*)obj + field->offset;
3379 #if ENABLE_NETCORE
3380 mono_copy_value (field->type, dest, value, value && field->type->type == MONO_TYPE_PTR);
3381 #else
3382 mono_copy_value (field->type, dest, value, FALSE);
3383 #endif
3387 * mono_field_set_value:
3388 * \param obj Instance object
3389 * \param field \c MonoClassField describing the field to set
3390 * \param value The value to be set
3392 * Sets the value of the field described by \p field in the object instance \p obj
3393 * to the value passed in \p value. This method should only be used for instance
3394 * fields. For static fields, use \c mono_field_static_set_value.
3396 * The value must be in the native format of the field type.
3398 void
3399 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3401 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_set_value_internal (obj, field, value));
3404 void
3405 mono_field_static_set_value_internal (MonoVTable *vt, MonoClassField *field, void *value)
3407 void *dest;
3409 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC) == 0)
3410 return;
3411 /* you cant set a constant! */
3412 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
3413 return;
3415 if (field->offset == -1) {
3416 /* Special static */
3417 gpointer addr;
3419 mono_domain_lock (vt->domain);
3420 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3421 mono_domain_unlock (vt->domain);
3422 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3423 } else {
3424 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3426 mono_copy_value (field->type, dest, value, FALSE);
3430 * mono_field_static_set_value:
3431 * \param field \c MonoClassField describing the field to set
3432 * \param value The value to be set
3433 * Sets the value of the static field described by \p field
3434 * to the value passed in \p value.
3435 * The value must be in the native format of the field type.
3437 void
3438 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3440 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_static_set_value_internal (vt, field, value));
3444 * mono_vtable_get_static_field_data:
3446 * Internal use function: return a pointer to the memory holding the static fields
3447 * for a class or NULL if there are no static fields.
3448 * This is exported only for use by the debugger.
3450 void *
3451 mono_vtable_get_static_field_data (MonoVTable *vt)
3453 MONO_REQ_GC_NEUTRAL_MODE
3455 if (!vt->has_static_fields)
3456 return NULL;
3457 return vt->vtable [m_class_get_vtable_size (vt->klass)];
3460 static guint8*
3461 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3463 MONO_REQ_GC_UNSAFE_MODE;
3465 guint8 *src;
3467 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3468 if (field->offset == -1) {
3469 /* Special static */
3470 gpointer addr;
3472 mono_domain_lock (vt->domain);
3473 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3474 mono_domain_unlock (vt->domain);
3475 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3476 } else {
3477 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3479 } else {
3480 src = (guint8*)obj + field->offset;
3483 return src;
3487 * mono_field_get_value:
3488 * \param obj Object instance
3489 * \param field \c MonoClassField describing the field to fetch information from
3490 * \param value pointer to the location where the value will be stored
3491 * Use this routine to get the value of the field \p field in the object
3492 * passed.
3494 * The pointer provided by value must be of the field type, for reference
3495 * types this is a \c MonoObject*, for value types its the actual pointer to
3496 * the value type.
3498 * For example:
3500 * <pre>
3501 * int i;
3503 * mono_field_get_value (obj, int_field, &i);
3504 * </pre>
3506 void
3507 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3509 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_get_value_internal (obj, field, value));
3512 void
3513 mono_field_get_value_internal (MonoObject *obj, MonoClassField *field, void *value)
3515 MONO_REQ_GC_UNSAFE_MODE;
3517 void *src;
3519 g_assert (obj);
3521 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3523 src = (char*)obj + field->offset;
3524 mono_copy_value (field->type, value, src, TRUE);
3528 * mono_field_get_value_object:
3529 * \param domain domain where the object will be created (if boxing)
3530 * \param field \c MonoClassField describing the field to fetch information from
3531 * \param obj The object instance for the field.
3532 * \returns a new \c MonoObject with the value from the given field. If the
3533 * field represents a value type, the value is boxed.
3535 MonoObject *
3536 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3538 MonoObject* result;
3539 MONO_ENTER_GC_UNSAFE;
3540 ERROR_DECL (error);
3541 result = mono_field_get_value_object_checked (domain, field, obj, error);
3542 mono_error_assert_ok (error);
3543 MONO_EXIT_GC_UNSAFE;
3544 return result;
3548 * mono_static_field_get_value_handle:
3549 * \param domain domain where the object will be created (if boxing)
3550 * \param field \c MonoClassField describing the field to fetch information from
3551 * \param obj The object instance for the field.
3552 * \returns a new \c MonoObject with the value from the given field. If the
3553 * field represents a value type, the value is boxed.
3555 MonoObjectHandle
3556 mono_static_field_get_value_handle (MonoDomain *domain, MonoClassField *field, MonoError *error)
3557 // FIXMEcoop invert
3559 HANDLE_FUNCTION_ENTER ();
3560 HANDLE_FUNCTION_RETURN_REF (MonoObject, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (domain, field, NULL, error)));
3564 * mono_field_get_value_object_checked:
3565 * \param domain domain where the object will be created (if boxing)
3566 * \param field \c MonoClassField describing the field to fetch information from
3567 * \param obj The object instance for the field.
3568 * \param error Set on error.
3569 * \returns a new \c MonoObject with the value from the given field. If the
3570 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3572 MonoObject *
3573 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3575 MONO_REQ_GC_UNSAFE_MODE;
3577 error_init (error);
3579 MonoObject *o = NULL;
3580 MonoClass *klass;
3581 MonoVTable *vtable = NULL;
3582 gpointer v;
3583 gboolean is_static = FALSE;
3584 gboolean is_ref = FALSE;
3585 gboolean is_literal = FALSE;
3586 gboolean is_ptr = FALSE;
3587 MonoType *type = mono_field_get_type_checked (field, error);
3589 return_val_if_nok (error, NULL);
3591 switch (type->type) {
3592 case MONO_TYPE_STRING:
3593 case MONO_TYPE_OBJECT:
3594 case MONO_TYPE_CLASS:
3595 case MONO_TYPE_ARRAY:
3596 case MONO_TYPE_SZARRAY:
3597 is_ref = TRUE;
3598 break;
3599 case MONO_TYPE_U1:
3600 case MONO_TYPE_I1:
3601 case MONO_TYPE_BOOLEAN:
3602 case MONO_TYPE_U2:
3603 case MONO_TYPE_I2:
3604 case MONO_TYPE_CHAR:
3605 case MONO_TYPE_U:
3606 case MONO_TYPE_I:
3607 case MONO_TYPE_U4:
3608 case MONO_TYPE_I4:
3609 case MONO_TYPE_R4:
3610 case MONO_TYPE_U8:
3611 case MONO_TYPE_I8:
3612 case MONO_TYPE_R8:
3613 case MONO_TYPE_VALUETYPE:
3614 is_ref = type->byref;
3615 break;
3616 case MONO_TYPE_GENERICINST:
3617 is_ref = !mono_type_generic_inst_is_valuetype (type);
3618 break;
3619 case MONO_TYPE_PTR:
3620 is_ptr = TRUE;
3621 break;
3622 default:
3623 g_error ("type 0x%x not handled in "
3624 "mono_field_get_value_object", type->type);
3625 return NULL;
3628 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3629 is_literal = TRUE;
3631 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3632 is_static = TRUE;
3634 if (!is_literal) {
3635 vtable = mono_class_vtable_checked (domain, field->parent, error);
3636 return_val_if_nok (error, NULL);
3638 if (!vtable->initialized) {
3639 mono_runtime_class_init_full (vtable, error);
3640 return_val_if_nok (error, NULL);
3643 } else {
3644 g_assert (obj);
3647 if (is_ref) {
3648 if (is_literal) {
3649 get_default_field_value (domain, field, &o, error);
3650 return_val_if_nok (error, NULL);
3651 } else if (is_static) {
3652 mono_field_static_get_value_checked (vtable, field, &o, error);
3653 return_val_if_nok (error, NULL);
3654 } else {
3655 mono_field_get_value_internal (obj, field, &o);
3657 return o;
3660 if (is_ptr) {
3661 static MonoMethod *m;
3662 gpointer args [2];
3663 gpointer *ptr;
3665 if (!m) {
3666 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3667 m = mono_class_get_method_from_name_checked (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC, error);
3668 return_val_if_nok (error, NULL);
3669 g_assert (m);
3672 v = &ptr;
3673 if (is_literal) {
3674 get_default_field_value (domain, field, v, error);
3675 return_val_if_nok (error, NULL);
3676 } else if (is_static) {
3677 mono_field_static_get_value_checked (vtable, field, v, error);
3678 return_val_if_nok (error, NULL);
3679 } else {
3680 mono_field_get_value_internal (obj, field, v);
3683 #if ENABLE_NETCORE
3684 args [0] = ptr;
3685 #else
3686 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3687 args [0] = ptr ? *ptr : NULL;
3688 #endif
3689 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3690 return_val_if_nok (error, NULL);
3692 o = mono_runtime_invoke_checked (m, NULL, args, error);
3693 return_val_if_nok (error, NULL);
3695 return o;
3698 /* boxed value type */
3699 klass = mono_class_from_mono_type_internal (type);
3701 if (mono_class_is_nullable (klass))
3702 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3704 o = mono_object_new_checked (domain, klass, error);
3705 return_val_if_nok (error, NULL);
3706 v = mono_object_get_data (o);
3708 if (is_literal) {
3709 get_default_field_value (domain, field, v, error);
3710 return_val_if_nok (error, NULL);
3711 } else if (is_static) {
3712 mono_field_static_get_value_checked (vtable, field, v, error);
3713 return_val_if_nok (error, NULL);
3714 } else {
3715 mono_field_get_value_internal (obj, field, v);
3718 return o;
3722 * Important detail, if type is MONO_TYPE_STRING we return a blob encoded string (ie, utf16 + leb128 prefixed size)
3724 gboolean
3725 mono_metadata_read_constant_value (const char *blob, MonoTypeEnum type, void *value, MonoError *error)
3728 error_init (error);
3729 gboolean retval = TRUE;
3730 const char *p = blob;
3731 mono_metadata_decode_blob_size (p, &p);
3733 switch (type) {
3734 case MONO_TYPE_BOOLEAN:
3735 case MONO_TYPE_U1:
3736 case MONO_TYPE_I1:
3737 *(guint8 *) value = *p;
3738 break;
3739 case MONO_TYPE_CHAR:
3740 case MONO_TYPE_U2:
3741 case MONO_TYPE_I2:
3742 *(guint16*) value = read16 (p);
3743 break;
3744 case MONO_TYPE_U4:
3745 case MONO_TYPE_I4:
3746 *(guint32*) value = read32 (p);
3747 break;
3748 case MONO_TYPE_U8:
3749 case MONO_TYPE_I8:
3750 *(guint64*) value = read64 (p);
3751 break;
3752 case MONO_TYPE_R4:
3753 readr4 (p, (float*) value);
3754 break;
3755 case MONO_TYPE_R8:
3756 readr8 (p, (double*) value);
3757 break;
3758 case MONO_TYPE_STRING:
3759 *(const char**) value = blob;
3760 break;
3761 case MONO_TYPE_CLASS:
3762 *(gpointer*) value = NULL;
3763 break;
3764 default:
3765 retval = FALSE;
3766 mono_error_set_execution_engine (error, "Type 0x%02x should not be in constant table", type);
3768 return retval;
3772 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3774 MONO_REQ_GC_UNSAFE_MODE
3776 HANDLE_FUNCTION_ENTER ();
3778 int result = -1;
3780 if (!mono_metadata_read_constant_value (blob, type, value, error))
3781 goto exit;
3783 if (type == MONO_TYPE_STRING) {
3784 // FIXMEcoop
3785 *(gpointer*)value = MONO_HANDLE_RAW (mono_ldstr_metadata_sig (domain, *(const char**)value, error));
3788 result = 0;
3789 exit:
3790 HANDLE_FUNCTION_RETURN_VAL (result);
3793 static void
3794 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3796 MONO_REQ_GC_NEUTRAL_MODE;
3798 MonoTypeEnum def_type;
3799 const char* data;
3801 error_init (error);
3803 data = mono_class_get_field_default_value (field, &def_type);
3804 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3807 void
3808 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3810 MONO_REQ_GC_UNSAFE_MODE;
3812 void *src;
3814 error_init (error);
3816 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3818 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3819 get_default_field_value (vt->domain, field, value, error);
3820 return;
3823 if (field->offset == -1) {
3824 /* Special static */
3825 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3826 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3827 } else {
3828 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3830 mono_copy_value (field->type, value, src, TRUE);
3834 * mono_field_static_get_value:
3835 * \param vt vtable to the object
3836 * \param field \c MonoClassField describing the field to fetch information from
3837 * \param value where the value is returned
3838 * Use this routine to get the value of the static field \p field value.
3840 * The pointer provided by value must be of the field type, for reference
3841 * types this is a \c MonoObject*, for value types its the actual pointer to
3842 * the value type.
3844 * For example:
3846 * <pre>
3847 * int i;
3849 * mono_field_static_get_value (vt, int_field, &i);
3850 * </pre>
3852 void
3853 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3855 MONO_REQ_GC_NEUTRAL_MODE;
3857 ERROR_DECL (error);
3858 mono_field_static_get_value_checked (vt, field, value, error);
3859 mono_error_cleanup (error);
3863 * mono_field_static_get_value_checked:
3864 * \param vt vtable to the object
3865 * \param field \c MonoClassField describing the field to fetch information from
3866 * \param value where the value is returned
3867 * \param error set on error
3868 * Use this routine to get the value of the static field \p field value.
3870 * The pointer provided by value must be of the field type, for reference
3871 * types this is a \c MonoObject*, for value types its the actual pointer to
3872 * the value type.
3874 * For example:
3875 * int i;
3876 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3877 * if (!is_ok (error)) { ... }
3879 * On failure sets \p error.
3881 void
3882 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3884 MONO_REQ_GC_NEUTRAL_MODE;
3886 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3890 * mono_property_set_value:
3891 * \param prop MonoProperty to set
3892 * \param obj instance object on which to act
3893 * \param params parameters to pass to the propery
3894 * \param exc optional exception
3895 * Invokes the property's set method with the given arguments on the
3896 * object instance obj (or NULL for static properties).
3898 * You can pass NULL as the exc argument if you don't want to
3899 * catch exceptions, otherwise, \c *exc will be set to the exception
3900 * thrown, if any. if an exception is thrown, you can't use the
3901 * \c MonoObject* result from the function.
3903 void
3904 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3906 MONO_ENTER_GC_UNSAFE;
3908 ERROR_DECL (error);
3909 do_runtime_invoke (prop->set, obj, params, exc, error);
3910 if (exc && *exc == NULL && !is_ok (error)) {
3911 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3912 } else {
3913 mono_error_cleanup (error);
3915 MONO_EXIT_GC_UNSAFE;
3919 * mono_property_set_value_handle:
3920 * \param prop \c MonoProperty to set
3921 * \param obj instance object on which to act
3922 * \param params parameters to pass to the propery
3923 * \param error set on error
3924 * Invokes the property's set method with the given arguments on the
3925 * object instance \p obj (or NULL for static properties).
3926 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3927 * If an exception is thrown, it will be caught and returned via \p error.
3929 gboolean
3930 mono_property_set_value_handle (MonoProperty *prop, MonoObjectHandle obj, void **params, MonoError *error)
3932 MONO_REQ_GC_UNSAFE_MODE;
3934 MonoObject *exc;
3936 error_init (error);
3937 do_runtime_invoke (prop->set, MONO_HANDLE_RAW (obj), params, &exc, error);
3938 if (exc != NULL && is_ok (error))
3939 mono_error_set_exception_instance (error, (MonoException*)exc);
3940 return is_ok (error);
3944 * mono_property_get_value:
3945 * \param prop \c MonoProperty to fetch
3946 * \param obj instance object on which to act
3947 * \param params parameters to pass to the propery
3948 * \param exc optional exception
3949 * Invokes the property's \c get method with the given arguments on the
3950 * object instance \p obj (or NULL for static properties).
3952 * You can pass NULL as the \p exc argument if you don't want to
3953 * catch exceptions, otherwise, \c *exc will be set to the exception
3954 * thrown, if any. if an exception is thrown, you can't use the
3955 * \c MonoObject* result from the function.
3957 * \returns the value from invoking the \c get method on the property.
3959 MonoObject*
3960 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3962 MonoObject *val;
3963 MONO_ENTER_GC_UNSAFE;
3965 ERROR_DECL (error);
3966 val = do_runtime_invoke (prop->get, obj, params, exc, error);
3967 if (exc && *exc == NULL && !is_ok (error)) {
3968 *exc = (MonoObject*) mono_error_convert_to_exception (error);
3969 } else {
3970 mono_error_cleanup (error); /* FIXME don't raise here */
3972 MONO_EXIT_GC_UNSAFE;
3973 return val;
3977 * mono_property_get_value_checked:
3978 * \param prop \c MonoProperty to fetch
3979 * \param obj instance object on which to act
3980 * \param params parameters to pass to the propery
3981 * \param error set on error
3982 * Invokes the property's \c get method with the given arguments on the
3983 * object instance obj (or NULL for static properties).
3985 * If an exception is thrown, you can't use the
3986 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3988 * \returns the value from invoking the get method on the property. On
3989 * failure returns NULL and sets \p error.
3991 MonoObject*
3992 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3994 MONO_REQ_GC_UNSAFE_MODE;
3996 MonoObject *exc;
3997 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3998 if (exc != NULL && !is_ok (error))
3999 mono_error_set_exception_instance (error, (MonoException*) exc);
4000 if (!is_ok (error))
4001 val = NULL;
4002 return val;
4005 static MonoClassField*
4006 nullable_class_get_value_field (MonoClass *klass)
4008 mono_class_setup_fields (klass);
4009 g_assert (m_class_is_fields_inited (klass));
4011 MonoClassField *klass_fields = m_class_get_fields (klass);
4012 return &klass_fields [1];
4015 static MonoClassField*
4016 nullable_class_get_has_value_field (MonoClass *klass)
4018 mono_class_setup_fields (klass);
4019 g_assert (m_class_is_fields_inited (klass));
4021 MonoClassField *klass_fields = m_class_get_fields (klass);
4022 return &klass_fields [0];
4025 static gpointer
4026 nullable_get_has_value_field_addr (guint8 *nullable, MonoClass *klass)
4028 MonoClassField *has_value_field = nullable_class_get_has_value_field (klass);
4030 return mono_vtype_get_field_addr (nullable, has_value_field);
4033 static gpointer
4034 nullable_get_value_field_addr (guint8 *nullable, MonoClass *klass)
4036 MonoClassField *has_value_field = nullable_class_get_value_field (klass);
4038 return mono_vtype_get_field_addr (nullable, has_value_field);
4042 * mono_nullable_init:
4043 * @buf: The nullable structure to initialize.
4044 * @value: the value to initialize from
4045 * @klass: the type for the object
4047 * Initialize the nullable structure pointed to by @buf from @value which
4048 * should be a boxed value type. The size of @buf should be able to hold
4049 * as much data as the @klass->instance_size (which is the number of bytes
4050 * that will be copies).
4052 * Since Nullables have variable structure, we can not define a C
4053 * structure for them.
4055 void
4056 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
4058 MONO_REQ_GC_UNSAFE_MODE;
4060 MonoClass *param_class = m_class_get_cast_class (klass);
4061 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
4062 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4064 *(guint8*)(has_value_field_addr) = value ? 1 : 0;
4065 if (value) {
4066 if (m_class_has_references (param_class))
4067 mono_gc_wbarrier_value_copy_internal (value_field_addr, mono_object_unbox_internal (value), 1, param_class);
4068 else
4069 mono_gc_memmove_atomic (value_field_addr, mono_object_unbox_internal (value), mono_class_value_size (param_class, NULL));
4070 } else {
4071 mono_gc_bzero_atomic (value_field_addr, mono_class_value_size (param_class, NULL));
4076 * mono_nullable_init_from_handle:
4077 * @buf: The nullable structure to initialize.
4078 * @value: the value to initialize from
4079 * @klass: the type for the object
4081 * Initialize the nullable structure pointed to by @buf from @value which
4082 * should be a boxed value type. The size of @buf should be able to hold
4083 * as much data as the @klass->instance_size (which is the number of bytes
4084 * that will be copies).
4086 * Since Nullables have variable structure, we can not define a C
4087 * structure for them.
4089 void
4090 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
4092 MONO_REQ_GC_UNSAFE_MODE;
4094 if (!MONO_HANDLE_IS_NULL (value)) {
4095 uint32_t value_gchandle = 0;
4096 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
4097 mono_nullable_init_unboxed (buf, src, klass);
4099 mono_gchandle_free_internal (value_gchandle);
4100 } else {
4101 mono_nullable_init_unboxed (buf, NULL, klass);
4106 * mono_nullable_init_unboxed
4108 * @buf: The nullable structure to initialize.
4109 * @value: the unboxed address of the value to initialize from
4110 * @klass: the type for the object
4112 * Initialize the nullable structure pointed to by @buf from @value which
4113 * should be a boxed value type. The size of @buf should be able to hold
4114 * as much data as the @klass->instance_size (which is the number of bytes
4115 * that will be copies).
4117 * Since Nullables have variable structure, we can not define a C
4118 * structure for them.
4120 * This function expects all objects to be pinned or for
4121 * MONO_ENTER_NO_SAFEPOINTS to be used in a caller.
4123 void
4124 mono_nullable_init_unboxed (guint8 *buf, gpointer value, MonoClass *klass)
4126 MONO_REQ_GC_UNSAFE_MODE;
4128 MonoClass *param_class = m_class_get_cast_class (klass);
4129 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
4130 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4132 *(guint8*)(has_value_field_addr) = (value == NULL) ? 0 : 1;
4133 if (value) {
4134 if (m_class_has_references (param_class))
4135 mono_gc_wbarrier_value_copy_internal (value_field_addr, value, 1, param_class);
4136 else
4137 mono_gc_memmove_atomic (value_field_addr, value, mono_class_value_size (param_class, NULL));
4138 } else {
4139 mono_gc_bzero_atomic (value_field_addr, mono_class_value_size (param_class, NULL));
4144 * mono_nullable_box:
4145 * \param buf The buffer representing the data to be boxed
4146 * \param klass the type to box it as.
4147 * \param error set on error
4149 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
4150 * \p buf. On failure returns NULL and sets \p error.
4152 MonoObject*
4153 mono_nullable_box (gpointer vbuf, MonoClass *klass, MonoError *error)
4155 guint8 *buf = (guint8*)vbuf;
4156 MONO_REQ_GC_UNSAFE_MODE;
4158 error_init (error);
4159 MonoClass *param_class = m_class_get_cast_class (klass);
4160 gpointer has_value_field_addr = nullable_get_has_value_field_addr (buf, klass);
4161 gpointer value_field_addr = nullable_get_value_field_addr (buf, klass);
4163 g_assertf (!m_class_is_byreflike (param_class), "Unexpected Nullable<%s> - generic type instantiated with IsByRefLike type", mono_type_get_full_name (param_class));
4165 if (*(guint8*)(has_value_field_addr)) {
4166 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
4167 return_val_if_nok (error, NULL);
4168 if (m_class_has_references (param_class))
4169 mono_gc_wbarrier_value_copy_internal (mono_object_unbox_internal (o), value_field_addr, 1, param_class);
4170 else
4171 mono_gc_memmove_atomic (mono_object_unbox_internal (o), value_field_addr, mono_class_value_size (param_class, NULL));
4172 return o;
4174 else
4175 return NULL;
4178 MonoObjectHandle
4179 mono_nullable_box_handle (gpointer buf, MonoClass *klass, MonoError *error)
4181 // FIXMEcoop gpointer buf needs more attention
4182 return MONO_HANDLE_NEW (MonoObject, mono_nullable_box (buf, klass, error));
4185 MonoMethod *
4186 mono_get_delegate_invoke_internal (MonoClass *klass)
4188 MonoMethod *result;
4189 ERROR_DECL (error);
4190 result = mono_get_delegate_invoke_checked (klass, error);
4191 /* FIXME: better external API that doesn't swallow the error */
4192 mono_error_cleanup (error);
4193 return result;
4197 * mono_get_delegate_invoke:
4198 * \param klass The delegate class
4199 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
4201 MonoMethod*
4202 mono_get_delegate_invoke (MonoClass *klass)
4204 MONO_EXTERNAL_ONLY (MonoMethod*, mono_get_delegate_invoke_internal (klass));
4208 * mono_get_delegate_invoke_checked:
4209 * \param klass The delegate class
4210 * \param error set on error
4211 * \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.
4213 * Sets \p error on error
4215 MonoMethod *
4216 mono_get_delegate_invoke_checked (MonoClass *klass, MonoError *error)
4218 MONO_REQ_GC_NEUTRAL_MODE;
4220 MonoMethod *im;
4222 /* This is called at runtime, so avoid the slower search in metadata */
4223 mono_class_setup_methods (klass);
4224 if (mono_class_has_failure (klass))
4225 return NULL;
4226 im = mono_class_get_method_from_name_checked (klass, "Invoke", -1, 0, error);
4227 return im;
4230 MonoMethod *
4231 mono_get_delegate_begin_invoke_internal (MonoClass *klass)
4233 MonoMethod *result;
4234 ERROR_DECL (error);
4235 result = mono_get_delegate_begin_invoke_checked (klass, error);
4236 /* FIXME: better external API that doesn't swallow the error */
4237 mono_error_cleanup (error);
4238 return result;
4242 * mono_get_delegate_begin_invoke:
4243 * \param klass The delegate class
4244 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4246 MonoMethod*
4247 mono_get_delegate_begin_invoke (MonoClass *klass)
4249 MONO_EXTERNAL_ONLY (MonoMethod*, mono_get_delegate_begin_invoke_internal (klass));
4253 * mono_get_delegate_begin_invoke_checked:
4254 * \param klass The delegate class
4255 * \param error set on error
4256 * \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.
4258 * Sets \p error on error
4260 MonoMethod *
4261 mono_get_delegate_begin_invoke_checked (MonoClass *klass, MonoError *error)
4263 MONO_REQ_GC_NEUTRAL_MODE;
4265 MonoMethod *im;
4267 /* This is called at runtime, so avoid the slower search in metadata */
4268 mono_class_setup_methods (klass);
4269 if (mono_class_has_failure (klass))
4270 return NULL;
4271 im = mono_class_get_method_from_name_checked (klass, "BeginInvoke", -1, 0, error);
4272 return im;
4275 MonoMethod *
4276 mono_get_delegate_end_invoke_internal (MonoClass *klass)
4278 MonoMethod *result;
4279 ERROR_DECL (error);
4280 result = mono_get_delegate_end_invoke_checked (klass, error);
4281 /* FIXME: better external API that doesn't swallow the error */
4282 mono_error_cleanup (error);
4283 return result;
4287 * mono_get_delegate_end_invoke:
4288 * \param klass The delegate class
4289 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4291 MonoMethod*
4292 mono_get_delegate_end_invoke (MonoClass *klass)
4294 MONO_EXTERNAL_ONLY (MonoMethod*, mono_get_delegate_end_invoke_internal (klass));
4298 * mono_get_delegate_end_invoke_checked:
4299 * \param klass The delegate class
4300 * \param error set on error
4301 * \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.
4303 * Sets \p error on error
4305 MonoMethod *
4306 mono_get_delegate_end_invoke_checked (MonoClass *klass, MonoError *error)
4308 MONO_REQ_GC_NEUTRAL_MODE;
4310 MonoMethod *im;
4312 /* This is called at runtime, so avoid the slower search in metadata */
4313 mono_class_setup_methods (klass);
4314 if (mono_class_has_failure (klass))
4315 return NULL;
4316 im = mono_class_get_method_from_name_checked (klass, "EndInvoke", -1, 0, error);
4317 return im;
4321 * mono_runtime_delegate_invoke:
4322 * \param delegate pointer to a delegate object.
4323 * \param params parameters for the delegate.
4324 * \param exc Pointer to the exception result.
4326 * Invokes the delegate method \p delegate with the parameters provided.
4328 * You can pass NULL as the \p exc argument if you don't want to
4329 * catch exceptions, otherwise, \c *exc will be set to the exception
4330 * thrown, if any. if an exception is thrown, you can't use the
4331 * \c MonoObject* result from the function.
4333 MonoObject*
4334 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4336 MONO_REQ_GC_UNSAFE_MODE;
4338 ERROR_DECL (error);
4339 if (exc) {
4340 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, error);
4341 if (*exc) {
4342 mono_error_cleanup (error);
4343 return NULL;
4344 } else {
4345 if (!is_ok (error))
4346 *exc = (MonoObject*)mono_error_convert_to_exception (error);
4347 return result;
4349 } else {
4350 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, error);
4351 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
4352 return result;
4357 * mono_runtime_delegate_try_invoke:
4358 * \param delegate pointer to a delegate object.
4359 * \param params parameters for the delegate.
4360 * \param exc Pointer to the exception result.
4361 * \param error set on error
4362 * Invokes the delegate method \p delegate with the parameters provided.
4364 * You can pass NULL as the \p exc argument if you don't want to
4365 * catch exceptions, otherwise, \c *exc will be set to the exception
4366 * thrown, if any. On failure to execute, \p error will be set.
4367 * if an exception is thrown, you can't use the
4368 * \c MonoObject* result from the function.
4370 MonoObject*
4371 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4373 MONO_REQ_GC_UNSAFE_MODE;
4375 error_init (error);
4376 MonoMethod *im;
4377 MonoClass *klass = delegate->vtable->klass;
4378 MonoObject *o;
4380 im = mono_get_delegate_invoke_internal (klass);
4381 g_assertf (im, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4383 if (exc) {
4384 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4385 } else {
4386 o = mono_runtime_invoke_checked (im, delegate, params, error);
4389 return o;
4392 static MonoObjectHandle
4393 mono_runtime_delegate_try_invoke_handle (MonoObjectHandle delegate, void **params, MonoError *error)
4395 MONO_REQ_GC_UNSAFE_MODE;
4397 MonoClass* const klass = MONO_HANDLE_GETVAL (delegate, vtable)->klass;
4398 MonoMethod* const im = mono_get_delegate_invoke_internal (klass);
4399 g_assertf (im, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4401 return mono_runtime_try_invoke_handle (im, delegate, params, error);
4405 * mono_runtime_delegate_invoke_checked:
4406 * \param delegate pointer to a delegate object.
4407 * \param params parameters for the delegate.
4408 * \param error set on error
4409 * Invokes the delegate method \p delegate with the parameters provided.
4410 * On failure \p error will be set and you can't use the \c MonoObject*
4411 * result from the function.
4413 MonoObject*
4414 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4416 error_init (error);
4417 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4420 static char **main_args = NULL;
4421 static int num_main_args = 0;
4424 * mono_runtime_get_main_args:
4425 * \returns A \c MonoArray with the arguments passed to the main program
4427 MonoArray*
4428 mono_runtime_get_main_args (void)
4430 HANDLE_FUNCTION_ENTER ();
4431 MONO_REQ_GC_UNSAFE_MODE;
4432 ERROR_DECL (error);
4433 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
4434 error_init (error);
4435 MonoArrayHandle arg_array = mono_runtime_get_main_args_handle (error);
4436 goto_if_nok (error, leave);
4437 MONO_HANDLE_ASSIGN (result, arg_array);
4438 leave:
4439 /* FIXME: better external API that doesn't swallow the error */
4440 mono_error_cleanup (error);
4441 HANDLE_FUNCTION_RETURN_OBJ (result);
4444 static gboolean
4445 handle_main_arg_array_set (MonoDomain *domain, int idx, MonoArrayHandle dest, MonoError *error)
4447 HANDLE_FUNCTION_ENTER ();
4448 error_init (error);
4449 MonoStringHandle value = mono_string_new_handle (domain, main_args [idx], error);
4450 goto_if_nok (error, leave);
4451 MONO_HANDLE_ARRAY_SETREF (dest, idx, value);
4452 leave:
4453 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
4457 * mono_runtime_get_main_args_handle:
4458 * \param error set on error
4459 * \returns a \c MonoArray with the arguments passed to the main
4460 * program. On failure returns NULL and sets \p error.
4462 MonoArrayHandle
4463 mono_runtime_get_main_args_handle (MonoError *error)
4465 HANDLE_FUNCTION_ENTER ();
4466 MonoArrayHandle array;
4467 int i;
4468 MonoDomain *domain = mono_domain_get ();
4469 error_init (error);
4471 array = mono_array_new_handle (domain, mono_defaults.string_class, num_main_args, error);
4472 if (!is_ok (error)) {
4473 array = MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
4474 goto leave;
4476 for (i = 0; i < num_main_args; ++i) {
4477 if (!handle_main_arg_array_set (domain, i, array, error))
4478 goto leave;
4480 leave:
4481 HANDLE_FUNCTION_RETURN_REF (MonoArray, array);
4484 static void
4485 free_main_args (void)
4487 MONO_REQ_GC_NEUTRAL_MODE;
4489 int i;
4491 for (i = 0; i < num_main_args; ++i)
4492 g_free (main_args [i]);
4493 g_free (main_args);
4494 num_main_args = 0;
4495 main_args = NULL;
4499 * mono_runtime_set_main_args:
4500 * \param argc number of arguments from the command line
4501 * \param argv array of strings from the command line
4502 * Set the command line arguments from an embedding application that doesn't otherwise call
4503 * \c mono_runtime_run_main.
4506 mono_runtime_set_main_args (int argc, char* argv[])
4508 MONO_REQ_GC_NEUTRAL_MODE;
4510 int i;
4512 free_main_args ();
4513 main_args = g_new0 (char*, argc);
4514 num_main_args = argc;
4516 for (i = 0; i < argc; ++i) {
4517 gchar *utf8_arg;
4519 utf8_arg = mono_utf8_from_external (argv[i]);
4520 if (utf8_arg == NULL) {
4521 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4522 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4523 exit (-1);
4526 main_args [i] = utf8_arg;
4529 MONO_EXTERNAL_ONLY (int, 0);
4533 * Prepare an array of arguments in order to execute a standard Main()
4534 * method (argc/argv contains the executable name). This method also
4535 * sets the command line argument value needed by System.Environment.
4538 static MonoArray*
4539 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4541 MONO_REQ_GC_UNSAFE_MODE;
4543 ERROR_DECL (error);
4544 int i;
4545 MonoArray *args = NULL;
4546 MonoDomain *domain = mono_domain_get ();
4547 gchar *utf8_fullpath;
4548 MonoMethodSignature *sig;
4550 g_assert (method != NULL);
4552 mono_thread_set_main (mono_thread_current ());
4554 main_args = g_new0 (char*, argc);
4555 num_main_args = argc;
4557 if (!g_path_is_absolute (argv [0])) {
4558 gchar *basename = g_path_get_basename (argv [0]);
4559 gchar *fullpath = g_build_filename (m_class_get_image (method->klass)->assembly->basedir,
4560 basename,
4561 NULL);
4563 utf8_fullpath = mono_utf8_from_external (fullpath);
4564 if(utf8_fullpath == NULL) {
4565 /* Printing the arg text will cause glib to
4566 * whinge about "Invalid UTF-8", but at least
4567 * its relevant, and shows the problem text
4568 * string.
4570 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4571 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4572 exit (-1);
4575 g_free (fullpath);
4576 g_free (basename);
4577 } else {
4578 utf8_fullpath = mono_utf8_from_external (argv[0]);
4579 if(utf8_fullpath == NULL) {
4580 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4581 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4582 exit (-1);
4586 main_args [0] = utf8_fullpath;
4588 for (i = 1; i < argc; ++i) {
4589 gchar *utf8_arg;
4591 utf8_arg=mono_utf8_from_external (argv[i]);
4592 if(utf8_arg==NULL) {
4593 /* Ditto the comment about Invalid UTF-8 here */
4594 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4595 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4596 exit (-1);
4599 main_args [i] = utf8_arg;
4601 argc--;
4602 argv++;
4604 sig = mono_method_signature_internal (method);
4605 if (!sig) {
4606 g_print ("Unable to load Main method.\n");
4607 exit (-1);
4610 if (sig->param_count) {
4611 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, error);
4612 mono_error_assert_ok (error);
4613 for (i = 0; i < argc; ++i) {
4614 /* The encodings should all work, given that
4615 * we've checked all these args for the
4616 * main_args array.
4618 gchar *str = mono_utf8_from_external (argv [i]);
4619 MonoString *arg = mono_string_new_checked (domain, str, error);
4620 mono_error_assert_ok (error);
4621 mono_array_setref_internal (args, i, arg);
4622 g_free (str);
4624 } else {
4625 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, error);
4626 mono_error_assert_ok (error);
4629 mono_assembly_set_main (m_class_get_image (method->klass)->assembly);
4631 return args;
4635 * mono_runtime_run_main:
4636 * \param method the method to start the application with (usually <code>Main</code>)
4637 * \param argc number of arguments from the command line
4638 * \param argv array of strings from the command line
4639 * \param exc excetption results
4640 * Execute a standard \c Main method (\p argc / \p argv contains the
4641 * executable name). This method also sets the command line argument value
4642 * needed by \c System.Environment.
4645 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4646 MonoObject **exc)
4648 MONO_REQ_GC_UNSAFE_MODE;
4650 ERROR_DECL (error);
4651 MonoArray *args = prepare_run_main (method, argc, argv);
4652 int res;
4653 if (exc) {
4654 res = mono_runtime_try_exec_main (method, args, exc);
4655 } else {
4656 res = mono_runtime_exec_main_checked (method, args, error);
4657 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a better alternative */
4659 return res;
4663 * mono_runtime_run_main_checked:
4664 * \param method the method to start the application with (usually \c Main)
4665 * \param argc number of arguments from the command line
4666 * \param argv array of strings from the command line
4667 * \param error set on error
4669 * Execute a standard \c Main method (\p argc / \p argv contains the
4670 * executable name). This method also sets the command line argument value
4671 * needed by \c System.Environment. On failure sets \p error.
4674 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4675 MonoError *error)
4677 error_init (error);
4678 MonoArray *args = prepare_run_main (method, argc, argv);
4679 return mono_runtime_exec_main_checked (method, args, error);
4683 * mono_runtime_try_run_main:
4684 * \param method the method to start the application with (usually \c Main)
4685 * \param argc number of arguments from the command line
4686 * \param argv array of strings from the command line
4687 * \param exc set if \c Main throws an exception
4688 * \param error set if \c Main can't be executed
4689 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4690 * name). This method also sets the command line argument value needed
4691 * by \c System.Environment. On failure sets \p error if Main can't be
4692 * executed or \p exc if it threw an exception.
4695 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4696 MonoObject **exc)
4698 g_assert (exc);
4699 MonoArray *args = prepare_run_main (method, argc, argv);
4700 return mono_runtime_try_exec_main (method, args, exc);
4703 MonoObjectHandle
4704 mono_new_null (void) // A code size optimization (source and object).
4706 return MONO_HANDLE_NEW (MonoObject, NULL);
4709 static MonoObjectHandle
4710 serialize_or_deserialize_object (MonoObjectHandle obj, const gchar *method_name, MonoMethod **method, MonoError *error)
4712 if (!*method) {
4713 MonoClass *klass = mono_class_get_remoting_services_class ();
4714 *method = mono_class_get_method_from_name_checked (klass, method_name, -1, 0, error);
4715 return_val_if_nok (error, mono_new_null ());
4718 if (!*method) {
4719 mono_error_set_exception_instance (error, NULL);
4720 return mono_new_null ();
4723 void *params [ ] = { MONO_HANDLE_RAW (obj) };
4724 return mono_runtime_try_invoke_handle (*method, NULL_HANDLE, params, error);
4727 static MonoMethod *serialize_method;
4729 static MonoObjectHandle
4730 serialize_object (MonoObjectHandle obj, MonoError *error)
4732 g_assert (!mono_class_is_marshalbyref (mono_handle_class (obj)));
4733 return serialize_or_deserialize_object (obj, "SerializeCallData", &serialize_method, error);
4736 static MonoMethod *deserialize_method;
4738 static MonoObjectHandle
4739 deserialize_object (MonoObjectHandle obj, MonoError *error)
4741 MONO_REQ_GC_UNSAFE_MODE;
4742 return serialize_or_deserialize_object (obj, "DeserializeCallData", &deserialize_method, error);
4745 #ifndef DISABLE_REMOTING
4746 static MonoObjectHandle
4747 make_transparent_proxy (MonoObjectHandle obj, MonoError *error)
4749 MONO_REQ_GC_UNSAFE_MODE;
4751 static MonoMethod *get_proxy_method;
4753 if (!get_proxy_method) {
4754 get_proxy_method = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "GetTransparentProxy", 0, 0, error);
4755 mono_error_assert_ok (error);
4758 g_assert (mono_class_is_marshalbyref (MONO_HANDLE_GETVAL (obj, vtable)->klass));
4760 MonoDomain *domain = mono_domain_get ();
4761 MonoRealProxyHandle real_proxy = MONO_HANDLE_CAST (MonoRealProxy, mono_object_new_handle (domain, mono_defaults.real_proxy_class, error));
4762 goto_if_nok (error, return_null);
4763 MonoReflectionTypeHandle reflection_type;
4764 reflection_type = mono_type_get_object_handle (domain, m_class_get_byval_arg (mono_handle_class (obj)), error);
4765 goto_if_nok (error, return_null);
4767 MONO_HANDLE_SET (real_proxy, class_to_proxy, reflection_type);
4768 MONO_HANDLE_SET (real_proxy, unwrapped_server, obj);
4770 return mono_runtime_try_invoke_handle (get_proxy_method, MONO_HANDLE_CAST (MonoObject, real_proxy), NULL, error);
4771 return_null:
4772 return mono_new_null ();
4774 #endif /* DISABLE_REMOTING */
4777 * mono_object_xdomain_representation
4778 * \param obj an object
4779 * \param target_domain a domain
4780 * \param error set on error.
4781 * Creates a representation of obj in the domain \p target_domain. This
4782 * is either a copy of \p obj arrived through via serialization and
4783 * deserialization or a proxy, depending on whether the object is
4784 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4785 * If the object cannot be represented in \p target_domain, NULL is
4786 * returned and \p error is set appropriately.
4788 MonoObjectHandle
4789 mono_object_xdomain_representation (MonoObjectHandle obj, MonoDomain *target_domain, MonoError *error)
4791 HANDLE_FUNCTION_ENTER ();
4793 MONO_REQ_GC_UNSAFE_MODE;
4795 MonoObjectHandle deserialized;
4797 #ifndef DISABLE_REMOTING
4798 if (mono_class_is_marshalbyref (mono_handle_class (obj))) {
4799 deserialized = make_transparent_proxy (obj, error);
4801 else
4802 #endif
4804 MonoDomain *domain = mono_domain_get ();
4806 mono_domain_set_internal_with_options (MONO_HANDLE_DOMAIN (obj), FALSE);
4807 MonoObjectHandle serialized = serialize_object (obj, error);
4808 mono_domain_set_internal_with_options (target_domain, FALSE);
4809 if (is_ok (error))
4810 deserialized = deserialize_object (serialized, error);
4811 else
4812 deserialized = mono_new_null ();
4814 if (domain != target_domain)
4815 mono_domain_set_internal_with_options (domain, FALSE);
4818 HANDLE_FUNCTION_RETURN_REF (MonoObject, deserialized);
4821 /* Used in call_unhandled_exception_delegate */
4822 static MonoObjectHandle
4823 create_unhandled_exception_eventargs (MonoObjectHandle exc, MonoError *error)
4825 MONO_REQ_GC_UNSAFE_MODE;
4827 MonoClass * const klass = mono_class_get_unhandled_exception_event_args_class ();
4828 mono_class_init_internal (klass);
4830 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4831 MonoMethod * const method = mono_class_get_method_from_name_checked (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC, error);
4832 goto_if_nok (error, return_null);
4833 g_assert (method);
4835 MonoBoolean is_terminating;
4836 is_terminating = TRUE;
4837 gpointer args [2];
4838 args [0] = MONO_HANDLE_RAW (exc); // FIXMEcoop
4839 args [1] = &is_terminating;
4841 MonoObjectHandle obj;
4842 obj = mono_object_new_handle (mono_domain_get (), klass, error);
4843 goto_if_nok (error, return_null);
4845 mono_runtime_invoke_handle_void (method, obj, args, error);
4846 goto_if_nok (error, return_null);
4847 return obj;
4849 return_null:
4850 return MONO_HANDLE_NEW (MonoObject, NULL);
4853 /* Used in mono_unhandled_exception_internal */
4854 static void
4855 call_unhandled_exception_delegate (MonoDomain *domain, MonoObjectHandle delegate, MonoObjectHandle exc)
4857 MONO_REQ_GC_UNSAFE_MODE;
4859 ERROR_DECL (error);
4860 MonoDomain *current_domain = mono_domain_get ();
4862 if (domain != current_domain)
4863 mono_domain_set_internal_with_options (domain, FALSE);
4865 g_assert (domain == mono_object_domain (domain->domain));
4867 if (MONO_HANDLE_DOMAIN (exc) != domain) {
4869 exc = mono_object_xdomain_representation (exc, domain, error);
4870 if (MONO_HANDLE_IS_NULL (exc)) {
4871 ERROR_DECL (inner_error);
4872 if (!is_ok (error)) {
4873 MonoExceptionHandle serialization_exc = mono_error_convert_to_exception_handle (error);
4874 exc = mono_object_xdomain_representation (MONO_HANDLE_CAST (MonoObject, serialization_exc), domain, inner_error);
4875 } else {
4876 exc = MONO_HANDLE_CAST (MonoObject, mono_exception_new_serialization ("Could not serialize unhandled exception.", inner_error));
4878 mono_error_assert_ok (inner_error);
4881 g_assert (MONO_HANDLE_DOMAIN (exc) == domain);
4883 gpointer pa [ ] = {
4884 domain->domain,
4885 MONO_HANDLE_RAW (create_unhandled_exception_eventargs (exc, error)) // FIXMEcoop
4887 mono_error_assert_ok (error);
4888 mono_runtime_delegate_try_invoke_handle (delegate, pa, error);
4890 if (domain != current_domain)
4891 mono_domain_set_internal_with_options (current_domain, FALSE);
4893 if (!is_ok (error)) {
4894 g_warning ("exception inside UnhandledException handler: %s\n", mono_error_get_message (error));
4895 mono_error_cleanup (error);
4899 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4902 * mono_runtime_unhandled_exception_policy_set:
4903 * \param policy the new policy
4904 * This is a VM internal routine.
4905 * Sets the runtime policy for handling unhandled exceptions.
4907 void
4908 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy)
4910 runtime_unhandled_exception_policy = policy;
4914 * mono_runtime_unhandled_exception_policy_get:
4916 * This is a VM internal routine.
4918 * Gets the runtime policy for handling unhandled exceptions.
4920 MonoRuntimeUnhandledExceptionPolicy
4921 mono_runtime_unhandled_exception_policy_get (void)
4923 return runtime_unhandled_exception_policy;
4926 void
4927 mono_unhandled_exception_internal (MonoObject *exc_raw)
4929 ERROR_DECL (error);
4930 HANDLE_FUNCTION_ENTER ();
4931 MONO_HANDLE_DCL (MonoObject, exc);
4932 mono_unhandled_exception_checked (exc, error);
4933 mono_error_assert_ok (error);
4934 HANDLE_FUNCTION_RETURN ();
4938 * mono_unhandled_exception:
4939 * \param exc exception thrown
4940 * This is a VM internal routine.
4942 * We call this function when we detect an unhandled exception
4943 * in the default domain.
4945 * It invokes the \c UnhandledException event in \c AppDomain or prints
4946 * a warning to the console
4948 void
4949 mono_unhandled_exception (MonoObject *exc)
4951 MONO_EXTERNAL_ONLY_VOID (mono_unhandled_exception_internal (exc));
4955 * mono_unhandled_exception_checked:
4956 * @exc: exception thrown
4958 * This is a VM internal routine.
4960 * We call this function when we detect an unhandled exception
4961 * in the default domain.
4963 * It invokes the * UnhandledException event in AppDomain or prints
4964 * a warning to the console
4966 void
4967 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4969 MONO_REQ_GC_UNSAFE_MODE;
4971 MonoClassField *field;
4972 MonoDomain *current_domain, *root_domain;
4973 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4975 MonoClass *klass = mono_handle_class (exc);
4977 * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
4978 * a thread started in unmanaged world.
4979 * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
4981 gboolean no_event = (klass == mono_defaults.threadabortexception_class);
4982 #ifndef ENABLE_NETCORE
4983 no_event = no_event ||
4984 (klass == mono_class_get_appdomain_unloaded_exception_class () &&
4985 mono_thread_info_current ()->runtime_thread);
4986 #endif
4987 if (no_event)
4988 return;
4990 field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "UnhandledException", NULL);
4991 g_assert (field);
4993 current_domain = mono_domain_get ();
4994 root_domain = mono_get_root_domain ();
4996 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 */
4997 return_if_nok (error);
4998 if (current_domain != root_domain) {
4999 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 */
5000 return_if_nok (error);
5003 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
5004 mono_print_unhandled_exception_internal (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
5005 } else {
5006 /* unhandled exception callbacks must not be aborted */
5007 mono_threads_begin_abort_protected_block ();
5008 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
5009 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
5010 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
5011 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
5012 mono_threads_end_abort_protected_block ();
5015 /* set exitcode only if we will abort the process */
5016 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
5017 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
5019 mono_environment_exitcode_set (1);
5024 * mono_runtime_exec_managed_code:
5025 * \param domain Application domain
5026 * \param main_func function to invoke from the execution thread
5027 * \param main_args parameter to the main_func
5028 * Launch a new thread to execute a function
5030 * \p main_func is called back from the thread with main_args as the
5031 * parameter. The callback function is expected to start \c Main
5032 * eventually. This function then waits for all managed threads to
5033 * finish.
5034 * It is not necessary anymore to execute managed code in a subthread,
5035 * so this function should not be used anymore by default: just
5036 * execute the code and then call mono_thread_manage().
5038 void
5039 mono_runtime_exec_managed_code (MonoDomain *domain,
5040 MonoMainThreadFunc mfunc,
5041 gpointer margs)
5043 // This function is external_only.
5045 ERROR_DECL (error);
5046 mono_thread_create_checked (domain, mfunc, margs, error);
5047 mono_error_assert_ok (error);
5049 mono_thread_manage ();
5052 static void
5053 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
5055 MONO_REQ_GC_UNSAFE_MODE;
5056 MonoInternalThread* thread = mono_thread_internal_current ();
5057 MonoCustomAttrInfo* cinfo;
5058 gboolean has_stathread_attribute;
5060 if (!domain->entry_assembly) {
5061 gchar *str;
5062 ERROR_DECL (error);
5063 MonoAssembly *assembly;
5065 assembly = m_class_get_image (method->klass)->assembly;
5066 domain->entry_assembly = assembly;
5067 /* Domains created from another domain already have application_base and configuration_file set */
5068 if (domain->setup->application_base == NULL) {
5069 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, error);
5070 mono_error_assert_ok (error);
5071 MONO_OBJECT_SETREF_INTERNAL (domain->setup, application_base, basedir);
5074 if (domain->setup->configuration_file == NULL) {
5075 str = g_strconcat (assembly->image->name, ".config", NULL);
5076 MonoString *config_file = mono_string_new_checked (domain, str, error);
5077 mono_error_assert_ok (error);
5078 MONO_OBJECT_SETREF_INTERNAL (domain->setup, configuration_file, config_file);
5079 g_free (str);
5080 mono_domain_set_options_from_config (domain);
5084 ERROR_DECL (cattr_error);
5085 cinfo = mono_custom_attrs_from_method_checked (method, cattr_error);
5086 mono_error_cleanup (cattr_error); /* FIXME warn here? */
5087 if (cinfo) {
5088 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
5089 if (!cinfo->cached)
5090 mono_custom_attrs_free (cinfo);
5091 } else {
5092 has_stathread_attribute = FALSE;
5094 if (has_stathread_attribute) {
5095 thread->apartment_state = ThreadApartmentState_STA;
5096 } else {
5097 thread->apartment_state = ThreadApartmentState_MTA;
5099 mono_thread_init_apartment_state ();
5103 static int
5104 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
5106 MONO_REQ_GC_UNSAFE_MODE;
5108 gpointer pa [1];
5109 int rval;
5111 error_init (error);
5112 g_assert (args);
5114 pa [0] = args;
5116 /* FIXME: check signature of method */
5117 if (mono_method_signature_internal (method)->ret->type == MONO_TYPE_I4) {
5118 MonoObject *res;
5119 res = mono_runtime_invoke_checked (method, NULL, pa, error);
5120 if (is_ok (error))
5121 rval = *(guint32 *)(mono_object_get_data (res));
5122 else
5123 rval = -1;
5124 mono_environment_exitcode_set (rval);
5125 } else {
5126 mono_runtime_invoke_checked (method, NULL, pa, error);
5128 if (is_ok (error))
5129 rval = 0;
5130 else {
5131 rval = -1;
5134 return rval;
5137 static int
5138 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5140 MONO_REQ_GC_UNSAFE_MODE;
5142 gpointer pa [1];
5143 int rval;
5145 g_assert (args);
5146 g_assert (exc);
5148 pa [0] = args;
5150 /* FIXME: check signature of method */
5151 if (mono_method_signature_internal (method)->ret->type == MONO_TYPE_I4) {
5152 ERROR_DECL (inner_error);
5153 MonoObject *res;
5154 res = mono_runtime_try_invoke (method, NULL, pa, exc, inner_error);
5155 if (*exc == NULL && !is_ok (inner_error))
5156 *exc = (MonoObject*) mono_error_convert_to_exception (inner_error);
5157 else
5158 mono_error_cleanup (inner_error);
5160 if (*exc == NULL)
5161 rval = *(guint32 *)(mono_object_get_data (res));
5162 else
5163 rval = -1;
5165 mono_environment_exitcode_set (rval);
5166 } else {
5167 ERROR_DECL (inner_error);
5168 mono_runtime_try_invoke (method, NULL, pa, exc, inner_error);
5169 if (*exc == NULL && !is_ok (inner_error))
5170 *exc = (MonoObject*) mono_error_convert_to_exception (inner_error);
5171 else
5172 mono_error_cleanup (inner_error);
5174 if (*exc == NULL)
5175 rval = 0;
5176 else {
5177 /* If the return type of Main is void, only
5178 * set the exitcode if an exception was thrown
5179 * (we don't want to blow away an
5180 * explicitly-set exit code)
5182 rval = -1;
5183 mono_environment_exitcode_set (rval);
5187 return rval;
5191 * Execute a standard Main() method (args doesn't contain the
5192 * executable name).
5195 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5197 int rval;
5198 MONO_ENTER_GC_UNSAFE;
5199 ERROR_DECL (error);
5200 prepare_thread_to_exec_main (mono_object_domain (args), method);
5201 if (exc) {
5202 rval = do_try_exec_main (method, args, exc);
5203 } else {
5204 rval = do_exec_main_checked (method, args, error);
5205 mono_error_raise_exception_deprecated (error); /* OK to throw, external only with no better option */
5207 MONO_EXIT_GC_UNSAFE;
5208 return rval;
5212 * Execute a standard Main() method (args doesn't contain the
5213 * executable name).
5215 * On failure sets @error
5218 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
5220 error_init (error);
5221 prepare_thread_to_exec_main (mono_object_domain (args), method);
5222 return do_exec_main_checked (method, args, error);
5226 * Execute a standard Main() method (args doesn't contain the
5227 * executable name).
5229 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
5232 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
5234 prepare_thread_to_exec_main (mono_object_domain (args), method);
5235 return do_try_exec_main (method, args, exc);
5238 /** invoke_array_extract_argument:
5239 * @params: array of arguments to the method.
5240 * @i: the index of the argument to extract.
5241 * @t: ith type from the method signature.
5242 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
5243 * @error: set on error.
5245 * Given an array of method arguments, return the ith one using the corresponding type
5246 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
5248 * On failure sets @error and returns NULL.
5250 static gpointer
5251 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
5253 MonoType *t_orig = t;
5254 gpointer result = NULL;
5255 error_init (error);
5256 again:
5257 switch (t->type) {
5258 case MONO_TYPE_U1:
5259 case MONO_TYPE_I1:
5260 case MONO_TYPE_BOOLEAN:
5261 case MONO_TYPE_U2:
5262 case MONO_TYPE_I2:
5263 case MONO_TYPE_CHAR:
5264 case MONO_TYPE_U:
5265 case MONO_TYPE_I:
5266 case MONO_TYPE_U4:
5267 case MONO_TYPE_I4:
5268 case MONO_TYPE_U8:
5269 case MONO_TYPE_I8:
5270 case MONO_TYPE_R4:
5271 case MONO_TYPE_R8:
5272 case MONO_TYPE_VALUETYPE:
5273 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type_internal (t_orig))) {
5274 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
5275 result = mono_array_get_internal (params, MonoObject*, i);
5276 if (t->byref)
5277 *has_byref_nullables = TRUE;
5278 } else {
5279 /* MS seems to create the objects if a null is passed in */
5280 gboolean was_null = FALSE;
5281 if (!mono_array_get_internal (params, MonoObject*, i)) {
5282 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type_internal (t_orig), error);
5283 return_val_if_nok (error, NULL);
5284 mono_array_setref_internal (params, i, o);
5285 was_null = TRUE;
5288 if (t->byref) {
5290 * We can't pass the unboxed vtype byref to the callee, since
5291 * that would mean the callee would be able to modify boxed
5292 * primitive types. So we (and MS) make a copy of the boxed
5293 * object, pass that to the callee, and replace the original
5294 * boxed object in the arg array with the copy.
5296 MonoObject *orig = mono_array_get_internal (params, MonoObject*, i);
5297 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox_internal (orig), error);
5298 return_val_if_nok (error, NULL);
5299 mono_array_setref_internal (params, i, copy);
5302 result = mono_object_unbox_internal (mono_array_get_internal (params, MonoObject*, i));
5303 if (!t->byref && was_null)
5304 mono_array_setref_internal (params, i, NULL);
5306 break;
5307 case MONO_TYPE_STRING:
5308 case MONO_TYPE_OBJECT:
5309 case MONO_TYPE_CLASS:
5310 case MONO_TYPE_ARRAY:
5311 case MONO_TYPE_SZARRAY:
5312 if (t->byref)
5313 result = mono_array_addr_internal (params, MonoObject*, i);
5314 // FIXME: I need to check this code path
5315 else
5316 result = mono_array_get_internal (params, MonoObject*, i);
5317 break;
5318 case MONO_TYPE_GENERICINST:
5319 if (t->byref)
5320 t = m_class_get_this_arg (t->data.generic_class->container_class);
5321 else
5322 t = m_class_get_byval_arg (t->data.generic_class->container_class);
5323 goto again;
5324 case MONO_TYPE_PTR: {
5325 MonoObject *arg;
5327 /* The argument should be an IntPtr */
5328 arg = mono_array_get_internal (params, MonoObject*, i);
5329 if (arg == NULL) {
5330 result = NULL;
5331 } else {
5332 g_assert (arg->vtable->klass == mono_defaults.int_class);
5333 result = ((MonoIntPtr*)arg)->m_value;
5335 break;
5337 default:
5338 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
5340 return result;
5343 * mono_runtime_invoke_array:
5344 * \param method method to invoke
5345 * \param obj object instance
5346 * \param params arguments to the method
5347 * \param exc exception information.
5348 * Invokes the method represented by \p method on the object \p obj.
5350 * \p obj is the \c this pointer, it should be NULL for static
5351 * methods, a \c MonoObject* for object instances and a pointer to
5352 * the value type for value types.
5354 * The \p params array contains the arguments to the method with the
5355 * same convention: \c MonoObject* pointers for object instances and
5356 * pointers to the value type otherwise. The \c _invoke_array
5357 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5358 * in this case the value types are boxed inside the
5359 * respective reference representation.
5361 * From unmanaged code you'll usually use the
5362 * mono_runtime_invoke_checked() variant.
5364 * Note that this function doesn't handle virtual methods for
5365 * you, it will exec the exact method you pass: we still need to
5366 * expose a function to lookup the derived class implementation
5367 * of a virtual method (there are examples of this in the code,
5368 * though).
5370 * You can pass NULL as the \p exc argument if you don't want to
5371 * catch exceptions, otherwise, \c *exc will be set to the exception
5372 * thrown, if any. if an exception is thrown, you can't use the
5373 * \c MonoObject* result from the function.
5375 * If the method returns a value type, it is boxed in an object
5376 * reference.
5378 MonoObject*
5379 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5380 MonoObject **exc)
5382 ERROR_DECL (error);
5383 if (exc) {
5384 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, error);
5385 if (*exc) {
5386 mono_error_cleanup (error);
5387 return NULL;
5388 } else {
5389 if (!is_ok (error))
5390 *exc = (MonoObject*)mono_error_convert_to_exception (error);
5391 return result;
5393 } else {
5394 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5395 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
5396 return result;
5401 * mono_runtime_invoke_array_checked:
5402 * \param method method to invoke
5403 * \param obj object instance
5404 * \param params arguments to the method
5405 * \param error set on failure.
5406 * Invokes the method represented by \p method on the object \p obj.
5408 * \p obj is the \c this pointer, it should be NULL for static
5409 * methods, a \c MonoObject* for object instances and a pointer to
5410 * the value type for value types.
5412 * The \p params array contains the arguments to the method with the
5413 * same convention: \c MonoObject* pointers for object instances and
5414 * pointers to the value type otherwise. The \c _invoke_array
5415 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5416 * in this case the value types are boxed inside the
5417 * respective reference representation.
5419 * From unmanaged code you'll usually use the
5420 * mono_runtime_invoke_checked() variant.
5422 * Note that this function doesn't handle virtual methods for
5423 * you, it will exec the exact method you pass: we still need to
5424 * expose a function to lookup the derived class implementation
5425 * of a virtual method (there are examples of this in the code,
5426 * though).
5428 * On failure or exception, \p error will be set. In that case, you
5429 * can't use the \c MonoObject* result from the function.
5431 * If the method returns a value type, it is boxed in an object
5432 * reference.
5434 MonoObject*
5435 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5436 MonoError *error)
5438 error_init (error);
5439 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5443 * mono_runtime_try_invoke_array:
5444 * \param method method to invoke
5445 * \param obj object instance
5446 * \param params arguments to the method
5447 * \param exc exception information.
5448 * \param error set on failure.
5449 * Invokes the method represented by \p method on the object \p obj.
5451 * \p obj is the \c this pointer, it should be NULL for static
5452 * methods, a \c MonoObject* for object instances and a pointer to
5453 * the value type for value types.
5455 * The \p params array contains the arguments to the method with the
5456 * same convention: \c MonoObject* pointers for object instances and
5457 * pointers to the value type otherwise. The \c _invoke_array
5458 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5459 * in this case the value types are boxed inside the
5460 * respective reference representation.
5462 * From unmanaged code you'll usually use the
5463 * mono_runtime_invoke_checked() variant.
5465 * Note that this function doesn't handle virtual methods for
5466 * you, it will exec the exact method you pass: we still need to
5467 * expose a function to lookup the derived class implementation
5468 * of a virtual method (there are examples of this in the code,
5469 * though).
5471 * You can pass NULL as the \p exc argument if you don't want to catch
5472 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5473 * any. On other failures, \p error will be set. If an exception is
5474 * thrown or there's an error, you can't use the \c MonoObject* result
5475 * from the function.
5477 * If the method returns a value type, it is boxed in an object
5478 * reference.
5480 MonoObject*
5481 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5482 MonoObject **exc, MonoError *error)
5484 MONO_REQ_GC_UNSAFE_MODE;
5486 error_init (error);
5488 MonoMethodSignature *sig = mono_method_signature_internal (method);
5489 gpointer *pa = NULL;
5490 MonoObject *res;
5491 int i;
5492 gboolean has_byref_nullables = FALSE;
5494 if (NULL != params) {
5495 pa = g_newa (gpointer, mono_array_length_internal (params));
5496 for (i = 0; i < mono_array_length_internal (params); i++) {
5497 MonoType *t = sig->params [i];
5498 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5499 return_val_if_nok (error, NULL);
5503 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5504 void *o = obj;
5506 if (mono_class_is_nullable (method->klass)) {
5507 /* Need to create a boxed vtype instead */
5508 g_assert (!obj);
5510 if (!params)
5511 return NULL;
5512 else {
5513 return mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method->klass), pa [0], error);
5517 if (!obj) {
5518 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5519 mono_error_assert_ok (error);
5520 g_assert (obj); /*maybe we should raise a TLE instead?*/
5521 #ifndef DISABLE_REMOTING
5522 if (mono_object_is_transparent_proxy (obj)) {
5523 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : m_class_get_vtable (method->klass) [method->slot], error);
5524 return_val_if_nok (error, NULL);
5526 #endif
5527 if (m_class_is_valuetype (method->klass))
5528 o = (MonoObject *)mono_object_unbox_internal ((MonoObject *)obj);
5529 else
5530 o = obj;
5531 } else if (m_class_is_valuetype (method->klass)) {
5532 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5533 return_val_if_nok (error, NULL);
5536 if (exc) {
5537 mono_runtime_try_invoke (method, o, pa, exc, error);
5538 } else {
5539 mono_runtime_invoke_checked (method, o, pa, error);
5542 return (MonoObject *)obj;
5543 } else {
5544 if (mono_class_is_nullable (method->klass)) {
5545 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
5546 obj = NULL;
5547 } else {
5548 MonoObject *nullable;
5549 /* Convert the unboxed vtype into a Nullable structure */
5550 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5551 return_val_if_nok (error, NULL);
5553 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method->klass), obj, error);
5554 return_val_if_nok (error, NULL);
5555 mono_nullable_init ((guint8 *)mono_object_unbox_internal (nullable), boxed, method->klass);
5556 obj = mono_object_unbox_internal (nullable);
5560 /* obj must be already unboxed if needed */
5561 if (exc) {
5562 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5563 } else {
5564 res = mono_runtime_invoke_checked (method, obj, pa, error);
5566 return_val_if_nok (error, NULL);
5568 if (sig->ret->type == MONO_TYPE_PTR) {
5569 MonoClass *pointer_class;
5570 static MonoMethod *box_method;
5571 void *box_args [2];
5572 MonoObject *box_exc;
5575 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5576 * convert it to a Pointer object.
5578 pointer_class = mono_class_get_pointer_class ();
5579 if (!box_method) {
5580 box_method = mono_class_get_method_from_name_checked (pointer_class, "Box", -1, 0, error);
5581 mono_error_assert_ok (error);
5584 g_assert (res->vtable->klass == mono_defaults.int_class);
5585 box_args [0] = ((MonoIntPtr*)res)->m_value;
5586 if (sig->ret->byref) {
5587 // byref is already unboxed by the invoke code
5588 MonoType *tmpret = mono_metadata_type_dup (NULL, sig->ret);
5589 tmpret->byref = FALSE;
5590 box_args [1] = mono_type_get_object_checked (mono_domain_get (), tmpret, error);
5591 mono_metadata_free_type (tmpret);
5592 } else {
5593 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5595 return_val_if_nok (error, NULL);
5597 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5598 g_assert (box_exc == NULL);
5599 mono_error_assert_ok (error);
5602 if (has_byref_nullables) {
5604 * The runtime invoke wrapper already converted byref nullables back,
5605 * and stored them in pa, we just need to copy them back to the
5606 * managed array.
5608 for (i = 0; i < mono_array_length_internal (params); i++) {
5609 MonoType *t = sig->params [i];
5611 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t)))
5612 mono_array_setref_internal (params, i, pa [i]);
5616 return res;
5620 // FIXME these will move to header soon
5621 static MonoObjectHandle
5622 mono_object_new_by_vtable (MonoVTable *vtable, MonoError *error);
5625 * object_new_common_tail:
5627 * This function centralizes post-processing of objects upon creation.
5628 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields,
5629 * and setting error.
5631 static MonoObject*
5632 object_new_common_tail (MonoObject *o, MonoClass *klass, MonoError *error)
5634 error_init (error);
5636 if (G_UNLIKELY (!o)) {
5637 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (klass));
5638 return o;
5641 if (G_UNLIKELY (m_class_has_finalize (klass)))
5642 mono_object_register_finalizer (o);
5644 if (G_UNLIKELY (m_class_has_weak_fields (klass)))
5645 mono_gc_register_obj_with_weak_fields (o);
5647 return o;
5651 * object_new_handle_tail:
5653 * This function centralizes post-processing of objects upon creation.
5654 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields.
5656 static MonoObjectHandle
5657 object_new_handle_common_tail (MonoObjectHandle o, MonoClass *klass, MonoError *error)
5659 error_init (error);
5661 if (G_UNLIKELY (MONO_HANDLE_IS_NULL (o))) {
5662 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (klass));
5663 return o;
5666 if (G_UNLIKELY (m_class_has_finalize (klass)))
5667 mono_object_register_finalizer_handle (o);
5669 if (G_UNLIKELY (m_class_has_weak_fields (klass)))
5670 mono_gc_register_object_with_weak_fields (o);
5672 return o;
5676 * mono_object_new:
5677 * \param klass the class of the object that we want to create
5678 * \returns a newly created object whose definition is
5679 * looked up using \p klass. This will not invoke any constructors,
5680 * so the consumer of this routine has to invoke any constructors on
5681 * its own to initialize the object.
5683 * It returns NULL on failure.
5685 MonoObject *
5686 mono_object_new (MonoDomain *domain, MonoClass *klass)
5688 MonoObject * result;
5689 MONO_ENTER_GC_UNSAFE;
5690 ERROR_DECL (error);
5691 result = mono_object_new_checked (domain, klass, error);
5692 mono_error_cleanup (error);
5693 MONO_EXIT_GC_UNSAFE;
5694 return result;
5697 MonoObject *
5698 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5700 MONO_REQ_GC_UNSAFE_MODE;
5702 ERROR_DECL (error);
5704 MonoObject * result = mono_object_new_checked (domain, klass, error);
5706 mono_error_set_pending_exception (error);
5707 return result;
5711 * mono_object_new_checked:
5712 * \param klass the class of the object that we want to create
5713 * \param error set on error
5714 * \returns a newly created object whose definition is
5715 * looked up using \p klass. This will not invoke any constructors,
5716 * so the consumer of this routine has to invoke any constructors on
5717 * its own to initialize the object.
5719 * It returns NULL on failure and sets \p error.
5721 MonoObject *
5722 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5724 MONO_REQ_GC_UNSAFE_MODE;
5726 MonoVTable *vtable;
5728 vtable = mono_class_vtable_checked (domain, klass, error);
5729 if (!is_ok (error))
5730 return NULL;
5732 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5733 return o;
5737 * mono_object_new_handle:
5738 * \param klass the class of the object that we want to create
5739 * \param error set on error
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 and sets \p error.
5747 MonoObjectHandle
5748 mono_object_new_handle (MonoDomain *domain, MonoClass *klass, MonoError *error)
5750 MONO_REQ_GC_UNSAFE_MODE;
5752 MonoVTable* const vtable = mono_class_vtable_checked (domain, klass, error);
5754 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5756 return mono_object_new_by_vtable (vtable, error);
5760 * mono_object_new_pinned:
5762 * Same as mono_object_new, but the returned object will be pinned.
5763 * For SGEN, these objects will only be freed at appdomain unload.
5765 MonoObjectHandle
5766 mono_object_new_pinned_handle (MonoDomain *domain, MonoClass *klass, MonoError *error)
5768 MONO_REQ_GC_UNSAFE_MODE;
5770 MonoVTable* const vtable = mono_class_vtable_checked (domain, klass, error);
5771 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5773 g_assert (vtable->klass == klass);
5775 int const size = mono_class_instance_size (klass);
5777 MonoObjectHandle o = mono_gc_alloc_handle_pinned_obj (vtable, size);
5779 return object_new_handle_common_tail (o, klass, error);
5782 MonoObject *
5783 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5785 MONO_REQ_GC_UNSAFE_MODE;
5787 MonoVTable *vtable;
5789 vtable = mono_class_vtable_checked (domain, klass, error);
5790 return_val_if_nok (error, NULL);
5792 MonoObject *o = mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5794 return object_new_common_tail (o, klass, error);
5798 * mono_object_new_specific:
5799 * \param vtable the vtable of the object that we want to create
5800 * \returns A newly created object with class and domain specified
5801 * by \p vtable
5803 MonoObject *
5804 mono_object_new_specific (MonoVTable *vtable)
5806 ERROR_DECL (error);
5807 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5808 mono_error_cleanup (error);
5810 return o;
5813 MonoObject *
5814 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5816 MONO_REQ_GC_UNSAFE_MODE;
5818 MonoObject *o;
5820 error_init (error);
5822 /* check for is_com_object for COM Interop */
5823 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5825 gpointer pa [1];
5826 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5828 if (im == NULL) {
5829 MonoClass *klass = mono_class_get_activation_services_class ();
5831 if (!m_class_is_inited (klass))
5832 mono_class_init_internal (klass);
5834 im = mono_class_get_method_from_name_checked (klass, "CreateProxyForType", 1, 0, error);
5835 return_val_if_nok (error, NULL);
5836 if (!im) {
5837 mono_error_set_not_supported (error, "Linked away.");
5838 return NULL;
5840 vtable->domain->create_proxy_for_type_method = im;
5843 pa [0] = mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable->klass), error);
5844 if (!is_ok (error))
5845 return NULL;
5847 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5848 if (!is_ok (error))
5849 return NULL;
5851 if (o != NULL)
5852 return o;
5855 return mono_object_new_alloc_specific_checked (vtable, error);
5858 static MonoObjectHandle
5859 mono_object_new_by_vtable (MonoVTable *vtable, MonoError *error)
5861 // This function handles remoting and COM.
5862 // mono_object_new_alloc_by_vtable does not.
5864 MONO_REQ_GC_UNSAFE_MODE;
5866 MonoObjectHandle o = MONO_HANDLE_NEW (MonoObject, NULL);
5868 error_init (error);
5870 /* check for is_com_object for COM Interop */
5871 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5873 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5875 if (im == NULL) {
5876 MonoClass *klass = mono_class_get_activation_services_class ();
5878 if (!m_class_is_inited (klass))
5879 mono_class_init_internal (klass);
5881 im = mono_class_get_method_from_name_checked (klass, "CreateProxyForType", 1, 0, error);
5882 return_val_if_nok (error, mono_new_null ());
5883 if (!im) {
5884 mono_error_set_not_supported (error, "Linked away.");
5885 return MONO_HANDLE_NEW (MonoObject, NULL);
5887 vtable->domain->create_proxy_for_type_method = im;
5890 // FIXMEcoop
5891 gpointer pa[ ] = { mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable->klass), error) };
5892 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5894 // FIXMEcoop
5895 o = MONO_HANDLE_NEW (MonoObject, mono_runtime_invoke_checked (im, NULL, pa, error));
5896 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
5898 if (!MONO_HANDLE_IS_NULL (o))
5899 return o;
5902 return mono_object_new_alloc_by_vtable (vtable, error);
5905 MonoObject *
5906 ves_icall_object_new_specific (MonoVTable *vtable)
5908 ERROR_DECL (error);
5909 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5910 mono_error_set_pending_exception (error);
5912 return o;
5916 * mono_object_new_alloc_specific:
5917 * \param vtable virtual table for the object.
5918 * This function allocates a new \c MonoObject with the type derived
5919 * from the \p vtable information. If the class of this object has a
5920 * finalizer, then the object will be tracked for finalization.
5922 * This method might raise an exception on errors. Use the
5923 * \c mono_object_new_fast_checked method if you want to manually raise
5924 * the exception.
5926 * \returns the allocated object.
5928 MonoObject *
5929 mono_object_new_alloc_specific (MonoVTable *vtable)
5931 ERROR_DECL (error);
5932 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, error);
5933 mono_error_cleanup (error);
5935 return o;
5939 * mono_object_new_alloc_specific_checked:
5940 * \param vtable virtual table for the object.
5941 * \param error holds the error return value.
5943 * This function allocates a new \c MonoObject with the type derived
5944 * from the \p vtable information. If the class of this object has a
5945 * finalizer, then the object will be tracked for finalization.
5947 * If there is not enough memory, the \p error parameter will be set
5948 * and will contain a user-visible message with the amount of bytes
5949 * that were requested.
5951 * \returns the allocated object, or NULL if there is not enough memory
5953 MonoObject *
5954 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5956 MONO_REQ_GC_UNSAFE_MODE;
5958 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5960 return object_new_common_tail (o, vtable->klass, error);
5963 MonoObjectHandle
5964 mono_object_new_alloc_by_vtable (MonoVTable *vtable, MonoError *error)
5966 MONO_REQ_GC_UNSAFE_MODE;
5968 MonoClass* const klass = vtable->klass;
5969 int const size = m_class_get_instance_size (klass);
5971 MonoObjectHandle o = mono_gc_alloc_handle_obj (vtable, size);
5973 return object_new_handle_common_tail (o, klass, error);
5977 * mono_object_new_fast:
5978 * \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. The returned object is not tracked
5982 * for finalization. If your object implements a finalizer, you should
5983 * use \c mono_object_new_alloc_specific instead.
5985 * This method might raise an exception on errors. Use the
5986 * \c mono_object_new_fast_checked method if you want to manually raise
5987 * the exception.
5989 * \returns the allocated object.
5991 MonoObject*
5992 mono_object_new_fast (MonoVTable *vtable)
5994 ERROR_DECL (error);
5996 MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5998 // This deliberately skips object_new_common_tail.
6000 if (G_UNLIKELY (!o))
6001 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
6003 mono_error_cleanup (error);
6005 return o;
6008 MonoObject*
6009 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
6011 MONO_REQ_GC_UNSAFE_MODE;
6013 int size;
6015 size = m_class_get_instance_size (vtable->klass);
6017 #if MONO_CROSS_COMPILE
6018 /* In cross compile mode, we should only allocate thread objects */
6019 /* The instance size refers to the target arch, this should be safe enough */
6020 size *= 2;
6021 #endif
6023 MonoObject *o = mono_gc_alloc_mature (vtable, size);
6025 return object_new_common_tail (o, vtable->klass, error);
6028 MonoObjectHandle
6029 mono_object_new_handle_mature (MonoVTable *vtable, MonoError *error)
6031 MONO_REQ_GC_UNSAFE_MODE;
6033 MonoClass* const klass = vtable->klass;
6034 int const size = m_class_get_instance_size (klass);
6036 MonoObjectHandle o = mono_gc_alloc_handle_mature (vtable, size);
6038 return object_new_handle_common_tail (o, klass, error);
6042 * mono_object_new_from_token:
6043 * \param image Context where the type_token is hosted
6044 * \param token a token of the type that we want to create
6045 * \returns A newly created object whose definition is
6046 * looked up using \p token in the \p image image
6048 MonoObject *
6049 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
6051 MONO_REQ_GC_UNSAFE_MODE;
6053 HANDLE_FUNCTION_ENTER ();
6055 ERROR_DECL (error);
6056 MonoClass *klass;
6058 klass = mono_class_get_checked (image, token, error);
6059 mono_error_assert_ok (error);
6061 MonoObjectHandle result = mono_object_new_handle (domain, klass, error);
6063 mono_error_cleanup (error);
6065 HANDLE_FUNCTION_RETURN_OBJ (result);
6069 * mono_object_clone:
6070 * \param obj the object to clone
6071 * \returns A newly created object who is a shallow copy of \p obj
6073 MonoObject *
6074 mono_object_clone (MonoObject *obj)
6076 ERROR_DECL (error);
6077 MonoObject *o = mono_object_clone_checked (obj, error);
6078 mono_error_cleanup (error);
6080 return o;
6083 MonoObject *
6084 mono_object_clone_checked (MonoObject *obj_raw, MonoError *error)
6086 MONO_REQ_GC_UNSAFE_MODE;
6087 HANDLE_FUNCTION_ENTER ();
6088 MONO_HANDLE_DCL (MonoObject, obj);
6089 HANDLE_FUNCTION_RETURN_OBJ (mono_object_clone_handle (obj, error));
6092 MonoObjectHandle
6093 mono_object_clone_handle (MonoObjectHandle obj, MonoError *error)
6095 MONO_REQ_GC_UNSAFE_MODE;
6097 MonoVTable* const vtable = MONO_HANDLE_GETVAL (obj, vtable);
6098 MonoClass* const klass = vtable->klass;
6100 if (m_class_get_rank (klass))
6101 return MONO_HANDLE_CAST (MonoObject, mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (obj),
6102 MONO_HANDLE_CAST (MonoArray, obj), error));
6104 int const size = m_class_get_instance_size (klass);
6106 MonoObjectHandle o = mono_gc_alloc_handle_obj (vtable, size);
6108 if (G_LIKELY (!MONO_HANDLE_IS_NULL (o))) {
6109 /* If the object doesn't contain references this will do a simple memmove. */
6110 mono_gc_wbarrier_object_copy_handle (o, obj);
6113 return object_new_handle_common_tail (o, klass, error);
6117 * mono_array_full_copy:
6118 * \param src source array to copy
6119 * \param dest destination array
6120 * Copies the content of one array to another with exactly the same type and size.
6122 void
6123 mono_array_full_copy (MonoArray *src, MonoArray *dest)
6125 MONO_REQ_GC_UNSAFE_MODE;
6127 uintptr_t size;
6128 MonoClass *klass = mono_object_class (&src->obj);
6130 g_assert (klass == mono_object_class (&dest->obj));
6132 size = mono_array_length_internal (src);
6133 g_assert (size == mono_array_length_internal (dest));
6134 size *= mono_array_element_size (klass);
6136 array_full_copy_unchecked_size (src, dest, klass, size);
6139 static void
6140 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
6142 if (mono_gc_is_moving ()) {
6143 MonoClass *element_class = m_class_get_element_class (klass);
6144 if (m_class_is_valuetype (element_class)) {
6145 if (m_class_has_references (element_class))
6146 mono_value_copy_array_internal (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length_internal (src));
6147 else
6148 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
6149 } else {
6150 mono_array_memcpy_refs_internal
6151 (dest, 0, src, 0, mono_array_length_internal (src));
6153 } else {
6154 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
6159 * mono_array_clone_in_domain:
6160 * \param domain the domain in which the array will be cloned into
6161 * \param array the array to clone
6162 * \param error set on error
6163 * This routine returns a copy of the array that is hosted on the
6164 * specified \c MonoDomain. On failure returns NULL and sets \p error.
6166 MonoArrayHandle
6167 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
6169 MONO_REQ_GC_UNSAFE_MODE;
6171 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
6172 uintptr_t size = 0;
6173 MonoClass *klass = mono_handle_class (array_handle);
6175 error_init (error);
6177 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
6178 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
6180 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
6181 MonoArrayHandle o;
6182 if (array_bounds == NULL) {
6183 size = mono_array_handle_length (array_handle);
6184 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
6185 goto_if_nok (error, leave);
6186 size *= mono_array_element_size (klass);
6187 } else {
6188 guint8 klass_rank = m_class_get_rank (klass);
6189 uintptr_t *sizes = g_newa (uintptr_t, klass_rank);
6190 intptr_t *lower_bounds = g_newa (intptr_t, klass_rank);
6191 size = mono_array_element_size (klass);
6192 for (int i = 0; i < klass_rank; ++i) {
6193 sizes [i] = array_bounds [i].length;
6194 size *= array_bounds [i].length;
6195 lower_bounds [i] = array_bounds [i].lower_bound;
6197 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
6198 goto_if_nok (error, leave);
6201 uint32_t dst_handle;
6202 dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
6203 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
6204 mono_gchandle_free_internal (dst_handle);
6206 MONO_HANDLE_ASSIGN (result, o);
6208 leave:
6209 mono_gchandle_free_internal (src_handle);
6210 return result;
6214 * mono_array_clone:
6215 * \param array the array to clone
6216 * \returns A newly created array who is a shallow copy of \p array
6218 MonoArray*
6219 mono_array_clone (MonoArray *array)
6221 MONO_REQ_GC_UNSAFE_MODE;
6223 ERROR_DECL (error);
6224 MonoArray *result = mono_array_clone_checked (array, error);
6225 mono_error_cleanup (error);
6226 return result;
6230 * mono_array_clone_checked:
6231 * \param array the array to clone
6232 * \param error set on error
6233 * \returns A newly created array who is a shallow copy of \p array. On
6234 * failure returns NULL and sets \p error.
6236 MonoArray*
6237 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
6239 MONO_REQ_GC_UNSAFE_MODE;
6240 HANDLE_FUNCTION_ENTER ();
6241 /* FIXME: callers of mono_array_clone_checked should use handles */
6242 error_init (error);
6243 MONO_HANDLE_DCL (MonoArray, array);
6244 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
6245 HANDLE_FUNCTION_RETURN_OBJ (result);
6248 /* helper macros to check for overflow when calculating the size of arrays */
6249 #ifdef MONO_BIG_ARRAYS
6250 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
6251 #define MYGUINT_MAX MYGUINT64_MAX
6252 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6253 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
6254 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6255 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
6256 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
6257 #else
6258 #define MYGUINT32_MAX 4294967295U
6259 #define MYGUINT_MAX MYGUINT32_MAX
6260 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6261 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
6262 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6263 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
6264 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
6265 #endif
6267 gboolean
6268 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
6270 MONO_REQ_GC_NEUTRAL_MODE;
6272 uintptr_t byte_len;
6274 byte_len = mono_array_element_size (klass);
6275 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
6276 return FALSE;
6277 byte_len *= len;
6278 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
6279 return FALSE;
6280 byte_len += MONO_SIZEOF_MONO_ARRAY;
6282 *res = byte_len;
6284 return TRUE;
6288 * mono_array_new_full:
6289 * \param domain domain where the object is created
6290 * \param array_class array class
6291 * \param lengths lengths for each dimension in the array
6292 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
6293 * This routine creates a new array object with the given dimensions,
6294 * lower bounds and type.
6296 MonoArray*
6297 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
6299 ERROR_DECL (error);
6300 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, error);
6301 mono_error_cleanup (error);
6303 return array;
6306 MonoArray*
6307 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
6309 MONO_REQ_GC_UNSAFE_MODE;
6311 uintptr_t byte_len = 0, len, bounds_size;
6312 MonoObject *o;
6313 MonoArray *array;
6314 MonoArrayBounds *bounds;
6315 MonoVTable *vtable;
6316 int i;
6318 error_init (error);
6320 if (!m_class_is_inited (array_class))
6321 mono_class_init_internal (array_class);
6323 len = 1;
6325 guint8 array_class_rank = m_class_get_rank (array_class);
6326 /* A single dimensional array with a 0 lower bound is the same as an szarray */
6327 if (array_class_rank == 1 && ((m_class_get_byval_arg (array_class)->type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
6328 len = lengths [0];
6329 if (len > MONO_ARRAY_MAX_INDEX) {
6330 mono_error_set_generic_error (error, "System", "OverflowException", "");
6331 return NULL;
6333 bounds_size = 0;
6334 } else {
6335 bounds_size = sizeof (MonoArrayBounds) * array_class_rank;
6337 for (i = 0; i < array_class_rank; ++i) {
6338 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
6339 mono_error_set_generic_error (error, "System", "OverflowException", "");
6340 return NULL;
6342 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
6343 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6344 return NULL;
6346 len *= lengths [i];
6350 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
6351 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6352 return NULL;
6355 if (bounds_size) {
6356 /* align */
6357 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
6358 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6359 return NULL;
6361 byte_len = (byte_len + 3) & ~3;
6362 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
6363 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6364 return NULL;
6366 byte_len += bounds_size;
6369 * Following three lines almost taken from mono_object_new ():
6370 * they need to be kept in sync.
6372 vtable = mono_class_vtable_checked (domain, array_class, error);
6373 return_val_if_nok (error, NULL);
6375 if (bounds_size)
6376 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
6377 else
6378 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
6380 if (G_UNLIKELY (!o)) {
6381 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
6382 return NULL;
6385 array = (MonoArray*)o;
6387 bounds = array->bounds;
6389 if (bounds_size) {
6390 for (i = 0; i < array_class_rank; ++i) {
6391 bounds [i].length = lengths [i];
6392 if (lower_bounds)
6393 bounds [i].lower_bound = lower_bounds [i];
6397 return array;
6401 * mono_array_new:
6402 * \param domain domain where the object is created
6403 * \param eclass element class
6404 * \param n number of array elements
6405 * This routine creates a new szarray with \p n elements of type \p eclass.
6407 MonoArray *
6408 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6410 MonoArray *result;
6411 MONO_ENTER_GC_UNSAFE;
6413 ERROR_DECL (error);
6414 result = mono_array_new_checked (domain, eclass, n, error);
6415 mono_error_cleanup (error);
6416 MONO_EXIT_GC_UNSAFE;
6417 return result;
6421 * mono_array_new_checked:
6422 * \param domain domain where the object is created
6423 * \param eclass element class
6424 * \param n number of array elements
6425 * \param error set on error
6426 * This routine creates a new szarray with \p n elements of type \p eclass.
6427 * On failure returns NULL and sets \p error.
6429 MonoArray *
6430 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
6432 MonoClass *ac;
6434 error_init (error);
6436 ac = mono_class_create_array (eclass, 1);
6437 g_assert (ac);
6439 MonoVTable *vtable = mono_class_vtable_checked (domain, ac, error);
6440 return_val_if_nok (error, NULL);
6442 return mono_array_new_specific_checked (vtable, n, error);
6445 MonoArray*
6446 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6448 ERROR_DECL (error);
6449 MonoArray *arr = mono_array_new_checked (domain, eclass, n, error);
6450 mono_error_set_pending_exception (error);
6452 return arr;
6456 * mono_array_new_specific:
6457 * \param vtable a vtable in the appropriate domain for an initialized class
6458 * \param n number of array elements
6459 * This routine is a fast alternative to \c mono_array_new for code which
6460 * can be sure about the domain it operates in.
6462 MonoArray *
6463 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
6465 ERROR_DECL (error);
6466 MonoArray *arr = mono_array_new_specific_checked (vtable, n, error);
6467 mono_error_cleanup (error);
6469 return arr;
6472 MonoArray*
6473 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
6475 MONO_REQ_GC_UNSAFE_MODE;
6477 MonoObject *o;
6478 uintptr_t byte_len;
6480 error_init (error);
6482 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6483 mono_error_set_generic_error (error, "System", "OverflowException", "");
6484 return NULL;
6487 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6488 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6489 return NULL;
6491 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6493 if (G_UNLIKELY (!o)) {
6494 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
6495 return NULL;
6498 return (MonoArray*)o;
6502 MonoArrayHandle
6503 mono_array_new_specific_handle (MonoVTable *vtable, uintptr_t n, MonoError *error)
6505 // FIXMEcoop invert relationship with mono_array_new_specific_checked
6506 return MONO_HANDLE_NEW (MonoArray, mono_array_new_specific_checked (vtable, n, error));
6509 MonoArray*
6510 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6512 ERROR_DECL (error);
6513 MonoArray *arr = mono_array_new_specific_checked (vtable, n, error);
6514 mono_error_set_pending_exception (error);
6516 return arr;
6520 * mono_string_empty_wrapper:
6522 * Returns: The same empty string instance as the managed string.Empty
6524 MonoString*
6525 mono_string_empty_wrapper (void)
6527 MonoDomain *domain = mono_domain_get ();
6528 return mono_string_empty_internal (domain);
6531 MonoString*
6532 mono_string_empty_internal (MonoDomain *domain)
6534 g_assert (domain);
6535 g_assert (domain->empty_string);
6536 return domain->empty_string;
6540 * mono_string_empty:
6542 * Returns: The same empty string instance as the managed string.Empty
6544 MonoString*
6545 mono_string_empty (MonoDomain *domain)
6547 MONO_EXTERNAL_ONLY (MonoString*, mono_string_empty_internal (domain));
6550 MonoStringHandle
6551 mono_string_empty_handle (MonoDomain *domain)
6553 return MONO_HANDLE_NEW (MonoString, mono_string_empty_internal (domain));
6557 * mono_string_new_utf16:
6558 * \param text a pointer to an utf16 string
6559 * \param len the length of the string
6560 * \returns A newly created string object which contains \p text.
6562 MonoString *
6563 mono_string_new_utf16 (MonoDomain *domain, const mono_unichar2 *text, gint32 len)
6565 MONO_REQ_GC_UNSAFE_MODE;
6567 ERROR_DECL (error);
6568 MonoString *res = NULL;
6569 res = mono_string_new_utf16_checked (domain, text, len, error);
6570 mono_error_cleanup (error);
6572 return res;
6576 * mono_string_new_utf16_checked:
6577 * \param text a pointer to an utf16 string
6578 * \param len the length of the string
6579 * \param error written on error.
6580 * \returns A newly created string object which contains \p text.
6581 * On error, returns NULL and sets \p error.
6583 MonoString *
6584 mono_string_new_utf16_checked (MonoDomain *domain, const gunichar2 *text, gint32 len, MonoError *error)
6586 MONO_REQ_GC_UNSAFE_MODE;
6588 MonoString *s;
6590 error_init (error);
6592 s = mono_string_new_size_checked (domain, len, error);
6593 if (s != NULL)
6594 memcpy (mono_string_chars_internal (s), text, len * 2);
6596 return s;
6600 * mono_string_new_utf16_handle:
6601 * \param text a pointer to an utf16 string
6602 * \param len the length of the string
6603 * \param error written on error.
6604 * \returns A newly created string object which contains \p text.
6605 * On error, returns NULL and sets \p error.
6607 MonoStringHandle
6608 mono_string_new_utf16_handle (MonoDomain *domain, const gunichar2 *text, gint32 len, MonoError *error)
6610 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6614 * mono_string_new_utf32_checked:
6615 * \param text a pointer to an utf32 string
6616 * \param len the length of the string
6617 * \param error set on failure.
6618 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6620 static MonoString *
6621 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6623 MONO_REQ_GC_UNSAFE_MODE;
6625 MonoString *s;
6626 mono_unichar2 *utf16_output = NULL;
6628 error_init (error);
6629 utf16_output = g_ucs4_to_utf16 (text, len, NULL, NULL, NULL);
6631 gint32 utf16_len = g_utf16_len (utf16_output);
6633 s = mono_string_new_size_checked (domain, utf16_len, error);
6634 goto_if_nok (error, exit);
6636 memcpy (mono_string_chars_internal (s), utf16_output, utf16_len * 2);
6638 exit:
6639 g_free (utf16_output);
6641 return s;
6645 * mono_string_new_utf32:
6646 * \param text a pointer to a UTF-32 string
6647 * \param len the length of the string
6648 * \returns A newly created string object which contains \p text.
6650 MonoString *
6651 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6653 ERROR_DECL (error);
6654 MonoString *result = mono_string_new_utf32_checked (domain, text, len, error);
6655 mono_error_cleanup (error);
6656 return result;
6660 * mono_string_new_size:
6661 * \param text a pointer to a UTF-16 string
6662 * \param len the length of the string
6663 * \returns A newly created string object of \p len
6665 MonoString *
6666 mono_string_new_size (MonoDomain *domain, gint32 len)
6668 ERROR_DECL (error);
6669 MonoString *str = mono_string_new_size_checked (domain, len, error);
6670 mono_error_cleanup (error);
6672 return str;
6675 MonoStringHandle
6676 mono_string_new_size_handle (MonoDomain *domain, gint32 len, MonoError *error)
6678 MONO_REQ_GC_UNSAFE_MODE;
6680 MonoStringHandle s;
6681 MonoVTable *vtable;
6682 size_t size;
6684 error_init (error);
6686 /* check for overflow */
6687 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6688 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6689 return NULL_HANDLE_STRING;
6692 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6693 g_assert (size > 0);
6695 vtable = mono_class_vtable_checked (domain, mono_defaults.string_class, error);
6696 return_val_if_nok (error, NULL_HANDLE_STRING);
6698 s = mono_gc_alloc_handle_string (vtable, size, len);
6700 if (G_UNLIKELY (MONO_HANDLE_IS_NULL (s)))
6701 mono_error_set_out_of_memory (error, "Could not allocate %" G_GSIZE_FORMAT " bytes", size);
6703 return s;
6706 MonoString *
6707 mono_string_new_size_checked (MonoDomain *domain, gint32 length, MonoError *error)
6709 HANDLE_FUNCTION_ENTER ();
6710 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_size_handle (domain, length, error));
6714 * mono_string_new_len:
6715 * \param text a pointer to an utf8 string
6716 * \param length number of bytes in \p text to consider
6717 * \returns A newly created string object which contains \p text.
6719 MonoString*
6720 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6722 HANDLE_FUNCTION_ENTER ();
6723 ERROR_DECL (error);
6724 MonoStringHandle result;
6726 MONO_ENTER_GC_UNSAFE;
6727 result = mono_string_new_utf8_len (domain, text, length, error);
6728 MONO_EXIT_GC_UNSAFE;
6730 mono_error_cleanup (error);
6731 HANDLE_FUNCTION_RETURN_OBJ (result);
6735 * mono_string_new_utf8_len:
6736 * \param text a pointer to an utf8 string
6737 * \param length number of bytes in \p text to consider
6738 * \param error set on error
6739 * \returns A newly created string object which contains \p text. On
6740 * failure returns NULL and sets \p error.
6742 MonoStringHandle
6743 mono_string_new_utf8_len (MonoDomain *domain, const char *text, guint length, MonoError *error)
6745 MONO_REQ_GC_UNSAFE_MODE;
6747 error_init (error);
6749 GError *eg_error = NULL;
6750 MonoStringHandle o = NULL_HANDLE_STRING;
6751 gunichar2 *ut = NULL;
6752 glong items_written;
6754 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6756 if (eg_error) {
6757 o = NULL_HANDLE_STRING;
6758 // Like mono_ldstr_utf8:
6759 mono_error_set_argument (error, "string", eg_error->message);
6760 // FIXME? See mono_string_new_checked.
6761 //mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6762 g_error_free (eg_error);
6763 } else {
6764 o = mono_string_new_utf16_handle (domain, ut, items_written, error);
6767 g_free (ut);
6769 return o;
6772 MonoString*
6773 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6775 HANDLE_FUNCTION_ENTER ();
6776 error_init (error);
6777 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_utf8_len (domain, text, length, error));
6780 static
6781 MonoString*
6782 mono_string_new_internal (MonoDomain *domain, const char *text)
6784 ERROR_DECL (error);
6785 MonoString *res = NULL;
6786 res = mono_string_new_checked (domain, text, error);
6787 if (!is_ok (error)) {
6788 /* Mono API compatability: assert on Out of Memory errors,
6789 * return NULL otherwise (most likely an invalid UTF-8 byte
6790 * sequence). */
6791 if (mono_error_get_error_code (error) == MONO_ERROR_OUT_OF_MEMORY)
6792 mono_error_assert_ok (error);
6793 else
6794 mono_error_cleanup (error);
6796 return res;
6800 * mono_string_new:
6801 * \param text a pointer to a UTF-8 string
6802 * \deprecated Use \c mono_string_new_checked in new code.
6803 * This function asserts if it cannot allocate a new string.
6804 * \returns A newly created string object which contains \p text.
6806 MonoString*
6807 mono_string_new (MonoDomain *domain, const char *text)
6809 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoString*, mono_string_new_internal (domain, text));
6813 * mono_string_new_checked:
6814 * \param text a pointer to an utf8 string
6815 * \param merror set on error
6816 * \returns A newly created string object which contains \p text.
6817 * On error returns NULL and sets \p merror.
6819 MonoString*
6820 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6822 MONO_REQ_GC_UNSAFE_MODE;
6824 GError *eg_error = NULL;
6825 MonoString *o = NULL;
6826 gunichar2 *ut;
6827 glong items_written;
6828 int len;
6830 error_init (error);
6832 len = strlen (text);
6834 ut = g_utf8_to_utf16 (text, len, NULL, &items_written, &eg_error);
6836 if (!eg_error)
6837 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6838 else {
6839 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6840 g_error_free (eg_error);
6843 g_free (ut);
6845 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6846 #if 0
6847 gunichar2 *str;
6848 const gchar *end;
6849 int len;
6850 MonoString *o = NULL;
6852 if (!g_utf8_validate (text, -1, &end)) {
6853 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6854 goto leave;
6857 len = g_utf8_strlen (text, -1);
6858 o = mono_string_new_size_checked (domain, len, error);
6859 if (!o)
6860 goto leave;
6861 str = mono_string_chars_internal (o);
6863 while (text < end) {
6864 *str++ = g_utf8_get_char (text);
6865 text = g_utf8_next_char (text);
6868 leave:
6869 #endif
6870 return o;
6874 * mono_string_new_wtf8_len_checked:
6875 * \param text a pointer to an wtf8 string (see https://simonsapin.github.io/wtf-8/)
6876 * \param length number of bytes in \p text to consider
6877 * \param merror set on error
6878 * \returns A newly created string object which contains \p text.
6879 * On error returns NULL and sets \p merror.
6881 MonoString*
6882 mono_string_new_wtf8_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6884 MONO_REQ_GC_UNSAFE_MODE;
6886 error_init (error);
6888 GError *eg_error = NULL;
6889 MonoString *o = NULL;
6890 gunichar2 *ut = NULL;
6891 glong items_written;
6893 ut = eg_wtf8_to_utf16 (text, length, NULL, &items_written, &eg_error);
6895 if (!eg_error)
6896 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6897 else
6898 g_error_free (eg_error);
6900 g_free (ut);
6902 return o;
6905 MonoStringHandle
6906 mono_string_new_wrapper_internal_impl (const char *text, MonoError *error)
6908 return MONO_HANDLE_NEW (MonoString, mono_string_new_internal (mono_domain_get (), text));
6912 * mono_string_new_wrapper:
6913 * \param text pointer to UTF-8 characters.
6914 * Helper function to create a string object from \p text in the current domain.
6916 MonoString*
6917 mono_string_new_wrapper (const char *text)
6919 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoString*, mono_string_new_wrapper_internal (text));
6923 * mono_value_box:
6924 * \param class the class of the value
6925 * \param value a pointer to the unboxed data
6926 * \returns A newly created object which contains \p value.
6928 MonoObject *
6929 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6931 MonoObject *result;
6932 MONO_ENTER_GC_UNSAFE;
6933 ERROR_DECL (error);
6934 result = mono_value_box_checked (domain, klass, value, error);
6935 mono_error_cleanup (error);
6936 MONO_EXIT_GC_UNSAFE;
6937 return result;
6941 * mono_value_box_handle:
6942 * \param domain the domain of the new object
6943 * \param class the class of the value
6944 * \param value a pointer to the unboxed data
6945 * \param error set on error
6946 * \returns A newly created object which contains \p value. On failure
6947 * returns NULL and sets \p error.
6949 MonoObjectHandle
6950 mono_value_box_handle (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6952 // FIXMEcoop gpointer value needs more attention
6953 MONO_REQ_GC_UNSAFE_MODE;
6954 MonoVTable *vtable;
6956 error_init (error);
6958 g_assert (m_class_is_valuetype (klass));
6959 g_assert (value != NULL);
6960 if (G_UNLIKELY (m_class_is_byreflike (klass))) {
6961 char *full_name = mono_type_get_full_name (klass);
6962 mono_error_set_execution_engine (error, "Cannot box IsByRefLike type %s", full_name);
6963 g_free (full_name);
6964 return NULL_HANDLE;
6966 if (mono_class_is_nullable (klass))
6967 return mono_nullable_box_handle (value, klass, error);
6969 vtable = mono_class_vtable_checked (domain, klass, error);
6970 return_val_if_nok (error, NULL_HANDLE);
6972 int size = mono_class_instance_size (klass);
6974 MonoObjectHandle res_handle = mono_object_new_alloc_by_vtable (vtable, error);
6975 return_val_if_nok (error, NULL_HANDLE);
6977 size -= MONO_ABI_SIZEOF (MonoObject);
6978 if (mono_gc_is_moving ()) {
6979 g_assert (size == mono_class_value_size (klass, NULL));
6980 MONO_ENTER_NO_SAFEPOINTS;
6981 gpointer data = mono_handle_get_data_unsafe (res_handle);
6982 mono_gc_wbarrier_value_copy_internal (data, value, 1, klass);
6983 MONO_EXIT_NO_SAFEPOINTS;
6984 } else {
6985 MONO_ENTER_NO_SAFEPOINTS;
6986 gpointer data = mono_handle_get_data_unsafe (res_handle);
6987 #if NO_UNALIGNED_ACCESS
6988 mono_gc_memmove_atomic (data, value, size);
6989 #else
6990 switch (size) {
6991 case 1:
6992 *(guint8*)data = *(guint8 *) value;
6993 break;
6994 case 2:
6995 *(guint16 *)(data) = *(guint16 *) value;
6996 break;
6997 case 4:
6998 *(guint32 *)(data) = *(guint32 *) value;
6999 break;
7000 case 8:
7001 *(guint64 *)(data) = *(guint64 *) value;
7002 break;
7003 default:
7004 mono_gc_memmove_atomic (data, value, size);
7006 #endif
7007 MONO_EXIT_NO_SAFEPOINTS;
7009 if (m_class_has_finalize (klass))
7010 mono_object_register_finalizer_handle (res_handle);
7012 return res_handle;
7016 * mono_value_box_checked:
7017 * \param domain the domain of the new object
7018 * \param class the class of the value
7019 * \param value a pointer to the unboxed data
7020 * \param error set on error
7021 * \returns A newly created object which contains \p value. On failure
7022 * returns NULL and sets \p error.
7024 MonoObject *
7025 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
7027 HANDLE_FUNCTION_ENTER ();
7028 HANDLE_FUNCTION_RETURN_OBJ (mono_value_box_handle (domain, klass, value, error));
7031 void
7032 mono_value_copy_internal (gpointer dest, gpointer src, MonoClass *klass)
7034 MONO_REQ_GC_UNSAFE_MODE;
7036 mono_gc_wbarrier_value_copy_internal (dest, src, 1, klass);
7040 * mono_value_copy:
7041 * \param dest destination pointer
7042 * \param src source pointer
7043 * \param klass a valuetype class
7044 * Copy a valuetype from \p src to \p dest. This function must be used
7045 * when \p klass contains reference fields.
7047 void
7048 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
7050 mono_value_copy_internal (dest, src, klass);
7053 void
7054 mono_value_copy_array_internal (MonoArray *dest, int dest_idx, gconstpointer src, int count)
7056 MONO_REQ_GC_UNSAFE_MODE;
7058 int size = mono_array_element_size (dest->obj.vtable->klass);
7059 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
7060 g_assert (size == mono_class_value_size (m_class_get_element_class (mono_object_class (dest)), NULL));
7061 // FIXME remove (gpointer) cast.
7062 mono_gc_wbarrier_value_copy_internal (d, (gpointer)src, count, m_class_get_element_class (mono_object_class (dest)));
7065 void
7066 mono_value_copy_array_handle (MonoArrayHandle dest, int dest_idx, gconstpointer src, int count)
7068 mono_value_copy_array_internal (MONO_HANDLE_RAW (dest), dest_idx, src, count);
7072 * mono_value_copy_array:
7073 * \param dest destination array
7074 * \param dest_idx index in the \p dest array
7075 * \param src source pointer
7076 * \param count number of items
7077 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
7078 * This function must be used when \p klass contains references fields.
7079 * Overlap is handled.
7081 void
7082 mono_value_copy_array (MonoArray *dest, int dest_idx, void* src, int count)
7084 MONO_EXTERNAL_ONLY_VOID (mono_value_copy_array_internal (dest, dest_idx, src, count));
7087 MonoVTable *
7088 mono_object_get_vtable_internal (MonoObject *obj)
7090 // This could be called during STW, so untag the vtable if needed.
7091 return mono_gc_get_vtable (obj);
7094 MonoVTable*
7095 mono_object_get_vtable (MonoObject *obj)
7097 MONO_EXTERNAL_ONLY (MonoVTable*, mono_object_get_vtable_internal (obj));
7100 MonoDomain*
7101 mono_object_get_domain_internal (MonoObject *obj)
7103 MONO_REQ_GC_UNSAFE_MODE;
7105 return mono_object_domain (obj);
7109 * mono_object_get_domain:
7110 * \param obj object to query
7111 * \returns the \c MonoDomain where the object is hosted
7113 MonoDomain*
7114 mono_object_get_domain (MonoObject *obj)
7116 MONO_EXTERNAL_ONLY (MonoDomain*, mono_object_get_domain_internal (obj));
7120 * mono_object_get_class:
7121 * \param obj object to query
7122 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
7123 * \returns the \c MonoClass of the object.
7125 MonoClass*
7126 mono_object_get_class (MonoObject *obj)
7128 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoClass*, mono_object_class (obj));
7131 guint
7132 mono_object_get_size_internal (MonoObject* o)
7134 MONO_REQ_GC_UNSAFE_MODE;
7136 MonoClass* klass = mono_object_class (o);
7137 if (klass == mono_defaults.string_class) {
7138 return MONO_SIZEOF_MONO_STRING + 2 * mono_string_length_internal ((MonoString*) o) + 2;
7139 } else if (o->vtable->rank) {
7140 MonoArray *array = (MonoArray*)o;
7141 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length_internal (array);
7142 if (array->bounds) {
7143 size += 3;
7144 size &= ~3;
7145 size += sizeof (MonoArrayBounds) * o->vtable->rank;
7147 return size;
7148 } else {
7149 return mono_class_instance_size (klass);
7154 * mono_object_get_size:
7155 * \param o object to query
7156 * \returns the size, in bytes, of \p o
7158 unsigned
7159 mono_object_get_size (MonoObject *o)
7161 MONO_EXTERNAL_ONLY (unsigned, mono_object_get_size_internal (o));
7164 gpointer
7165 mono_object_unbox_internal (MonoObject *obj)
7167 /* add assert for valuetypes? */
7168 g_assert (m_class_is_valuetype (mono_object_class (obj)));
7169 return mono_object_get_data (obj);
7173 * mono_object_unbox:
7174 * \param obj object to unbox
7175 * \returns a pointer to the start of the valuetype boxed in this
7176 * object.
7178 * This method will assert if the object passed is not a valuetype.
7180 void*
7181 mono_object_unbox (MonoObject *obj)
7183 MONO_EXTERNAL_ONLY_GC_UNSAFE (void*, mono_object_unbox_internal (obj));
7187 * mono_object_isinst:
7188 * \param obj an object
7189 * \param klass a pointer to a class
7190 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
7192 MonoObject *
7193 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
7195 HANDLE_FUNCTION_ENTER ();
7196 MonoObjectHandle result;
7197 MONO_ENTER_GC_UNSAFE;
7199 MONO_HANDLE_DCL (MonoObject, obj);
7200 ERROR_DECL (error);
7201 result = mono_object_handle_isinst (obj, klass, error);
7202 mono_error_cleanup (error);
7203 MONO_EXIT_GC_UNSAFE;
7204 HANDLE_FUNCTION_RETURN_OBJ (result);
7208 * mono_object_isinst_checked:
7209 * \param obj an object
7210 * \param klass a pointer to a class
7211 * \param error set on error
7212 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7213 * On failure returns NULL and sets \p error.
7215 MonoObject *
7216 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
7218 MONO_REQ_GC_UNSAFE_MODE;
7220 HANDLE_FUNCTION_ENTER ();
7221 error_init (error);
7222 MONO_HANDLE_DCL (MonoObject, obj);
7223 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
7224 HANDLE_FUNCTION_RETURN_OBJ (result);
7228 * mono_object_handle_isinst:
7229 * \param obj an object
7230 * \param klass a pointer to a class
7231 * \param error set on error
7232 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7233 * On failure returns NULL and sets \p error.
7235 MonoObjectHandle
7236 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7238 error_init (error);
7240 if (!m_class_is_inited (klass))
7241 mono_class_init_internal (klass);
7243 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
7244 return mono_object_handle_isinst_mbyref (obj, klass, error);
7247 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7249 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from_internal (klass, mono_handle_class (obj)))
7250 MONO_HANDLE_ASSIGN (result, obj);
7251 return result;
7255 * mono_object_isinst_mbyref:
7257 MonoObject *
7258 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
7260 MONO_REQ_GC_UNSAFE_MODE;
7262 HANDLE_FUNCTION_ENTER ();
7263 ERROR_DECL (error);
7264 MONO_HANDLE_DCL (MonoObject, obj);
7265 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, error);
7266 mono_error_cleanup (error); /* FIXME better API that doesn't swallow the error */
7267 HANDLE_FUNCTION_RETURN_OBJ (result);
7270 MonoObjectHandle
7271 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7273 gboolean success = FALSE;
7274 error_init (error);
7276 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7278 if (MONO_HANDLE_IS_NULL (obj))
7279 goto leave;
7281 success = mono_object_handle_isinst_mbyref_raw (obj, klass, error);
7282 if (success && is_ok (error))
7283 MONO_HANDLE_ASSIGN (result, obj);
7285 leave:
7286 return result;
7289 gboolean
7290 mono_object_handle_isinst_mbyref_raw (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
7292 error_init (error);
7294 gboolean result = FALSE;
7296 if (MONO_HANDLE_IS_NULL (obj))
7297 goto leave;
7299 MonoVTable *vt;
7300 vt = MONO_HANDLE_GETVAL (obj, vtable);
7302 if (mono_class_is_interface (klass)) {
7303 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, m_class_get_interface_id (klass))) {
7304 result = TRUE;
7305 goto leave;
7308 /* casting an array one of the invariant interfaces that must act as such */
7309 if (m_class_is_array_special_interface (klass)) {
7310 if (mono_class_is_assignable_from_internal (klass, vt->klass)) {
7311 result = TRUE;
7312 goto leave;
7316 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
7317 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from_internal (klass, mono_handle_class (obj))) {
7318 result = TRUE;
7319 goto leave;
7321 } else {
7322 MonoClass *oklass = vt->klass;
7323 if (mono_class_is_transparent_proxy (oklass)){
7324 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
7325 oklass = remote_class->proxy_class;
7328 mono_class_setup_supertypes (klass);
7329 if (mono_class_has_parent_fast (oklass, klass)) {
7330 result = TRUE;
7331 goto leave;
7334 #ifndef DISABLE_REMOTING
7335 if (mono_class_is_transparent_proxy (vt->klass))
7337 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
7338 if (!custom_type_info)
7339 goto leave;
7340 MonoDomain *domain = mono_domain_get ();
7341 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
7342 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
7343 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
7344 MonoMethod *im = NULL;
7345 gpointer pa [2];
7347 im = mono_class_get_method_from_name_checked (rpklass, "CanCastTo", -1, 0, error);
7348 goto_if_nok (error, leave);
7349 if (!im) {
7350 mono_error_set_not_supported (error, "Linked away.");
7351 goto leave;
7353 im = mono_object_handle_get_virtual_method (rp, im, error);
7354 goto_if_nok (error, leave);
7355 g_assert (im);
7357 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, m_class_get_byval_arg (klass), error);
7358 goto_if_nok (error, leave);
7360 pa [0] = MONO_HANDLE_RAW (reftype);
7361 pa [1] = MONO_HANDLE_RAW (obj);
7362 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
7363 goto_if_nok (error, leave);
7365 if (*(MonoBoolean *) mono_object_unbox_internal (res)) {
7366 /* Update the vtable of the remote type, so it can safely cast to this new type */
7367 mono_upgrade_remote_class (domain, obj, klass, error);
7368 goto_if_nok (error, leave);
7369 result = TRUE;
7370 goto leave;
7373 #endif /* DISABLE_REMOTING */
7374 leave:
7375 return result;
7379 * mono_object_castclass_mbyref:
7380 * \param obj an object
7381 * \param klass a pointer to a class
7382 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
7384 MonoObject *
7385 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
7387 MONO_REQ_GC_UNSAFE_MODE;
7388 HANDLE_FUNCTION_ENTER ();
7389 ERROR_DECL (error);
7390 MONO_HANDLE_DCL (MonoObject, obj);
7391 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
7392 if (MONO_HANDLE_IS_NULL (obj))
7393 goto leave;
7394 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, error));
7395 mono_error_cleanup (error);
7396 leave:
7397 HANDLE_FUNCTION_RETURN_OBJ (result);
7400 static MonoStringHandle
7401 mono_string_get_pinned (MonoStringHandle str, MonoError *error)
7403 MONO_REQ_GC_UNSAFE_MODE;
7405 error_init (error);
7407 /* We only need to make a pinned version of a string if this is a moving GC */
7408 if (!mono_gc_is_moving ())
7409 return str;
7411 const gsize length = mono_string_handle_length (str);
7412 const gsize size = MONO_SIZEOF_MONO_STRING + (length + 1) * sizeof (gunichar2);
7413 MonoStringHandle news = MONO_HANDLE_CAST (MonoString, mono_gc_alloc_handle_pinned_obj (MONO_HANDLE_GETVAL (str, object.vtable), size));
7414 if (!MONO_HANDLE_BOOL (news)) {
7415 mono_error_set_out_of_memory (error, "Could not allocate %" G_GSIZE_FORMAT " bytes", size);
7416 return news;
7419 MONO_ENTER_NO_SAFEPOINTS;
7421 memcpy (mono_string_chars_internal (MONO_HANDLE_RAW (news)),
7422 mono_string_chars_internal (MONO_HANDLE_RAW (str)),
7423 length * sizeof (gunichar2));
7425 MONO_EXIT_NO_SAFEPOINTS;
7427 MONO_HANDLE_SETVAL (news, length, int, length);
7428 return news;
7431 MonoStringHandle
7432 mono_string_is_interned_lookup (MonoStringHandle str, gboolean insert, MonoError *error)
7434 MONO_REQ_GC_UNSAFE_MODE;
7436 MonoGHashTable *ldstr_table = MONO_HANDLE_DOMAIN (str)->ldstr_table;
7437 ldstr_lock ();
7438 MonoString *res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, MONO_HANDLE_RAW (str));
7439 ldstr_unlock ();
7440 if (res)
7441 return MONO_HANDLE_NEW (MonoString, res);
7442 if (!insert)
7443 return NULL_HANDLE_STRING;
7445 // Allocate outside the lock.
7446 MonoStringHandle s = mono_string_get_pinned (str, error);
7447 if (!is_ok (error) || !MONO_HANDLE_BOOL (s))
7448 return NULL_HANDLE_STRING;
7450 // Try again inside lock.
7451 ldstr_lock ();
7452 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, MONO_HANDLE_RAW (str));
7453 if (res)
7454 MONO_HANDLE_ASSIGN_RAW (s, res);
7455 else
7456 mono_g_hash_table_insert_internal (ldstr_table, MONO_HANDLE_RAW (s), MONO_HANDLE_RAW (s));
7457 ldstr_unlock ();
7458 return s;
7462 * mono_string_is_interned:
7463 * \param o String to probe
7464 * \returns Whether the string has been interned.
7466 MonoString*
7467 mono_string_is_interned (MonoString *str_raw)
7469 ERROR_DECL (error);
7470 HANDLE_FUNCTION_ENTER ();
7471 MONO_HANDLE_DCL (MonoString, str);
7472 MONO_ENTER_GC_UNSAFE;
7473 str = mono_string_is_interned_internal (str, error);
7474 MONO_EXIT_GC_UNSAFE;
7475 mono_error_assert_ok (error);
7476 HANDLE_FUNCTION_RETURN_OBJ (str);
7480 * mono_string_intern:
7481 * \param o String to intern
7482 * Interns the string passed.
7483 * \returns The interned string.
7485 MonoString*
7486 mono_string_intern (MonoString *str_raw)
7488 ERROR_DECL (error);
7489 HANDLE_FUNCTION_ENTER ();
7490 MONO_HANDLE_DCL (MonoString, str);
7491 MONO_ENTER_GC_UNSAFE;
7492 str = mono_string_intern_checked (str, error);
7493 MONO_EXIT_GC_UNSAFE;
7494 HANDLE_FUNCTION_RETURN_OBJ (str);
7498 * mono_ldstr:
7499 * \param domain the domain where the string will be used.
7500 * \param image a metadata context
7501 * \param idx index into the user string table.
7502 * Implementation for the \c ldstr opcode.
7503 * \returns a loaded string from the \p image / \p idx combination.
7505 MonoString*
7506 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
7508 ERROR_DECL (error);
7509 MonoString *result = mono_ldstr_checked (domain, image, idx, error);
7510 mono_error_cleanup (error);
7511 return result;
7515 * mono_ldstr_checked:
7516 * \param domain the domain where the string will be used.
7517 * \param image a metadata context
7518 * \param idx index into the user string table.
7519 * \param error set on error.
7520 * Implementation for the \c ldstr opcode.
7521 * \returns A loaded string from the \p image / \p idx combination.
7522 * On failure returns NULL and sets \p error.
7524 MonoString*
7525 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
7527 MONO_REQ_GC_UNSAFE_MODE;
7528 error_init (error);
7530 HANDLE_FUNCTION_ENTER ();
7532 MonoString* str = NULL;
7534 if (image->dynamic) {
7535 str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
7536 goto exit;
7538 if (!mono_verifier_verify_string_signature (image, idx, error))
7539 goto exit;
7540 // FIXMEcoop
7541 str = MONO_HANDLE_RAW (mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error));
7542 exit:
7543 HANDLE_FUNCTION_RETURN_VAL (str);
7546 MonoStringHandle
7547 mono_ldstr_handle (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
7549 // FIXME invert mono_ldstr_handle and mono_ldstr_checked.
7550 return MONO_HANDLE_NEW (MonoString, mono_ldstr_checked (domain, image, idx, error));
7553 char*
7554 mono_string_from_blob (const char *str, MonoError *error)
7556 gsize len = mono_metadata_decode_blob_size (str, &str) >> 1;
7558 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7559 gunichar2 *src = (gunichar2*)str;
7560 gunichar2 *copy = g_new (gunichar2, len);
7561 int i;
7562 for (i = 0; i < len; ++i)
7563 copy [i] = GUINT16_FROM_LE (src [i]);
7565 char *res = mono_utf16_to_utf8 (copy, len, error);
7566 g_free (copy);
7567 return res;
7568 #else
7569 return mono_utf16_to_utf8 ((const gunichar2*)str, len, error);
7570 #endif
7573 * mono_ldstr_metadata_sig
7574 * \param domain the domain for the string
7575 * \param sig the signature of a metadata string
7576 * \param error set on error
7577 * \returns a \c MonoString for a string stored in the metadata. On
7578 * failure returns NULL and sets \p error.
7580 static MonoStringHandle
7581 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
7583 MONO_REQ_GC_UNSAFE_MODE;
7585 error_init (error);
7587 const gsize len = mono_metadata_decode_blob_size (sig, &sig) / sizeof (gunichar2);
7589 MonoStringHandle o = mono_string_new_utf16_handle (domain, (gunichar2*)sig, len, error);
7590 return_val_if_nok (error, NULL_HANDLE_STRING);
7591 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7592 gunichar2 *p = mono_string_chars_internal (MONO_HANDLE_RAW (o));
7593 for (gsize i = 0; i < len; ++i)
7594 p [i] = GUINT16_FROM_LE (p [i]);
7595 #endif
7596 return mono_string_intern_checked (o, error);
7600 * mono_ldstr_utf8:
7602 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
7603 * of an object.
7605 char*
7606 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
7608 const char *str;
7609 size_t len2;
7610 long written = 0;
7611 char *as;
7612 GError *gerror = NULL;
7614 error_init (error);
7616 if (!mono_verifier_verify_string_signature (image, idx, error))
7617 return NULL;
7618 str = mono_metadata_user_string (image, idx);
7620 len2 = mono_metadata_decode_blob_size (str, &str);
7621 len2 >>= 1;
7623 as = g_utf16_to_utf8 ((gunichar2*)str, len2, NULL, &written, &gerror);
7624 if (gerror) {
7625 mono_error_set_argument (error, "string", gerror->message);
7626 g_error_free (gerror);
7627 return NULL;
7629 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7630 if (len2 > written) {
7631 /* allocate the total length and copy the part of the string that has been converted */
7632 char *as2 = (char *)g_malloc0 (len2);
7633 memcpy (as2, as, written);
7634 g_free (as);
7635 as = as2;
7638 return as;
7642 * mono_string_to_utf8:
7643 * \param s a \c System.String
7644 * \deprecated Use \c mono_string_to_utf8_checked_internal to avoid having an exception arbitrarily raised.
7645 * \returns the UTF-8 representation for \p s.
7646 * The resulting buffer needs to be freed with \c mono_free().
7648 char *
7649 mono_string_to_utf8 (MonoString *s)
7651 char *result;
7652 ERROR_DECL (error);
7653 result = mono_string_to_utf8_checked_internal (s, error);
7655 if (!is_ok (error)) {
7656 mono_error_cleanup (error);
7657 result = NULL;
7659 return result;
7663 * mono_utf16_to_utf8len:
7665 char *
7666 mono_utf16_to_utf8len (const gunichar2 *s, gsize slength, gsize *utf8_length, MonoError *error)
7668 MONO_REQ_GC_UNSAFE_MODE;
7670 long written = 0;
7671 *utf8_length = 0;
7672 char *as;
7673 GError *gerror = NULL;
7675 error_init (error);
7677 if (s == NULL)
7678 return NULL;
7680 if (!slength)
7681 return g_strdup ("");
7683 as = g_utf16_to_utf8 (s, slength, NULL, &written, &gerror);
7684 *utf8_length = written;
7685 if (gerror) {
7686 mono_error_set_argument (error, "string", gerror->message);
7687 g_error_free (gerror);
7688 return NULL;
7690 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7691 if (slength > written) {
7692 /* allocate the total length and copy the part of the string that has been converted */
7693 char *as2 = (char *)g_malloc0 (slength);
7694 memcpy (as2, as, written);
7695 g_free (as);
7696 as = as2;
7698 // FIXME utf8_length is ambiguous here.
7699 // For now it is what strlen would report.
7700 // A lot of code does not deal correctly with embedded nuls.
7703 return as;
7707 * mono_utf16_to_utf8:
7709 char *
7710 mono_utf16_to_utf8 (const gunichar2 *s, gsize slength, MonoError *error)
7712 gsize utf8_length = 0;
7713 return mono_utf16_to_utf8len (s, slength, &utf8_length, error);
7716 char *
7717 mono_string_to_utf8_checked_internal (MonoString *s, MonoError *error)
7719 MONO_REQ_GC_UNSAFE_MODE;
7721 error_init (error);
7723 if (s == NULL)
7724 return NULL;
7726 if (!s->length)
7727 return g_strdup ("");
7729 return mono_utf16_to_utf8 (mono_string_chars_internal (s), s->length, error);
7732 char *
7733 mono_string_to_utf8len (MonoStringHandle s, gsize *utf8len, MonoError *error)
7735 *utf8len = 0;
7736 if (MONO_HANDLE_IS_NULL (s))
7737 return NULL;
7739 char *utf8;
7741 MONO_ENTER_NO_SAFEPOINTS;
7743 utf8 = mono_utf16_to_utf8len (mono_string_chars_internal (MONO_HANDLE_RAW (s)), mono_string_handle_length (s), utf8len, error);
7745 MONO_EXIT_NO_SAFEPOINTS;
7747 return utf8;
7751 * mono_string_to_utf8_checked:
7752 * \param s a \c System.String
7753 * \param error a \c MonoError.
7754 * Converts a \c MonoString to its UTF-8 representation. May fail; check
7755 * \p error to determine whether the conversion was successful.
7756 * The resulting buffer should be freed with \c mono_free().
7758 char*
7759 mono_string_to_utf8_checked (MonoString *string_obj, MonoError *error)
7761 MONO_EXTERNAL_ONLY_GC_UNSAFE (char*, mono_string_to_utf8_checked_internal (string_obj, error));
7764 char *
7765 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7767 return mono_string_to_utf8_checked_internal (MONO_HANDLE_RAW (s), error);
7771 * mono_string_to_utf8_ignore:
7772 * \param s a MonoString
7773 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7774 * invalid surrogate pairs.
7775 * The resulting buffer should be freed with \c mono_free().
7777 char *
7778 mono_string_to_utf8_ignore (MonoString *s)
7780 MONO_REQ_GC_UNSAFE_MODE;
7782 long written = 0;
7783 char *as;
7785 if (s == NULL)
7786 return NULL;
7788 if (!s->length)
7789 return g_strdup ("");
7791 as = g_utf16_to_utf8 (mono_string_chars_internal (s), s->length, NULL, &written, NULL);
7793 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7794 if (s->length > written) {
7795 /* allocate the total length and copy the part of the string that has been converted */
7796 char *as2 = (char *)g_malloc0 (s->length);
7797 memcpy (as2, as, written);
7798 g_free (as);
7799 as = as2;
7802 return as;
7805 mono_unichar2*
7806 mono_string_to_utf16_internal_impl (MonoStringHandle s, MonoError *error)
7808 MONO_REQ_GC_UNSAFE_MODE;
7810 // FIXME This optimization ok to miss before wrapper? Or null is rare?
7811 if (MONO_HANDLE_RAW (s) == NULL)
7812 return NULL;
7814 int const length = mono_string_handle_length (s);
7815 mono_unichar2* const as = (mono_unichar2*)g_malloc ((length + 1) * sizeof (*as));
7816 if (as) {
7817 as [length] = 0;
7818 if (length)
7819 memcpy (as, mono_string_chars_internal (MONO_HANDLE_RAW (s)), length * sizeof (*as));
7821 return as;
7825 * mono_string_to_utf16:
7826 * \param s a \c MonoString
7827 * \returns a null-terminated array of the UTF-16 chars
7828 * contained in \p s. The result must be freed with \c g_free().
7829 * This is a temporary helper until our string implementation
7830 * is reworked to always include the null-terminating char.
7832 mono_unichar2*
7833 mono_string_to_utf16 (MonoString *string_obj)
7835 if (!string_obj)
7836 return NULL;
7837 MONO_EXTERNAL_ONLY (mono_unichar2*, mono_string_to_utf16_internal (string_obj));
7840 mono_unichar4*
7841 mono_string_to_utf32_internal_impl (MonoStringHandle s, MonoError *error)
7843 MONO_REQ_GC_UNSAFE_MODE;
7845 // FIXME This optimization ok to miss before wrapper? Or null is rare?
7846 if (MONO_HANDLE_RAW (s) == NULL)
7847 return NULL;
7849 return g_utf16_to_ucs4 (MONO_HANDLE_RAW (s)->chars, mono_string_handle_length (s), NULL, NULL, NULL);
7853 * mono_string_to_utf32:
7854 * \param s a \c MonoString
7855 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7856 * contained in \p s. The result must be freed with \c g_free().
7858 mono_unichar4*
7859 mono_string_to_utf32 (MonoString *string_obj)
7861 MONO_EXTERNAL_ONLY (mono_unichar4*, mono_string_to_utf32_internal (string_obj));
7865 * mono_string_from_utf16:
7866 * \param data the UTF-16 string (LPWSTR) to convert
7867 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7868 * \returns a \c MonoString.
7870 MonoString *
7871 mono_string_from_utf16 (gunichar2 *data)
7873 ERROR_DECL (error);
7874 MonoString *result = mono_string_from_utf16_checked (data, error);
7875 mono_error_cleanup (error);
7876 return result;
7880 * mono_string_from_utf16_checked:
7881 * \param data the UTF-16 string (LPWSTR) to convert
7882 * \param error set on error
7883 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7884 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7886 MonoString *
7887 mono_string_from_utf16_checked (const gunichar2 *data, MonoError *error)
7889 MONO_REQ_GC_UNSAFE_MODE;
7890 error_init (error);
7891 if (!data)
7892 return NULL;
7893 return mono_string_new_utf16_checked (mono_domain_get (), data, g_utf16_len (data), error);
7897 * mono_string_from_utf32:
7898 * \param data the UTF-32 string (LPWSTR) to convert
7899 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7900 * \returns a \c MonoString.
7902 MonoString *
7903 mono_string_from_utf32 (/*const*/ mono_unichar4 *data)
7905 ERROR_DECL (error);
7906 MonoString *result = mono_string_from_utf32_checked (data, error);
7907 mono_error_cleanup (error);
7908 return result;
7912 * mono_string_from_utf32_checked:
7913 * \param data the UTF-32 string (LPWSTR) to convert
7914 * \param error set on error
7915 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7916 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7918 MonoString *
7919 mono_string_from_utf32_checked (const mono_unichar4 *data, MonoError *error)
7921 MONO_REQ_GC_UNSAFE_MODE;
7923 error_init (error);
7924 MonoString* result = NULL;
7925 mono_unichar2 *utf16_output = NULL;
7926 GError *gerror = NULL;
7927 glong items_written;
7928 int len = 0;
7930 if (!data)
7931 return NULL;
7933 while (data [len]) len++;
7935 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7937 if (gerror)
7938 g_error_free (gerror);
7940 result = mono_string_from_utf16_checked (utf16_output, error);
7941 g_free (utf16_output);
7942 return result;
7945 static char *
7946 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
7948 MONO_REQ_GC_UNSAFE_MODE;
7950 char *r;
7951 char *mp_s;
7952 int len;
7954 r = mono_string_to_utf8_checked_internal (s, error);
7955 if (!is_ok (error))
7956 return NULL;
7958 if (!mp && !image)
7959 return r;
7961 len = strlen (r) + 1;
7962 if (mp)
7963 mp_s = (char *)mono_mempool_alloc (mp, len);
7964 else
7965 mp_s = (char *)mono_image_alloc (image, len);
7967 memcpy (mp_s, r, len);
7969 g_free (r);
7971 return mp_s;
7975 * mono_string_to_utf8_image:
7976 * \param s a \c System.String
7977 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7979 char *
7980 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7982 MONO_REQ_GC_UNSAFE_MODE;
7984 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), error); /* FIXME pin the string */
7988 * mono_string_to_utf8_mp:
7989 * \param s a \c System.String
7990 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7992 char *
7993 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7995 MONO_REQ_GC_UNSAFE_MODE;
7997 return mono_string_to_utf8_internal (mp, NULL, s, error);
8001 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
8003 void
8004 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
8006 eh_callbacks = *cbs;
8009 MonoRuntimeExceptionHandlingCallbacks *
8010 mono_get_eh_callbacks (void)
8012 return &eh_callbacks;
8015 void
8016 mono_raise_exception_internal (MonoException *ex)
8018 /* raise_exception doesn't return, so the transition to GC Unsafe is unbalanced */
8019 MONO_STACKDATA (stackdata);
8020 mono_threads_enter_gc_unsafe_region_unbalanced_with_info (mono_thread_info_current (), &stackdata);
8021 mono_raise_exception_deprecated (ex);
8025 * mono_raise_exception:
8026 * \param ex exception object
8027 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
8028 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8030 void
8031 mono_raise_exception (MonoException *ex)
8033 MONO_EXTERNAL_ONLY_VOID (mono_raise_exception_internal (ex));
8037 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8039 void
8040 mono_raise_exception_deprecated (MonoException *ex)
8042 MONO_REQ_GC_UNSAFE_MODE;
8044 eh_callbacks.mono_raise_exception (ex);
8048 * mono_reraise_exception:
8049 * \param ex exception object
8050 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
8051 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8053 void
8054 mono_reraise_exception (MonoException *ex)
8056 mono_reraise_exception_deprecated (ex);
8060 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8062 void
8063 mono_reraise_exception_deprecated (MonoException *ex)
8065 MONO_REQ_GC_UNSAFE_MODE;
8067 eh_callbacks.mono_reraise_exception (ex);
8071 * CTX must point to managed code.
8073 void
8074 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
8076 MONO_REQ_GC_UNSAFE_MODE;
8078 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
8082 * mono_wait_handle_new:
8083 * \param domain Domain where the object will be created
8084 * \param handle Handle for the wait handle
8085 * \param error set on error.
8086 * \returns A new \c MonoWaitHandle created in the given domain for the
8087 * given handle. On failure returns NULL and sets \p error.
8089 MonoWaitHandle *
8090 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
8092 MONO_REQ_GC_UNSAFE_MODE;
8094 MonoWaitHandle *res;
8095 gpointer params [1];
8096 static MonoMethod *handle_set;
8098 error_init (error);
8099 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
8100 return_val_if_nok (error, NULL);
8102 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
8103 if (!handle_set)
8104 handle_set = mono_class_get_property_from_name_internal (mono_defaults.manualresetevent_class, "Handle")->set;
8106 params [0] = &handle;
8108 mono_runtime_invoke_checked (handle_set, res, params, error);
8109 return res;
8112 HANDLE
8113 mono_wait_handle_get_handle (MonoWaitHandle *handle)
8115 MONO_REQ_GC_UNSAFE_MODE;
8117 static MonoClassField *f_safe_handle = NULL;
8118 MonoSafeHandle *sh;
8120 if (!f_safe_handle) {
8121 f_safe_handle = mono_class_get_field_from_name_full (mono_defaults.manualresetevent_class, "safeWaitHandle", NULL);
8122 g_assert (f_safe_handle);
8125 mono_field_get_value_internal ((MonoObject*)handle, f_safe_handle, &sh);
8126 return sh->handle;
8130 * Returns the MonoMethod to call to Capture the ExecutionContext.
8132 MonoMethod*
8133 mono_get_context_capture_method (void)
8135 static MonoMethod *method;
8137 /* older corlib revisions won't have the class (nor the method) */
8138 MonoClass *execution_context = mono_class_try_get_execution_context_class ();
8139 if (execution_context && !method) {
8140 ERROR_DECL (error);
8141 mono_class_init_internal (execution_context);
8142 method = mono_class_get_method_from_name_checked (execution_context, "Capture", 0, 0, error);
8143 mono_error_assert_ok (error);
8146 return method;
8149 static MonoObject*
8150 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
8152 #ifdef HOST_WASM
8153 return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
8154 #else
8155 MONO_REQ_GC_UNSAFE_MODE;
8157 RuntimeInvokeFunction runtime_invoke;
8159 error_init (error);
8161 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
8162 MonoMethod *method = mono_get_context_capture_method ();
8163 MonoMethod *wrapper;
8164 if (!method)
8165 return NULL;
8166 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
8167 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
8168 return_val_if_nok (error, NULL);
8169 domain->capture_context_method = mono_compile_method_checked (method, error);
8170 return_val_if_nok (error, NULL);
8173 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
8175 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
8176 #endif
8180 * mono_async_result_new:
8181 * \param domain domain where the object will be created.
8182 * \param handle wait handle.
8183 * \param state state to pass to AsyncResult
8184 * \param data C closure data.
8185 * \param error set on error.
8186 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
8187 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
8188 * On failure returns NULL and sets \p error.
8190 MonoAsyncResult *
8191 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
8193 MONO_REQ_GC_UNSAFE_MODE;
8195 error_init (error);
8196 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_class_get_asyncresult_class (), error);
8197 return_val_if_nok (error, NULL);
8198 MonoObject *context = mono_runtime_capture_context (domain, error);
8199 return_val_if_nok (error, NULL);
8200 /* we must capture the execution context from the original thread */
8201 if (context) {
8202 MONO_OBJECT_SETREF_INTERNAL (res, execution_context, context);
8203 /* note: result may be null if the flow is suppressed */
8206 res->data = (void **)data;
8207 MONO_OBJECT_SETREF_INTERNAL (res, object_data, object_data);
8208 MONO_OBJECT_SETREF_INTERNAL (res, async_state, state);
8209 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
8210 return_val_if_nok (error, NULL);
8211 if (handle != NULL)
8212 MONO_OBJECT_SETREF_INTERNAL (res, handle, (MonoObject *) wait_handle);
8214 res->sync_completed = FALSE;
8215 res->completed = FALSE;
8217 return res;
8220 MonoObject *
8221 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
8223 MONO_REQ_GC_UNSAFE_MODE;
8225 ERROR_DECL (error);
8226 MonoAsyncCall *ac;
8227 MonoObject *res;
8229 g_assert (ares);
8230 g_assert (ares->async_delegate);
8232 ac = (MonoAsyncCall*) ares->object_data;
8233 if (!ac) {
8234 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, error);
8235 if (mono_error_set_pending_exception (error))
8236 return NULL;
8237 } else {
8238 gpointer wait_event = NULL;
8240 ac->msg->exc = NULL;
8242 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, error);
8244 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
8245 mono_threads_begin_abort_protected_block ();
8247 if (!ac->msg->exc) {
8248 MonoException *ex = mono_error_convert_to_exception (error);
8249 ac->msg->exc = (MonoObject *)ex;
8250 } else {
8251 mono_error_cleanup (error);
8254 MONO_OBJECT_SETREF_INTERNAL (ac, res, res);
8256 mono_monitor_enter_internal ((MonoObject*) ares);
8257 ares->completed = 1;
8258 if (ares->handle)
8259 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
8260 mono_monitor_exit_internal ((MonoObject*) ares);
8262 if (wait_event != NULL)
8263 mono_w32event_set (wait_event);
8265 error_init (error); //the else branch would leave it in an undefined state
8266 if (ac->cb_method)
8267 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, error);
8269 mono_threads_end_abort_protected_block ();
8271 if (mono_error_set_pending_exception (error))
8272 return NULL;
8275 return res;
8278 gboolean
8279 mono_message_init (MonoDomain *domain,
8280 MonoMethodMessage *this_obj,
8281 MonoReflectionMethod *method,
8282 MonoArray *out_args,
8283 MonoError *error)
8285 MONO_REQ_GC_UNSAFE_MODE;
8287 static MonoMethod *init_message_method = NULL;
8289 if (!init_message_method) {
8290 init_message_method = mono_class_get_method_from_name_checked (mono_defaults.mono_method_message_class, "InitMessage", 2, 0, error);
8291 mono_error_assert_ok (error);
8292 g_assert (init_message_method != NULL);
8295 error_init (error);
8296 /* FIXME set domain instead? */
8297 g_assert (domain == mono_domain_get ());
8299 gpointer args[2];
8301 args[0] = method;
8302 args[1] = out_args;
8304 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
8305 return is_ok (error);
8308 #ifndef DISABLE_REMOTING
8310 * mono_remoting_invoke:
8311 * \param real_proxy pointer to a \c RealProxy object
8312 * \param msg The \c MonoMethodMessage to execute
8313 * \param exc used to store exceptions
8314 * \param out_args used to store output arguments
8315 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
8316 * \c IMessage interface and it is not trivial to extract results from there. So
8317 * we call an helper method \c PrivateInvoke instead of calling
8318 * \c RealProxy::Invoke() directly.
8319 * \returns the result object.
8321 MonoObject *
8322 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
8324 MONO_REQ_GC_UNSAFE_MODE;
8326 MonoObject *o;
8327 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
8328 gpointer pa [4];
8330 g_assert (exc);
8332 error_init (error);
8334 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
8336 if (!im) {
8337 im = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "PrivateInvoke", 4, 0, error);
8338 return_val_if_nok (error, NULL);
8339 if (!im) {
8340 mono_error_set_not_supported (error, "Linked away.");
8341 return NULL;
8343 real_proxy->vtable->domain->private_invoke_method = im;
8346 pa [0] = real_proxy;
8347 pa [1] = msg;
8348 pa [2] = exc;
8349 pa [3] = out_args;
8351 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
8352 return_val_if_nok (error, NULL);
8354 return o;
8356 #endif
8358 MonoObject *
8359 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
8360 MonoObject **exc, MonoArray **out_args, MonoError *error)
8362 MONO_REQ_GC_UNSAFE_MODE;
8364 static MonoClass *object_array_klass;
8365 error_init (error);
8367 MonoDomain *domain;
8368 MonoMethod *method;
8369 MonoMethodSignature *sig;
8370 MonoArray *arr;
8371 int i, j, outarg_count = 0;
8373 #ifndef DISABLE_REMOTING
8374 if (target && mono_object_is_transparent_proxy (target)) {
8375 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
8376 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8377 target = tp->rp->unwrapped_server;
8378 } else {
8379 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
8382 #endif
8384 domain = mono_domain_get ();
8385 method = msg->method->method;
8386 sig = mono_method_signature_internal (method);
8388 for (i = 0; i < sig->param_count; i++) {
8389 if (sig->params [i]->byref)
8390 outarg_count++;
8393 if (!object_array_klass) {
8394 MonoClass *klass;
8396 klass = mono_class_create_array (mono_defaults.object_class, 1);
8397 g_assert (klass);
8399 mono_memory_barrier ();
8400 object_array_klass = klass;
8403 MonoVTable *vt = mono_class_vtable_checked (domain, object_array_klass, error);
8404 return_val_if_nok (error, NULL);
8405 arr = mono_array_new_specific_checked (vt, outarg_count, error);
8406 return_val_if_nok (error, NULL);
8408 mono_gc_wbarrier_generic_store_internal (out_args, (MonoObject*) arr);
8409 *exc = NULL;
8411 MonoObject *ret = mono_runtime_try_invoke_array (method, m_class_is_valuetype (method->klass)? mono_object_unbox_internal (target): target, msg->args, exc, error);
8412 return_val_if_nok (error, NULL);
8414 for (i = 0, j = 0; i < sig->param_count; i++) {
8415 if (sig->params [i]->byref) {
8416 MonoObject* arg;
8417 arg = (MonoObject *)mono_array_get_internal (msg->args, gpointer, i);
8418 mono_array_setref_internal (*out_args, j, arg);
8419 j++;
8423 return ret;
8427 * prepare_to_string_method:
8428 * @obj: The object
8429 * @target: Set to @obj or unboxed value if a valuetype
8431 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
8433 static MonoMethod *
8434 prepare_to_string_method (MonoObject *obj, void **target)
8436 MONO_REQ_GC_UNSAFE_MODE;
8438 static MonoMethod *to_string = NULL;
8439 MonoMethod *method;
8440 g_assert (target);
8441 g_assert (obj);
8443 *target = obj;
8445 if (!to_string) {
8446 ERROR_DECL (error);
8447 to_string = mono_class_get_method_from_name_checked (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC, error);
8448 mono_error_assert_ok (error);
8451 method = mono_object_get_virtual_method_internal (obj, to_string);
8453 // Unbox value type if needed
8454 if (m_class_is_valuetype (mono_method_get_class (method))) {
8455 *target = mono_object_unbox_internal (obj);
8457 return method;
8461 * mono_object_to_string:
8462 * \param obj The object
8463 * \param exc Any exception thrown by \c ToString. May be NULL.
8464 * \returns the result of calling \c ToString on an object.
8466 MonoString *
8467 mono_object_to_string (MonoObject *obj, MonoObject **exc)
8469 ERROR_DECL (error);
8470 MonoString *s = NULL;
8471 void *target;
8472 MonoMethod *method = prepare_to_string_method (obj, &target);
8473 if (exc) {
8474 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, error);
8475 if (*exc == NULL && !is_ok (error))
8476 *exc = (MonoObject*) mono_error_convert_to_exception (error);
8477 else
8478 mono_error_cleanup (error);
8479 } else {
8480 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, error);
8481 mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */
8484 return s;
8488 * mono_object_try_to_string:
8489 * \param obj The object
8490 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
8491 * \param error Set if method cannot be invoked.
8492 * \returns the result of calling \c ToString() on an object. If the
8493 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
8494 * and returns NULL.
8496 MonoString *
8497 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
8499 g_assert (exc);
8500 error_init (error);
8501 void *target;
8502 MonoMethod *method = prepare_to_string_method (obj, &target);
8503 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
8508 static char *
8509 get_native_backtrace (MonoException *exc_raw)
8511 HANDLE_FUNCTION_ENTER ();
8512 MONO_HANDLE_DCL(MonoException, exc);
8513 char * const trace = mono_exception_handle_get_native_backtrace (exc);
8514 HANDLE_FUNCTION_RETURN_VAL (trace);
8518 * mono_print_unhandled_exception:
8519 * \param exc The exception
8520 * Prints the unhandled exception.
8522 void
8523 mono_print_unhandled_exception_internal (MonoObject *exc)
8525 MONO_REQ_GC_UNSAFE_MODE;
8527 MonoString * str;
8528 char *message = (char*)"";
8529 gboolean free_message = FALSE;
8530 ERROR_DECL (error);
8532 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
8533 message = g_strdup ("OutOfMemoryException");
8534 free_message = TRUE;
8535 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
8536 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
8537 free_message = TRUE;
8538 } else {
8540 if (((MonoException*)exc)->native_trace_ips) {
8541 message = get_native_backtrace ((MonoException*)exc);
8542 free_message = TRUE;
8543 } else {
8544 MonoObject *other_exc = NULL;
8545 str = mono_object_try_to_string (exc, &other_exc, error);
8546 if (other_exc == NULL && !is_ok (error))
8547 other_exc = (MonoObject*)mono_error_convert_to_exception (error);
8548 else
8549 mono_error_cleanup (error);
8550 if (other_exc) {
8551 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
8552 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
8554 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
8555 original_backtrace, nested_backtrace);
8557 g_free (original_backtrace);
8558 g_free (nested_backtrace);
8559 free_message = TRUE;
8560 } else if (str) {
8561 message = mono_string_to_utf8_checked_internal (str, error);
8562 if (!is_ok (error)) {
8563 mono_error_cleanup (error);
8564 message = (char *) "";
8565 } else {
8566 free_message = TRUE;
8573 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
8574 * exc->vtable->klass->name, message);
8576 g_printerr ("\nUnhandled Exception:\n%s\n", message);
8578 if (free_message)
8579 g_free (message);
8582 void
8583 mono_print_unhandled_exception (MonoObject *exc)
8585 MONO_EXTERNAL_ONLY_VOID (mono_print_unhandled_exception_internal (exc));
8589 * mono_delegate_ctor_with_method:
8590 * \param this pointer to an uninitialized delegate object
8591 * \param target target object
8592 * \param addr pointer to native code
8593 * \param method method
8594 * \param error set on error.
8595 * Initialize a delegate and sets a specific method, not the one
8596 * associated with \p addr. This is useful when sharing generic code.
8597 * In that case \p addr will most probably not be associated with the
8598 * correct instantiation of the method.
8599 * On failure returns FALSE and sets \p error.
8601 gboolean
8602 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
8604 MONO_REQ_GC_UNSAFE_MODE;
8606 error_init (error);
8607 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
8609 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
8611 MonoClass *klass = mono_handle_class (this_obj);
8612 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
8614 if (method)
8615 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
8617 UnlockedIncrement (&mono_stats.delegate_creations);
8619 if (addr)
8620 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
8622 #ifndef DISABLE_REMOTING
8623 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
8624 if (callbacks.interp_get_remoting_invoke) {
8625 MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, callbacks.interp_get_remoting_invoke (method, addr, error));
8626 } else {
8627 g_assert (method);
8628 method = mono_marshal_get_remoting_invoke (method, error);
8629 return_val_if_nok (error, FALSE);
8630 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
8632 return_val_if_nok (error, FALSE);
8634 #endif
8636 MONO_HANDLE_SET (delegate, target, target);
8637 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
8638 g_assert (callbacks.init_delegate);
8639 callbacks.init_delegate (delegate, error);
8640 return_val_if_nok (error, FALSE);
8641 return TRUE;
8645 * mono_delegate_ctor:
8646 * \param this pointer to an uninitialized delegate object
8647 * \param target target object
8648 * \param addr pointer to native code
8649 * \param error set on error.
8650 * This is used to initialize a delegate.
8651 * On failure returns FALSE and sets \p error.
8653 gboolean
8654 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
8656 MONO_REQ_GC_UNSAFE_MODE;
8658 error_init (error);
8659 MonoDomain *domain = mono_domain_get ();
8660 MonoJitInfo *ji;
8661 MonoMethod *method = NULL;
8663 g_assert (addr);
8665 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
8666 /* Shared code */
8667 if (!ji && domain != mono_get_root_domain ())
8668 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
8669 if (ji) {
8670 method = mono_jit_info_get_method (ji);
8671 g_assert (!mono_class_is_gtd (method->klass));
8674 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
8678 * mono_method_call_message_new:
8679 * \param method method to encapsulate
8680 * \param params parameters to the method
8681 * \param invoke optional, delegate invoke.
8682 * \param cb async callback delegate.
8683 * \param state state passed to the async callback.
8684 * \param error set on error.
8685 * Translates arguments pointers into a \c MonoMethodMessage.
8686 * On failure returns NULL and sets \p error.
8688 MonoMethodMessage *
8689 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
8690 MonoDelegate **cb, MonoObject **state, MonoError *error)
8692 MONO_REQ_GC_UNSAFE_MODE;
8694 error_init (error);
8696 MonoDomain *domain = mono_domain_get ();
8697 MonoMethodSignature *sig = mono_method_signature_internal (method);
8698 MonoMethodMessage *msg;
8699 int i, count;
8701 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8702 return_val_if_nok (error, NULL);
8704 if (invoke) {
8705 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8706 return_val_if_nok (error, NULL);
8707 mono_message_init (domain, msg, rm, NULL, error);
8708 return_val_if_nok (error, NULL);
8709 count = sig->param_count - 2;
8710 } else {
8711 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8712 return_val_if_nok (error, NULL);
8713 mono_message_init (domain, msg, rm, NULL, error);
8714 return_val_if_nok (error, NULL);
8715 count = sig->param_count;
8718 for (i = 0; i < count; i++) {
8719 gpointer vpos;
8720 MonoClass *klass;
8721 MonoObject *arg;
8723 if (sig->params [i]->byref)
8724 vpos = *((gpointer *)params [i]);
8725 else
8726 vpos = params [i];
8728 klass = mono_class_from_mono_type_internal (sig->params [i]);
8730 if (m_class_is_valuetype (klass)) {
8731 arg = mono_value_box_checked (domain, klass, vpos, error);
8732 return_val_if_nok (error, NULL);
8733 } else
8734 arg = *((MonoObject **)vpos);
8736 mono_array_setref_internal (msg->args, i, arg);
8739 if (cb != NULL && state != NULL) {
8740 *cb = *((MonoDelegate **)params [i]);
8741 i++;
8742 *state = *((MonoObject **)params [i]);
8745 return msg;
8749 * mono_method_return_message_restore:
8751 * Restore results from message based processing back to arguments pointers
8753 void
8754 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8756 MONO_REQ_GC_UNSAFE_MODE;
8758 error_init (error);
8760 MonoMethodSignature *sig = mono_method_signature_internal (method);
8761 int i, j, type, size, out_len;
8763 if (out_args == NULL)
8764 return;
8765 out_len = mono_array_length_internal (out_args);
8766 if (out_len == 0)
8767 return;
8769 for (i = 0, j = 0; i < sig->param_count; i++) {
8770 MonoType *pt = sig->params [i];
8772 if (pt->byref) {
8773 char *arg;
8774 if (j >= out_len) {
8775 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8776 return;
8779 arg = (char *)mono_array_get_internal (out_args, gpointer, j);
8780 type = pt->type;
8782 g_assert (type != MONO_TYPE_VOID);
8784 if (MONO_TYPE_IS_REFERENCE (pt)) {
8785 mono_gc_wbarrier_generic_store_internal (*((MonoObject ***)params [i]), (MonoObject *)arg);
8786 } else {
8787 if (arg) {
8788 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8789 size = mono_class_value_size (klass, NULL);
8790 if (m_class_has_references (klass))
8791 mono_gc_wbarrier_value_copy_internal (*((gpointer *)params [i]), mono_object_get_data ((MonoObject*)arg), 1, klass);
8792 else
8793 mono_gc_memmove_atomic (*((gpointer *)params [i]), mono_object_get_data ((MonoObject*)arg), size);
8794 } else {
8795 size = mono_class_value_size (mono_class_from_mono_type_internal (pt), NULL);
8796 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8800 j++;
8805 #ifndef DISABLE_REMOTING
8808 * mono_load_remote_field:
8809 * \param this pointer to an object
8810 * \param klass klass of the object containing \p field
8811 * \param field the field to load
8812 * \param res a storage to store the result
8813 * This method is called by the runtime on attempts to load fields of
8814 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8815 * the object containing \p field. \p res is a storage location which can be
8816 * used to store the result.
8817 * \returns an address pointing to the value of field.
8819 gpointer
8820 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8822 ERROR_DECL (error);
8823 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, error);
8824 mono_error_cleanup (error);
8825 return result;
8829 * mono_load_remote_field_checked:
8830 * \param this pointer to an object
8831 * \param klass klass of the object containing \p field
8832 * \param field the field to load
8833 * \param res a storage to store the result
8834 * \param error set on error
8835 * This method is called by the runtime on attempts to load fields of
8836 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8837 * the object containing \p field. \p res is a storage location which can be
8838 * used to store the result.
8839 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8841 gpointer
8842 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8844 MONO_REQ_GC_UNSAFE_MODE;
8846 static MonoMethod *getter = NULL;
8848 error_init (error);
8850 MonoDomain *domain = mono_domain_get ();
8851 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8852 MonoClass *field_class;
8853 MonoMethodMessage *msg;
8854 MonoArray *out_args;
8855 MonoObject *exc;
8856 char* full_name;
8858 g_assert (mono_object_is_transparent_proxy (this_obj));
8859 g_assert (res != NULL);
8861 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8862 mono_field_get_value_internal (tp->rp->unwrapped_server, field, res);
8863 return res;
8866 if (!getter) {
8867 getter = mono_class_get_method_from_name_checked (mono_defaults.object_class, "FieldGetter", -1, 0, error);
8868 return_val_if_nok (error, NULL);
8869 if (!getter) {
8870 mono_error_set_not_supported (error, "Linked away.");
8871 return NULL;
8875 field_class = mono_class_from_mono_type_internal (field->type);
8877 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8878 return_val_if_nok (error, NULL);
8879 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8880 return_val_if_nok (error, NULL);
8881 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8882 return_val_if_nok (error, NULL);
8883 mono_message_init (domain, msg, rm, out_args, error);
8884 return_val_if_nok (error, NULL);
8886 full_name = mono_type_get_full_name (klass);
8887 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8888 g_free (full_name);
8889 return_val_if_nok (error, NULL);
8890 mono_array_setref_internal (msg->args, 0, full_name_str);
8891 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8892 return_val_if_nok (error, NULL);
8893 mono_array_setref_internal (msg->args, 1, field_name);
8895 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8896 return_val_if_nok (error, NULL);
8898 if (exc) {
8899 mono_error_set_exception_instance (error, (MonoException *)exc);
8900 return NULL;
8903 if (mono_array_length_internal (out_args) == 0)
8904 return NULL;
8906 mono_gc_wbarrier_generic_store_internal (res, mono_array_get_internal (out_args, MonoObject *, 0));
8908 if (m_class_is_valuetype (field_class)) {
8909 return mono_object_get_data ((MonoObject*)*res);
8910 } else
8911 return res;
8915 * mono_load_remote_field_new:
8916 * \param this
8917 * \param klass
8918 * \param field
8919 * Missing documentation.
8921 MonoObject *
8922 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8924 ERROR_DECL (error);
8926 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, error);
8927 mono_error_cleanup (error);
8928 return result;
8932 * mono_load_remote_field_new_checked:
8933 * \param this pointer to an object
8934 * \param klass klass of the object containing \p field
8935 * \param field the field to load
8936 * \param error set on error.
8937 * This method is called by the runtime on attempts to load fields of
8938 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8939 * the object containing \p field.
8940 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8942 MonoObject *
8943 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8945 MONO_REQ_GC_UNSAFE_MODE;
8947 error_init (error);
8949 static MonoMethod *tp_load = NULL;
8951 g_assert (mono_object_is_transparent_proxy (this_obj));
8953 if (!tp_load) {
8954 tp_load = mono_class_get_method_from_name_checked (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1, 0, error);
8955 return_val_if_nok (error, NULL);
8956 if (!tp_load) {
8957 mono_error_set_not_supported (error, "Linked away.");
8958 return NULL;
8962 /* MonoType *type = m_class_get_byval_arg (klass); */
8964 gpointer args[2];
8965 args [0] = &klass;
8966 args [1] = &field;
8968 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8972 * mono_store_remote_field:
8973 * \param this_obj pointer to an object
8974 * \param klass klass of the object containing \p field
8975 * \param field the field to load
8976 * \param val the value/object to store
8977 * This method is called by the runtime on attempts to store fields of
8978 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8979 * the object containing \p field. \p val is the new value to store in \p field.
8981 void
8982 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8984 ERROR_DECL (error);
8985 (void) mono_store_remote_field_checked (this_obj, klass, field, val, error);
8986 mono_error_cleanup (error);
8990 * mono_store_remote_field_checked:
8991 * \param this_obj pointer to an object
8992 * \param klass klass of the object containing \p field
8993 * \param field the field to load
8994 * \param val the value/object to store
8995 * \param error set on error
8996 * This method is called by the runtime on attempts to store fields of
8997 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8998 * the object containing \p field. \p val is the new value to store in \p field.
8999 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
9001 gboolean
9002 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
9005 MONO_REQ_GC_UNSAFE_MODE;
9007 error_init (error);
9009 MonoDomain *domain = mono_domain_get ();
9010 MonoClass *field_class;
9011 MonoObject *arg;
9013 g_assert (mono_object_is_transparent_proxy (this_obj));
9015 field_class = mono_class_from_mono_type_internal (field->type);
9017 if (m_class_is_valuetype (field_class)) {
9018 arg = mono_value_box_checked (domain, field_class, val, error);
9019 return_val_if_nok (error, FALSE);
9020 } else {
9021 arg = *((MonoObject**)val);
9024 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
9028 * mono_store_remote_field_new:
9029 * \param this_obj
9030 * \param klass
9031 * \param field
9032 * \param arg
9033 * Missing documentation
9035 void
9036 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
9038 ERROR_DECL (error);
9039 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
9040 mono_error_cleanup (error);
9044 * mono_store_remote_field_new_checked:
9045 * \param this_obj
9046 * \param klass
9047 * \param field
9048 * \param arg
9049 * \param error
9050 * Missing documentation
9052 gboolean
9053 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
9055 MONO_REQ_GC_UNSAFE_MODE;
9057 static MonoMethod *tp_store = NULL;
9059 error_init (error);
9061 g_assert (mono_object_is_transparent_proxy (this_obj));
9063 if (!tp_store) {
9064 tp_store = mono_class_get_method_from_name_checked (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1, 0, error);
9065 return_val_if_nok (error, FALSE);
9066 if (!tp_store) {
9067 mono_error_set_not_supported (error, "Linked away.");
9068 return FALSE;
9072 gpointer args[3];
9073 args [0] = &klass;
9074 args [1] = &field;
9075 args [2] = arg;
9077 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
9078 return is_ok (error);
9080 #endif
9083 * mono_create_ftnptr:
9085 * Given a function address, create a function descriptor for it.
9086 * This is only needed on some platforms.
9088 gpointer
9089 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
9091 return callbacks.create_ftnptr (domain, addr);
9095 * mono_get_addr_from_ftnptr:
9097 * Given a pointer to a function descriptor, return the function address.
9098 * This is only needed on some platforms.
9100 gpointer
9101 mono_get_addr_from_ftnptr (gpointer descr)
9103 return callbacks.get_addr_from_ftnptr (descr);
9106 gunichar2 *
9107 mono_string_chars_internal (MonoString *s)
9109 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
9111 return s->chars;
9115 * mono_string_chars:
9116 * \param s a \c MonoString
9117 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
9119 mono_unichar2*
9120 mono_string_chars (MonoString *s)
9122 MONO_EXTERNAL_ONLY (mono_unichar2*, mono_string_chars_internal (s));
9126 mono_string_length_internal (MonoString *s)
9128 MONO_REQ_GC_UNSAFE_MODE;
9130 return s->length;
9134 * mono_string_length:
9135 * \param s MonoString
9136 * \returns the length in characters of the string
9139 mono_string_length (MonoString *s)
9141 MONO_EXTERNAL_ONLY (int, mono_string_length_internal (s));
9145 * mono_array_length:
9146 * \param array a \c MonoArray*
9147 * \returns the total number of elements in the array. This works for
9148 * both vectors and multidimensional arrays.
9150 uintptr_t
9151 mono_array_length (MonoArray *array)
9153 MONO_EXTERNAL_ONLY (uintptr_t, mono_array_length_internal (array));
9156 #ifdef ENABLE_CHECKED_BUILD_GC
9159 * mono_string_handle_length:
9160 * \param s \c MonoString
9161 * \returns the length in characters of the string
9164 mono_string_handle_length (MonoStringHandle s)
9166 MONO_REQ_GC_UNSAFE_MODE;
9168 return MONO_HANDLE_GETVAL (s, length);
9171 #endif
9174 * mono_array_addr_with_size:
9175 * \param array a \c MonoArray*
9176 * \param size size of the array elements
9177 * \param idx index into the array
9178 * Use this function to obtain the address for the \p idx item on the
9179 * \p array containing elements of size \p size.
9181 * This method performs no bounds checking or type checking.
9182 * \returns the address of the \p idx element in the array.
9184 char*
9185 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
9187 MONO_EXTERNAL_ONLY (char*, mono_array_addr_with_size_internal (array, size, idx));
9190 MonoArray *
9191 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
9193 MonoDomain *domain = mono_domain_get ();
9194 MonoArray *res;
9195 int len, i;
9197 error_init (error);
9198 if (!list)
9199 return NULL;
9201 len = g_list_length (list);
9202 res = mono_array_new_checked (domain, eclass, len, error);
9203 return_val_if_nok (error, NULL);
9205 for (i = 0; list; list = list->next, i++)
9206 mono_array_set_internal (res, gpointer, i, list->data);
9208 return res;
9212 * mono_class_value_size:
9213 * \param klass a class
9215 * This function is used for value types, and return the
9216 * space and the alignment to store that kind of value object.
9218 * \returns the size of a value of kind \p klass
9220 gint32
9221 mono_class_value_size (MonoClass *klass, guint32 *align)
9223 gint32 size;
9225 /* fixme: check disable, because we still have external revereces to
9226 * mscorlib and Dummy Objects
9228 /*g_assert (klass->valuetype);*/
9230 size = mono_class_instance_size (klass) - MONO_ABI_SIZEOF (MonoObject);
9232 if (align)
9233 *align = m_class_get_min_align (klass);
9235 return size;
9239 * mono_object_get_data:
9241 * Return a pointer to the beginning of data inside a MonoObject.
9243 gpointer
9244 mono_object_get_data (MonoObject *o)
9246 return (guint8*)o + MONO_ABI_SIZEOF (MonoObject);
9250 * mono_vtype_get_field_addr:
9252 * Return the address of the FIELD in the valuetype VTYPE.
9254 gpointer
9255 mono_vtype_get_field_addr (gpointer vtype, MonoClassField *field)
9257 return ((char*)vtype) + field->offset - MONO_ABI_SIZEOF (MonoObject);
9261 #if NEVER_DEFINED
9263 * The following section is purely to declare prototypes and
9264 * document the API, as these C files are processed by our
9265 * tool
9269 * mono_array_set:
9270 * \param array array to alter
9271 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
9272 * \param index index into the array
9273 * \param value value to set
9274 * Value Type version: This sets the \p index's element of the \p array
9275 * with elements of size sizeof(type) to the provided \p value.
9277 * This macro does not attempt to perform type checking or bounds checking.
9279 * Use this to set value types in a \c MonoArray.
9281 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
9286 * mono_array_setref:
9287 * \param array array to alter
9288 * \param index index into the array
9289 * \param value value to set
9290 * Reference Type version. This sets the \p index's element of the
9291 * \p array with elements of size sizeof(type) to the provided \p value.
9293 * This macro does not attempt to perform type checking or bounds checking.
9295 * Use this to reference types in a \c MonoArray.
9297 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
9302 * mono_array_get:
9303 * \param array array on which to operate on
9304 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
9305 * \param index index into the array
9307 * Use this macro to retrieve the \p index element of an \p array and
9308 * extract the value assuming that the elements of the array match
9309 * the provided type value.
9311 * This method can be used with both arrays holding value types and
9312 * reference types. For reference types, the \p type parameter should
9313 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
9315 * This macro does not attempt to perform type checking or bounds checking.
9317 * \returns The element at the \p index position in the \p array.
9319 Type mono_array_get_internal (MonoArray *array, Type element_type, uintptr_t index)
9322 #endif