3 * Object creation for the Mono runtime
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.
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"
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"
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
);
79 free_main_args (void);
82 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, MonoError
*error
);
85 mono_string_to_utf8_mp (MonoMemPool
*mp
, MonoString
*s
, MonoError
*error
);
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.
111 mono_runtime_object_init (MonoObject
*this_obj
)
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.
127 mono_runtime_object_init_handle (MonoObjectHandle this_obj
, MonoError
*error
)
129 MONO_REQ_GC_UNSAFE_MODE
;
131 HANDLE_FUNCTION_ENTER ();
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
)) {
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
);
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.
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
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
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,
193 MonoNativeThreadId initializing_tid
;
194 guint32 waiting_count
;
197 /* condvar used to wait for 'done' becoming TRUE */
199 } TypeInitializationLock
;
201 /* for locking access to type_initialization_hash and blocked_thread_hash */
202 static MonoCoopMutex type_initialization_section
;
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
);
212 mono_type_initialization_unlock (void)
214 mono_coop_mutex_unlock (&type_initialization_section
);
218 mono_type_init_lock (TypeInitializationLock
*lock
)
220 MONO_REQ_GC_NEUTRAL_MODE
;
222 mono_coop_mutex_lock (&lock
->mutex
);
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
;
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.
252 mono_thread_set_main (MonoThread
*thread
)
254 MONO_REQ_GC_UNSAFE_MODE
;
256 static gboolean registered
= FALSE
;
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");
264 main_thread
= thread
;
268 * mono_thread_get_main:
271 mono_thread_get_main (void)
273 MONO_REQ_GC_UNSAFE_MODE
;
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
);
289 mono_type_initialization_cleanup (void)
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
;
299 mono_coop_mutex_destroy (&ldstr_section
);
300 g_hash_table_destroy (blocked_thread_hash
);
301 blocked_thread_hash
= NULL
;
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
;
325 MonoDomain
*domain
= vtable
->domain
;
326 MonoClass
*klass
= vtable
->klass
;
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
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
);
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
);
349 full_name
= g_strdup (klass_name
);
350 ex
= mono_get_exception_type_initialization_checked (full_name
, NULL
, error
);
352 return_val_if_nok (error
, NULL
);
359 * mono_runtime_class_init:
360 * \param vtable vtable that needs to be initialized
361 * This routine calls the class constructor for \p vtable.
364 mono_runtime_class_init (MonoVTable
*vtable
)
366 MONO_REQ_GC_UNSAFE_MODE
;
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.
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
);
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
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
);
413 module_vtable
= mono_class_vtable_checked (domain
, module_klass
, error
);
416 if (!mono_runtime_class_init_full (module_vtable
, error
))
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.
430 mono_runtime_class_init_full (MonoVTable
*vtable
, MonoError
*error
)
432 MONO_REQ_GC_UNSAFE_MODE
;
434 MonoMethod
*method
= NULL
;
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
;
446 if (vtable
->initialized
)
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
)) {
455 method
= mono_class_get_cctor (klass
);
457 vtable
->initialized
= 1;
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
470 mono_type_initialization_lock ();
471 /* double check... */
472 if (vtable
->initialized
) {
473 mono_type_initialization_unlock ();
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
);
486 lock
= (TypeInitializationLock
*)g_hash_table_lookup (type_initialization_hash
, vtable
);
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 ());
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;
505 g_hash_table_insert (type_initialization_hash
, vtable
, lock
);
506 do_initialization
= 1;
509 TypeInitializationLock
*pending_lock
;
511 if (mono_native_thread_id_equals (lock
->initializing_tid
, tid
)) {
512 mono_type_initialization_unlock ();
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 ();
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
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 */
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
);
553 mono_error_cleanup (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 */
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
);
570 full_name
= g_strdup (klass_name
);
572 MonoException
*exc_to_throw
= mono_get_exception_type_initialization_checked (full_name
, exc
, error
);
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
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
);
589 mono_domain_set_fast (last_domain
, TRUE
);
591 /* Signal to the other threads that we are done */
592 mono_type_init_lock (lock
);
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
) {
604 mono_thread_resume_interruption (FALSE
);
607 /* this just blocks until the initializing thread is done */
608 mono_type_init_lock (lock
);
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
);
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
));
636 mono_vtable_domain_internal (MonoVTable
*vtable
)
638 return vtable
->domain
;
642 mono_vtable_domain (MonoVTable
*vtable
)
644 MONO_EXTERNAL_ONLY (MonoDomain
*, mono_vtable_domain_internal (vtable
));
648 mono_vtable_class_internal (MonoVTable
*vtable
)
650 return vtable
->klass
;
654 mono_vtable_class (MonoVTable
*vtable
)
656 MONO_EXTERNAL_ONLY (MonoClass
*, mono_vtable_class_internal (vtable
));
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
) {
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
);
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
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
);
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"
715 mono_install_callbacks (MonoRuntimeCallbacks
*cbs
)
717 memcpy (&callbacks
, cbs
, sizeof (*cbs
));
720 MonoRuntimeCallbacks
*
721 mono_get_runtime_callbacks (void)
727 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func
)
729 imt_trampoline_builder
= func
;
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
745 mono_compile_method (MonoMethod
*method
)
748 gpointer result
= mono_compile_method_checked (method
, error
);
749 mono_error_cleanup (error
);
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.
761 mono_compile_method_checked (MonoMethod
*method
, MonoError
*error
)
765 MONO_REQ_GC_NEUTRAL_MODE
769 g_assert (callbacks
.compile_method
);
770 res
= callbacks
.compile_method (method
, error
);
775 mono_runtime_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
, MonoError
*error
)
779 MONO_REQ_GC_NEUTRAL_MODE
;
782 res
= callbacks
.create_jump_trampoline (domain
, method
, add_sync_wrapper
, error
);
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)
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))
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
;
836 int max_size
, wordsize
;
838 wordsize
= TARGET_SIZEOF_VOID_P
;
841 max_size
= mono_class_data_size (klass
) / wordsize
;
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
));
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
))) {
853 memset (bitmap
, 0, size
/ 8);
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
))) {
863 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
865 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
868 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
871 /* FIXME: should not happen, flag as type load error */
872 if (field
->type
->byref
)
875 if (static_fields
&& field
->offset
== -1)
879 pos
= field
->offset
/ TARGET_SIZEOF_VOID_P
;
882 type
= mono_type_get_underlying_type (field
->type
);
883 switch (type
->type
) {
887 case MONO_TYPE_FNPTR
:
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
);
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
);
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
);
928 case MONO_TYPE_BOOLEAN
:
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
);
943 * mono_class_compute_bitmap:
945 * Mono internal function to compute a bitmap of reference fields in a class.
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
);
957 * similar to the above, but sets the bits in the bitmap for any non-ref field
958 * and ignores static fields
961 compute_class_non_ref_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
)
963 MonoClassField
*field
;
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
))) {
979 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
981 /* FIXME: should not happen, flag as type load error */
982 if (field
->type
->byref
)
985 pos
= field
->offset
/ wordsize
;
988 type
= mono_type_get_underlying_type (field
->type
);
989 switch (type
->type
) {
990 #if SIZEOF_VOID_P == 8
994 case MONO_TYPE_FNPTR
:
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
);
1004 #if SIZEOF_VOID_P == 4
1008 case MONO_TYPE_FNPTR
:
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
);
1018 case MONO_TYPE_CHAR
:
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
);
1026 case MONO_TYPE_BOOLEAN
:
1029 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
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
:
1037 case MONO_TYPE_GENERICINST
:
1038 if (!mono_type_generic_inst_is_valuetype (type
)) {
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
);
1050 g_assert_not_reached ();
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.
1066 mono_class_insecure_overlapping (MonoClass
*klass
)
1070 gsize default_bitmap
[4] = {0};
1072 gsize default_nrbitmap
[4] = {0};
1073 int i
, insecure
= 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
]) {
1086 if (bitmap
!= default_bitmap
)
1088 if (nrbitmap
!= default_nrbitmap
)
1091 g_print ("class %s.%s in assembly %s has overlapping references\n", klass
->name_space
, klass
->name
, klass
->image
->name
);
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:
1115 mono_class_compute_gc_descriptor (MonoClass
*klass
)
1117 MONO_REQ_GC_NEUTRAL_MODE
;
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
))
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
))) {
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);*/
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);*/
1149 /*static int count = 0;
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
)
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.
1215 field_is_special_static (MonoClass
*fklass
, MonoClassField
*field
)
1217 MONO_REQ_GC_NEUTRAL_MODE
;
1220 MonoCustomAttrInfo
*ainfo
;
1222 ainfo
= mono_custom_attrs_from_field_checked (fklass
, field
, error
);
1223 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
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.
1272 mono_method_get_imt_slot (MonoMethod
*method
)
1274 MONO_REQ_GC_NEUTRAL_MODE
;
1276 MonoMethodSignature
*sig
;
1278 guint32
*hashes_start
, *hashes
;
1282 /* This can be used to stress tests the collision code */
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) {
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];
1332 case 0: /* nothing left to add */
1336 g_free (hashes_start
);
1337 /* Report the result */
1338 return c
% MONO_IMT_SIZE
;
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 */
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
);
1369 entry
->children
= 0;
1370 UnlockedIncrement (&mono_stats
.imt_used_slots
);
1372 imt_builder
[imt_slot
] = entry
;
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
);
1385 print_imt_entry (const char* message
, MonoImtBuilderEntry
*e
, int num
) {
1387 MonoMethod
*method
= e
->key
;
1388 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1392 method
->klass
->name_space
,
1393 method
->klass
->name
,
1396 printf (" * %s: NULL\n", message
);
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);
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
;
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
;
1425 item
->check_target_idx
= out_array
->len
+ 1;
1427 item
->check_target_idx
= 0;
1428 g_ptr_array_add (out_array
, item
);
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
);
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
;
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
);
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
];
1478 /* Collision, build the trampoline */
1479 GPtrArray
*imt_ir
= imt_sort_slot_entries (imt_builder_entry
);
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
);
1498 static MonoImtBuilderEntry
*
1499 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
);
1502 * LOCKING: requires the loader and domain locks.
1506 build_imt_slots (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
, int slot_num
)
1508 MONO_REQ_GC_NEUTRAL_MODE
;
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
;
1519 printf ("Building IMT for class %s.%s slot %d\n", m_class_get_name_space (klass
), m_class_get_name (klass
), slot_num
);
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
++) {
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
) {
1551 method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1552 if (method
->is_generic
) {
1553 has_generic_virtual
= TRUE
;
1558 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) {
1559 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, vt_slot
, slot_num
);
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
]);
1589 if (imt_builder
[i
]) {
1590 MonoImtBuilderEntry
*entry
;
1592 /* Link entries with imt_builder [i] */
1593 for (entry
= entries
; entry
->next
; entry
= entry
->next
) {
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
);
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
));
1619 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], NULL
);
1622 printf ("initialize_imt_slot[%d]: %p methods %d\n", i
, imt
[i
], imt_builder
[i
]->children
+ 1);
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
;
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
;
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.
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.
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;
1713 mono_counters_register ("Generic virtual trampoline bytes",
1714 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &generic_virtual_trampolines_size
);
1717 generic_virtual_trampolines_size
+= size
;
1719 return mono_domain_code_reserve (domain
, size
);
1722 typedef struct _GenericVirtualCase
{
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
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
);
1751 for (; list
; list
= list
->next
) {
1752 MonoImtBuilderEntry
*entry
;
1754 if (list
->count
< THUNK_THRESHOLD
)
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;
1762 entry
->children
= entries
->children
+ 1;
1763 entry
->next
= entries
;
1767 mono_domain_unlock (domain
);
1769 /* FIXME: Leaking memory ? */
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.
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
;
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
);
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
);
1810 /* Check whether the case was already added */
1811 list
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1814 if (gvc
->method
== method
)
1819 /* If not found, make a new one */
1821 gvc
= (GenericVirtualCase
*)mono_domain_alloc (domain
, sizeof (GenericVirtualCase
));
1822 gvc
->method
= method
;
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
);
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
;
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
,
1855 MonoImtBuilderEntry
*next
= 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
)
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.
1883 mono_class_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1886 MONO_ENTER_GC_UNSAFE
;
1888 vtable
= mono_class_vtable_checked (domain
, klass
, error
);
1889 mono_error_cleanup (error
);
1890 MONO_EXIT_GC_UNSAFE
;
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.
1903 mono_class_vtable_checked (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
1905 MONO_REQ_GC_UNSAFE_MODE
;
1907 MonoClassRuntimeInfo
*runtime_info
;
1913 if (mono_class_has_failure (klass
)) {
1914 mono_error_set_for_class_failure (error
, klass
);
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.
1933 mono_class_try_get_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1935 MONO_REQ_GC_NEUTRAL_MODE
;
1937 MonoClassRuntimeInfo
*runtime_info
;
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
];
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);
1967 return (gpointer
*) ((char*)mono_domain_alloc0 (domain
, vtable_size
) + alloc_offset
);
1971 mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
1973 MONO_REQ_GC_UNSAFE_MODE
;
1975 HANDLE_FUNCTION_ENTER ();
1978 MonoClassRuntimeInfo
*runtime_info
;
1979 MonoClassField
*field
;
1981 int i
, vtable_slots
;
1982 size_t imt_table_bytes
;
1984 guint32 vtable_size
, class_size
;
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
];
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
);
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
);
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
);
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
);
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
);
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));
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
);
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
;
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
;
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
;
2115 gsize default_bitmap
[4] = {0};
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
)
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
);
2133 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
2134 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2136 if (mono_field_is_deleted (field
))
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
;
2143 gsize default_bitmap
[4] = {0};
2148 if (mono_type_is_reference (field
->type
)) {
2149 default_bitmap
[0] = 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;
2157 default_bitmap
[0] = 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
)
2169 * This marks the field as special static to speed up the
2170 * checks in mono_field_static_get/set_value ().
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) */
2185 if (m_class_is_valuetype (fklass
)) {
2186 memcpy (t
, data
, mono_class_value_size (fklass
, NULL
));
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
));
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
);
2209 mono_class_setup_vtable (klass
);
2211 for (i
= 0; i
< m_class_get_vtable_size (klass
); ++i
) {
2214 cm
= m_class_get_vtable (klass
) [i
];
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
));
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
));
2247 if (mono_handle_class (vt_type
) != mono_defaults
.runtimetype_class
)
2248 /* This is unregistered in
2249 unregister_vtable_reflection_type() in
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
));
2281 if (mono_handle_class (vt_type
) != mono_defaults
.runtimetype_class
)
2282 /* This is unregistered in
2283 unregister_vtable_reflection_type() in
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
));
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).
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
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
;
2343 GSList
*extra_interfaces
= NULL
;
2344 MonoClass
*klass
= remote_class
->proxy_class
;
2345 gpointer
*interface_offsets
;
2346 uint8_t *bitmap
= NULL
;
2348 size_t imt_table_bytes
;
2349 gboolean use_interpreter
= callbacks
.is_interpreter_enabled ();
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2357 vt
= mono_class_vtable_checked (domain
, klass
, error
);
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
];
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
))
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
);
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
))
2388 extra_interfaces
= g_slist_prepend (extra_interfaces
, ic
);
2389 method_count
+= mono_class_num_methods (ic
);
2391 g_ptr_array_free (ifaces
, TRUE
);
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
) {
2444 if ((cm
= klass_vtable
[i
])) {
2445 pvt
->vtable
[i
] = create_remoting_trampoline (domain
, cm
, target_type
, error
);
2446 goto_if_nok (error
, failure
);
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
)) {
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
);
2469 bitmap
= (uint8_t *)mono_domain_alloc0 (domain
, bsize
);
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
);
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));
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
);
2514 pvt
->interface_bitmap
= bitmap
;
2516 MONO_PROFILER_RAISE (vtable_loaded
, (pvt
));
2519 if (extra_interfaces
)
2520 g_slist_free (extra_interfaces
);
2521 #ifdef COMPRESSED_INTERFACE_BITMAP
2524 MONO_PROFILER_RAISE (vtable_failed
, (pvt
));
2528 #endif /* DISABLE_REMOTING */
2531 * mono_class_field_is_special_static:
2532 * \returns whether \p field is a thread/context static field.
2535 mono_class_field_is_special_static (MonoClassField
*field
)
2537 MONO_REQ_GC_NEUTRAL_MODE
2539 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2541 if (mono_field_is_deleted (field
))
2543 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
2544 if (field_is_special_static (field
->parent
, field
) != SPECIAL_STATIC_NONE
)
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.
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.
2575 mono_class_has_special_static_fields (MonoClass
*klass
)
2577 MONO_REQ_GC_NEUTRAL_MODE
2579 MonoClassField
*field
;
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
))
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.
2599 create_remote_class_key (MonoRemoteClass
*remote_class
, MonoClass
*extra_class
)
2601 MONO_REQ_GC_NEUTRAL_MODE
;
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
;
2613 key
= (void **)g_malloc (sizeof(gpointer
) * 2);
2614 key
[0] = GINT_TO_POINTER (1);
2615 key
[1] = extra_class
;
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
;
2629 key
[j
] = remote_class
->interfaces
[i
];
2632 key
[j
] = extra_class
;
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
];
2647 * copy_remote_class_key:
2649 * Make a copy of KEY in the domain and return the copy.
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
);
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
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
;
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
);
2690 mono_domain_unlock (domain
);
2694 name
= mono_string_to_utf8_mp (domain
->mp
, MONO_HANDLE_RAW (class_name
), error
);
2695 if (!is_ok (error
)) {
2697 mono_domain_unlock (domain
);
2701 mp_key
= copy_remote_class_key (domain
, 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
;
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);
2729 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2731 mono_domain_unlock (domain
);
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
);
2754 mp_key
= copy_remote_class_key (domain
, key
);
2758 if (mono_class_is_interface (extra_class
)) {
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
];
2772 rc
->interfaces
[j
] = extra_class
;
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
);
2792 mono_remote_class_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRealProxyHandle rp
, MonoError
*error
)
2794 MONO_REQ_GC_UNSAFE_MODE
;
2796 gpointer result
= NULL
;
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
;
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
);
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
;
2824 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_COMINTEROP
, error
);
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
;
2835 mono_domain_unlock (domain
);
2836 mono_loader_unlock ();
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.
2851 mono_upgrade_remote_class (MonoDomain
*domain
, MonoObjectHandle proxy_object
, MonoClass
*klass
, MonoError
*error
)
2853 MONO_REQ_GC_UNSAFE_MODE
;
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
)) {
2864 for (i
= 0; i
< remote_class
->interface_count
&& redo_vtable
; i
++)
2865 if (remote_class
->interfaces
[i
] == klass
)
2866 redo_vtable
= FALSE
;
2869 redo_vtable
= (remote_class
->proxy_class
!= klass
);
2872 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2873 mono_domain_lock (domain
);
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
);
2884 mono_domain_unlock (domain
);
2885 mono_loader_unlock ();
2886 return is_ok (error
);
2888 #endif /* DISABLE_REMOTING */
2891 mono_object_get_virtual_method_internal (MonoObject
*obj_raw
, MonoMethod
*method
)
2893 HANDLE_FUNCTION_ENTER ();
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.
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.
2923 mono_object_handle_get_virtual_method (MonoObjectHandle obj
, MonoMethod
*method
, MonoError
*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
;
2934 return mono_class_get_virtual_method (klass
, method
, is_proxy
, error
);
2938 mono_class_get_virtual_method (MonoClass
*klass
, MonoMethod
*method
, gboolean is_proxy
, MonoError
*error
)
2940 MONO_REQ_GC_NEUTRAL_MODE
;
2943 if (!is_proxy
&& ((method
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)))
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
;
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
)) {
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
];
2971 res
= vtable
[method
->slot
];
2975 #ifndef DISABLE_REMOTING
2977 /* It may be an interface, abstract class method or generic method */
2978 if (!res
|| mono_method_signature_internal (res
)->generic_param_count
)
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
);
2986 if (klass
== mono_class_get_com_object_class () || mono_class_is_com_object (klass
))
2987 res
= mono_cominterop_get_invoke (res
);
2990 res
= mono_marshal_get_remoting_invoke (res
, error
);
2995 if (method
->is_inflated
) {
2996 /* Have to inflate the result */
2997 res
= mono_class_inflate_generic_method_checked (res
, &((MonoMethodInflated
*)method
)->context
, error
);
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
);
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
));
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,
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
3060 mono_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
3063 MONO_ENTER_GC_UNSAFE
;
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
);
3070 mono_error_cleanup (error
);
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
;
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,
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
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
);
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,
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
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
);
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
));
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:
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);
3236 * // handle exception
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>
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.
3258 mono_method_get_unmanaged_thunk (MonoMethod
*method
)
3260 MONO_REQ_GC_NEUTRAL_MODE
;
3261 MONO_REQ_API_ENTRYPOINT
;
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
;
3276 mono_copy_value (MonoType
*type
, void *dest
, void *value
, int deref_pointer
)
3278 MONO_REQ_GC_UNSAFE_MODE
;
3282 /* object fields cannot be byref, so we don't need a
3284 gpointer
*p
= (gpointer
*)dest
;
3291 case MONO_TYPE_BOOLEAN
:
3293 case MONO_TYPE_U1
: {
3294 guint8
*p
= (guint8
*)dest
;
3295 *p
= value
? *(guint8
*)value
: 0;
3300 case MONO_TYPE_CHAR
: {
3301 guint16
*p
= (guint16
*)dest
;
3302 *p
= value
? *(guint16
*)value
: 0;
3305 #if SIZEOF_VOID_P == 4
3310 case MONO_TYPE_U4
: {
3311 gint32
*p
= (gint32
*)dest
;
3312 *p
= value
? *(gint32
*)value
: 0;
3315 #if SIZEOF_VOID_P == 8
3320 case MONO_TYPE_U8
: {
3321 gint64
*p
= (gint64
*)dest
;
3322 *p
= value
? *(gint64
*)value
: 0;
3325 case MONO_TYPE_R4
: {
3326 float *p
= (float*)dest
;
3327 *p
= value
? *(float*)value
: 0;
3330 case MONO_TYPE_R8
: {
3331 double *p
= (double*)dest
;
3332 *p
= value
? *(double*)value
: 0;
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
);
3342 case MONO_TYPE_FNPTR
:
3343 case MONO_TYPE_PTR
: {
3344 gpointer
*p
= (gpointer
*)dest
;
3345 *p
= deref_pointer
? *(gpointer
*)value
: value
;
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
;
3354 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
3355 int size
= mono_class_value_size (klass
, NULL
);
3357 mono_gc_bzero_atomic (dest
, size
);
3359 mono_gc_wbarrier_value_copy_internal (dest
, value
, 1, klass
);
3362 case MONO_TYPE_GENERICINST
:
3363 t
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
)->type
;
3366 g_error ("got type %x", type
->type
);
3371 mono_field_set_value_internal (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3375 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3378 dest
= (char*)obj
+ field
->offset
;
3380 mono_copy_value (field
->type
, dest
, value
, value
&& field
->type
->type
== MONO_TYPE_PTR
);
3382 mono_copy_value (field
->type
, dest
, value
, FALSE
);
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.
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
));
3405 mono_field_static_set_value_internal (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3409 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) == 0)
3411 /* you cant set a constant! */
3412 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
3415 if (field
->offset
== -1) {
3416 /* Special static */
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
));
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.
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.
3451 mono_vtable_get_static_field_data (MonoVTable
*vt
)
3453 MONO_REQ_GC_NEUTRAL_MODE
3455 if (!vt
->has_static_fields
)
3457 return vt
->vtable
[m_class_get_vtable_size (vt
->klass
)];
3461 mono_field_get_addr (MonoObject
*obj
, MonoVTable
*vt
, MonoClassField
*field
)
3463 MONO_REQ_GC_UNSAFE_MODE
;
3467 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3468 if (field
->offset
== -1) {
3469 /* Special static */
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
));
3477 src
= (guint8
*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3480 src
= (guint8
*)obj
+ field
->offset
;
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
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
3503 * mono_field_get_value (obj, int_field, &i);
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
));
3513 mono_field_get_value_internal (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3515 MONO_REQ_GC_UNSAFE_MODE
;
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.
3536 mono_field_get_value_object (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
)
3539 MONO_ENTER_GC_UNSAFE
;
3541 result
= mono_field_get_value_object_checked (domain
, field
, obj
, error
);
3542 mono_error_assert_ok (error
);
3543 MONO_EXIT_GC_UNSAFE
;
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.
3556 mono_static_field_get_value_handle (MonoDomain
*domain
, MonoClassField
*field
, MonoError
*error
)
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.
3573 mono_field_get_value_object_checked (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
, MonoError
*error
)
3575 MONO_REQ_GC_UNSAFE_MODE
;
3579 MonoObject
*o
= NULL
;
3581 MonoVTable
*vtable
= NULL
;
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
:
3601 case MONO_TYPE_BOOLEAN
:
3604 case MONO_TYPE_CHAR
:
3613 case MONO_TYPE_VALUETYPE
:
3614 is_ref
= type
->byref
;
3616 case MONO_TYPE_GENERICINST
:
3617 is_ref
= !mono_type_generic_inst_is_valuetype (type
);
3623 g_error ("type 0x%x not handled in "
3624 "mono_field_get_value_object", type
->type
);
3628 if (type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
3631 if (type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
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
);
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
);
3655 mono_field_get_value_internal (obj
, field
, &o
);
3661 static MonoMethod
*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
);
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
);
3680 mono_field_get_value_internal (obj
, field
, v
);
3686 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3687 args
[0] = ptr
? *ptr
: NULL
;
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
);
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
);
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
);
3715 mono_field_get_value_internal (obj
, field
, v
);
3722 * Important detail, if type is MONO_TYPE_STRING we return a blob encoded string (ie, utf16 + leb128 prefixed size)
3725 mono_metadata_read_constant_value (const char *blob
, MonoTypeEnum type
, void *value
, MonoError
*error
)
3729 gboolean retval
= TRUE
;
3730 const char *p
= blob
;
3731 mono_metadata_decode_blob_size (p
, &p
);
3734 case MONO_TYPE_BOOLEAN
:
3737 *(guint8
*) value
= *p
;
3739 case MONO_TYPE_CHAR
:
3742 *(guint16
*) value
= read16 (p
);
3746 *(guint32
*) value
= read32 (p
);
3750 *(guint64
*) value
= read64 (p
);
3753 readr4 (p
, (float*) value
);
3756 readr8 (p
, (double*) value
);
3758 case MONO_TYPE_STRING
:
3759 *(const char**) value
= blob
;
3761 case MONO_TYPE_CLASS
:
3762 *(gpointer
*) value
= NULL
;
3766 mono_error_set_execution_engine (error
, "Type 0x%02x should not be in constant table", type
);
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 ();
3780 if (!mono_metadata_read_constant_value (blob
, type
, value
, error
))
3783 if (type
== MONO_TYPE_STRING
) {
3785 *(gpointer
*)value
= MONO_HANDLE_RAW (mono_ldstr_metadata_sig (domain
, *(const char**)value
, error
));
3790 HANDLE_FUNCTION_RETURN_VAL (result
);
3794 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
, MonoError
*error
)
3796 MONO_REQ_GC_NEUTRAL_MODE
;
3798 MonoTypeEnum def_type
;
3803 data
= mono_class_get_field_default_value (field
, &def_type
);
3804 mono_get_constant_value_from_blob (domain
, def_type
, data
, value
, error
);
3808 mono_field_static_get_value_for_thread (MonoInternalThread
*thread
, MonoVTable
*vt
, MonoClassField
*field
, void *value
, MonoError
*error
)
3810 MONO_REQ_GC_UNSAFE_MODE
;
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
);
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
));
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
3849 * mono_field_static_get_value (vt, int_field, &i);
3853 mono_field_static_get_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3855 MONO_REQ_GC_NEUTRAL_MODE
;
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
3876 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3877 * if (!is_ok (error)) { ... }
3879 * On failure sets \p error.
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.
3904 mono_property_set_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3906 MONO_ENTER_GC_UNSAFE
;
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
);
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.
3930 mono_property_set_value_handle (MonoProperty
*prop
, MonoObjectHandle obj
, void **params
, MonoError
*error
)
3932 MONO_REQ_GC_UNSAFE_MODE
;
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.
3960 mono_property_get_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3963 MONO_ENTER_GC_UNSAFE
;
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
);
3970 mono_error_cleanup (error
); /* FIXME don't raise here */
3972 MONO_EXIT_GC_UNSAFE
;
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.
3992 mono_property_get_value_checked (MonoProperty
*prop
, void *obj
, void **params
, MonoError
*error
)
3994 MONO_REQ_GC_UNSAFE_MODE
;
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
);
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];
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
);
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.
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;
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
);
4069 mono_gc_memmove_atomic (value_field_addr
, mono_object_unbox_internal (value
), mono_class_value_size (param_class
, NULL
));
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.
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
);
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.
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;
4134 if (m_class_has_references (param_class
))
4135 mono_gc_wbarrier_value_copy_internal (value_field_addr
, value
, 1, param_class
);
4137 mono_gc_memmove_atomic (value_field_addr
, value
, mono_class_value_size (param_class
, NULL
));
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.
4153 mono_nullable_box (gpointer vbuf
, MonoClass
*klass
, MonoError
*error
)
4155 guint8
*buf
= (guint8
*)vbuf
;
4156 MONO_REQ_GC_UNSAFE_MODE
;
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
);
4171 mono_gc_memmove_atomic (mono_object_unbox_internal (o
), value_field_addr
, mono_class_value_size (param_class
, NULL
));
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
));
4186 mono_get_delegate_invoke_internal (MonoClass
*klass
)
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
);
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
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
4216 mono_get_delegate_invoke_checked (MonoClass
*klass
, MonoError
*error
)
4218 MONO_REQ_GC_NEUTRAL_MODE
;
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
))
4226 im
= mono_class_get_method_from_name_checked (klass
, "Invoke", -1, 0, error
);
4231 mono_get_delegate_begin_invoke_internal (MonoClass
*klass
)
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
);
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
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
4261 mono_get_delegate_begin_invoke_checked (MonoClass
*klass
, MonoError
*error
)
4263 MONO_REQ_GC_NEUTRAL_MODE
;
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
))
4271 im
= mono_class_get_method_from_name_checked (klass
, "BeginInvoke", -1, 0, error
);
4276 mono_get_delegate_end_invoke_internal (MonoClass
*klass
)
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
);
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
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
4306 mono_get_delegate_end_invoke_checked (MonoClass
*klass
, MonoError
*error
)
4308 MONO_REQ_GC_NEUTRAL_MODE
;
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
))
4316 im
= mono_class_get_method_from_name_checked (klass
, "EndInvoke", -1, 0, error
);
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.
4334 mono_runtime_delegate_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
)
4336 MONO_REQ_GC_UNSAFE_MODE
;
4340 MonoObject
*result
= mono_runtime_delegate_try_invoke (delegate
, params
, exc
, error
);
4342 mono_error_cleanup (error
);
4346 *exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
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 */
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.
4371 mono_runtime_delegate_try_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
, MonoError
*error
)
4373 MONO_REQ_GC_UNSAFE_MODE
;
4377 MonoClass
*klass
= delegate
->vtable
->klass
;
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
));
4384 o
= mono_runtime_try_invoke (im
, delegate
, params
, exc
, error
);
4386 o
= mono_runtime_invoke_checked (im
, delegate
, params
, error
);
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.
4414 mono_runtime_delegate_invoke_checked (MonoObject
*delegate
, void **params
, MonoError
*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
4428 mono_runtime_get_main_args (void)
4430 HANDLE_FUNCTION_ENTER ();
4431 MONO_REQ_GC_UNSAFE_MODE
;
4433 MonoArrayHandle result
= MONO_HANDLE_NEW (MonoArray
, NULL
);
4435 MonoArrayHandle arg_array
= mono_runtime_get_main_args_handle (error
);
4436 goto_if_nok (error
, leave
);
4437 MONO_HANDLE_ASSIGN (result
, arg_array
);
4439 /* FIXME: better external API that doesn't swallow the error */
4440 mono_error_cleanup (error
);
4441 HANDLE_FUNCTION_RETURN_OBJ (result
);
4445 handle_main_arg_array_set (MonoDomain
*domain
, int idx
, MonoArrayHandle dest
, MonoError
*error
)
4447 HANDLE_FUNCTION_ENTER ();
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
);
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.
4463 mono_runtime_get_main_args_handle (MonoError
*error
)
4465 HANDLE_FUNCTION_ENTER ();
4466 MonoArrayHandle array
;
4468 MonoDomain
*domain
= mono_domain_get ();
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
);
4476 for (i
= 0; i
< num_main_args
; ++i
) {
4477 if (!handle_main_arg_array_set (domain
, i
, array
, error
))
4481 HANDLE_FUNCTION_RETURN_REF (MonoArray
, array
);
4485 free_main_args (void)
4487 MONO_REQ_GC_NEUTRAL_MODE
;
4491 for (i
= 0; i
< num_main_args
; ++i
)
4492 g_free (main_args
[i
]);
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
;
4513 main_args
= g_new0 (char*, argc
);
4514 num_main_args
= argc
;
4516 for (i
= 0; i
< argc
; ++i
) {
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");
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.
4539 prepare_run_main (MonoMethod
*method
, int argc
, char *argv
[])
4541 MONO_REQ_GC_UNSAFE_MODE
;
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
,
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
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");
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");
4586 main_args
[0] = utf8_fullpath
;
4588 for (i
= 1; i
< argc
; ++i
) {
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");
4599 main_args
[i
] = utf8_arg
;
4604 sig
= mono_method_signature_internal (method
);
4606 g_print ("Unable to load Main method.\n");
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
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
);
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
);
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
[],
4648 MONO_REQ_GC_UNSAFE_MODE
;
4651 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4654 res
= mono_runtime_try_exec_main (method
, args
, exc
);
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 */
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
[],
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
[],
4699 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4700 return mono_runtime_try_exec_main (method
, args
, exc
);
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
)
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 ());
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
);
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.
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
);
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
);
4810 deserialized
= deserialize_object (serialized
, error
);
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
);
4835 MonoBoolean is_terminating
;
4836 is_terminating
= TRUE
;
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
);
4850 return MONO_HANDLE_NEW (MonoObject
, NULL
);
4853 /* Used in mono_unhandled_exception_internal */
4855 call_unhandled_exception_delegate (MonoDomain
*domain
, MonoObjectHandle delegate
, MonoObjectHandle exc
)
4857 MONO_REQ_GC_UNSAFE_MODE
;
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
);
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
);
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.
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
;
4927 mono_unhandled_exception_internal (MonoObject
*exc_raw
)
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
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
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
);
4990 field
= mono_class_get_field_from_name_full (mono_defaults
.appdomain_class
, "UnhandledException", NULL
);
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 */
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
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().
5039 mono_runtime_exec_managed_code (MonoDomain
*domain
,
5040 MonoMainThreadFunc mfunc
,
5043 // This function is external_only.
5046 mono_thread_create_checked (domain
, mfunc
, margs
, error
);
5047 mono_error_assert_ok (error
);
5049 mono_thread_manage ();
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
) {
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
);
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? */
5088 has_stathread_attribute
= mono_custom_attrs_has_attr (cinfo
, mono_class_get_sta_thread_attribute_class ());
5090 mono_custom_attrs_free (cinfo
);
5092 has_stathread_attribute
= FALSE
;
5094 if (has_stathread_attribute
) {
5095 thread
->apartment_state
= ThreadApartmentState_STA
;
5097 thread
->apartment_state
= ThreadApartmentState_MTA
;
5099 mono_thread_init_apartment_state ();
5104 do_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*error
)
5106 MONO_REQ_GC_UNSAFE_MODE
;
5116 /* FIXME: check signature of method */
5117 if (mono_method_signature_internal (method
)->ret
->type
== MONO_TYPE_I4
) {
5119 res
= mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5121 rval
= *(guint32
*)(mono_object_get_data (res
));
5124 mono_environment_exitcode_set (rval
);
5126 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5138 do_try_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
5140 MONO_REQ_GC_UNSAFE_MODE
;
5150 /* FIXME: check signature of method */
5151 if (mono_method_signature_internal (method
)->ret
->type
== MONO_TYPE_I4
) {
5152 ERROR_DECL (inner_error
);
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
);
5158 mono_error_cleanup (inner_error
);
5161 rval
= *(guint32
*)(mono_object_get_data (res
));
5165 mono_environment_exitcode_set (rval
);
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
);
5172 mono_error_cleanup (inner_error
);
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)
5183 mono_environment_exitcode_set (rval
);
5191 * Execute a standard Main() method (args doesn't contain the
5195 mono_runtime_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
5198 MONO_ENTER_GC_UNSAFE
;
5200 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
5202 rval
= do_try_exec_main (method
, args
, exc
);
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
;
5212 * Execute a standard Main() method (args doesn't contain the
5215 * On failure sets @error
5218 mono_runtime_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*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
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.
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
;
5260 case MONO_TYPE_BOOLEAN
:
5263 case MONO_TYPE_CHAR
:
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
);
5277 *has_byref_nullables
= TRUE
;
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
);
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
);
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
:
5313 result
= mono_array_addr_internal (params
, MonoObject
*, i
);
5314 // FIXME: I need to check this code path
5316 result
= mono_array_get_internal (params
, MonoObject
*, i
);
5318 case MONO_TYPE_GENERICINST
:
5320 t
= m_class_get_this_arg (t
->data
.generic_class
->container_class
);
5322 t
= m_class_get_byval_arg (t
->data
.generic_class
->container_class
);
5324 case MONO_TYPE_PTR
: {
5327 /* The argument should be an IntPtr */
5328 arg
= mono_array_get_internal (params
, MonoObject
*, i
);
5332 g_assert (arg
->vtable
->klass
== mono_defaults
.int_class
);
5333 result
= ((MonoIntPtr
*)arg
)->m_value
;
5338 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig
->type
);
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,
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
5379 mono_runtime_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
5384 MonoObject
*result
= mono_runtime_try_invoke_array (method
, obj
, params
, exc
, error
);
5386 mono_error_cleanup (error
);
5390 *exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
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 */
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,
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
5435 mono_runtime_invoke_array_checked (MonoMethod
*method
, void *obj
, MonoArray
*params
,
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,
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
5481 mono_runtime_try_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
5482 MonoObject
**exc
, MonoError
*error
)
5484 MONO_REQ_GC_UNSAFE_MODE
;
5488 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
5489 gpointer
*pa
= NULL
;
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
) {
5506 if (mono_class_is_nullable (method
->klass
)) {
5507 /* Need to create a boxed vtype instead */
5513 return mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method
->klass
), pa
[0], error
);
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
);
5527 if (m_class_is_valuetype (method
->klass
))
5528 o
= (MonoObject
*)mono_object_unbox_internal ((MonoObject
*)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
);
5537 mono_runtime_try_invoke (method
, o
, pa
, exc
, error
);
5539 mono_runtime_invoke_checked (method
, o
, pa
, error
);
5542 return (MonoObject
*)obj
;
5544 if (mono_class_is_nullable (method
->klass
)) {
5545 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
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 */
5562 res
= mono_runtime_try_invoke (method
, obj
, pa
, exc
, error
);
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
;
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 ();
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
);
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
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
]);
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.
5632 object_new_common_tail (MonoObject
*o
, MonoClass
*klass
, MonoError
*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
));
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
);
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
)
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
));
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
);
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.
5686 mono_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5688 MonoObject
* result
;
5689 MONO_ENTER_GC_UNSAFE
;
5691 result
= mono_object_new_checked (domain
, klass
, error
);
5692 mono_error_cleanup (error
);
5693 MONO_EXIT_GC_UNSAFE
;
5698 ves_icall_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5700 MONO_REQ_GC_UNSAFE_MODE
;
5704 MonoObject
* result
= mono_object_new_checked (domain
, klass
, error
);
5706 mono_error_set_pending_exception (error
);
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.
5722 mono_object_new_checked (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5724 MONO_REQ_GC_UNSAFE_MODE
;
5728 vtable
= mono_class_vtable_checked (domain
, klass
, error
);
5732 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
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.
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.
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
);
5783 mono_object_new_pinned (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5785 MONO_REQ_GC_UNSAFE_MODE
;
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
5804 mono_object_new_specific (MonoVTable
*vtable
)
5807 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
5808 mono_error_cleanup (error
);
5814 mono_object_new_specific_checked (MonoVTable
*vtable
, MonoError
*error
)
5816 MONO_REQ_GC_UNSAFE_MODE
;
5822 /* check for is_com_object for COM Interop */
5823 if (mono_vtable_is_remote (vtable
) || mono_class_is_com_object (vtable
->klass
))
5826 MonoMethod
*im
= vtable
->domain
->create_proxy_for_type_method
;
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
);
5837 mono_error_set_not_supported (error
, "Linked away.");
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
);
5847 o
= mono_runtime_invoke_checked (im
, NULL
, pa
, error
);
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
);
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
;
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 ());
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
;
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
));
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
))
5902 return mono_object_new_alloc_by_vtable (vtable
, error
);
5906 ves_icall_object_new_specific (MonoVTable
*vtable
)
5909 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
5910 mono_error_set_pending_exception (error
);
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
5926 * \returns the allocated object.
5929 mono_object_new_alloc_specific (MonoVTable
*vtable
)
5932 MonoObject
*o
= mono_object_new_alloc_specific_checked (vtable
, error
);
5933 mono_error_cleanup (error
);
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
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
);
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
5989 * \returns the allocated object.
5992 mono_object_new_fast (MonoVTable
*vtable
)
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
);
6009 mono_object_new_mature (MonoVTable
*vtable
, MonoError
*error
)
6011 MONO_REQ_GC_UNSAFE_MODE
;
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 */
6023 MonoObject
*o
= mono_gc_alloc_mature (vtable
, size
);
6025 return object_new_common_tail (o
, vtable
->klass
, error
);
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
6049 mono_object_new_from_token (MonoDomain
*domain
, MonoImage
*image
, guint32 token
)
6051 MONO_REQ_GC_UNSAFE_MODE
;
6053 HANDLE_FUNCTION_ENTER ();
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
6074 mono_object_clone (MonoObject
*obj
)
6077 MonoObject
*o
= mono_object_clone_checked (obj
, error
);
6078 mono_error_cleanup (error
);
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
));
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.
6123 mono_array_full_copy (MonoArray
*src
, MonoArray
*dest
)
6125 MONO_REQ_GC_UNSAFE_MODE
;
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
);
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
));
6148 mono_gc_memmove_atomic (&dest
->vector
, &src
->vector
, size
);
6150 mono_array_memcpy_refs_internal
6151 (dest
, 0, src
, 0, mono_array_length_internal (src
));
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.
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
);
6173 MonoClass
*klass
= mono_handle_class (array_handle
);
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
);
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
);
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
);
6209 mono_gchandle_free_internal (src_handle
);
6215 * \param array the array to clone
6216 * \returns A newly created array who is a shallow copy of \p array
6219 mono_array_clone (MonoArray
*array
)
6221 MONO_REQ_GC_UNSAFE_MODE
;
6224 MonoArray
*result
= mono_array_clone_checked (array
, error
);
6225 mono_error_cleanup (error
);
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.
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 */
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)))))
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)))))
6268 mono_array_calc_byte_len (MonoClass
*klass
, uintptr_t len
, uintptr_t *res
)
6270 MONO_REQ_GC_NEUTRAL_MODE
;
6274 byte_len
= mono_array_element_size (klass
);
6275 if (CHECK_MUL_OVERFLOW_UN (byte_len
, len
))
6278 if (CHECK_ADD_OVERFLOW_UN (byte_len
, MONO_SIZEOF_MONO_ARRAY
))
6280 byte_len
+= MONO_SIZEOF_MONO_ARRAY
;
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.
6297 mono_array_new_full (MonoDomain
*domain
, MonoClass
*array_class
, uintptr_t *lengths
, intptr_t *lower_bounds
)
6300 MonoArray
*array
= mono_array_new_full_checked (domain
, array_class
, lengths
, lower_bounds
, error
);
6301 mono_error_cleanup (error
);
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
;
6314 MonoArrayBounds
*bounds
;
6320 if (!m_class_is_inited (array_class
))
6321 mono_class_init_internal (array_class
);
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))) {
6329 if (len
> MONO_ARRAY_MAX_INDEX
) {
6330 mono_error_set_generic_error (error
, "System", "OverflowException", "");
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", "");
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
);
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
);
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
);
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
);
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
);
6376 o
= (MonoObject
*)mono_gc_alloc_array (vtable
, byte_len
, len
, bounds_size
);
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
);
6385 array
= (MonoArray
*)o
;
6387 bounds
= array
->bounds
;
6390 for (i
= 0; i
< array_class_rank
; ++i
) {
6391 bounds
[i
].length
= lengths
[i
];
6393 bounds
[i
].lower_bound
= lower_bounds
[i
];
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.
6408 mono_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
6411 MONO_ENTER_GC_UNSAFE
;
6414 result
= mono_array_new_checked (domain
, eclass
, n
, error
);
6415 mono_error_cleanup (error
);
6416 MONO_EXIT_GC_UNSAFE
;
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.
6430 mono_array_new_checked (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
, MonoError
*error
)
6436 ac
= mono_class_create_array (eclass
, 1);
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
);
6446 ves_icall_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
6449 MonoArray
*arr
= mono_array_new_checked (domain
, eclass
, n
, error
);
6450 mono_error_set_pending_exception (error
);
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.
6463 mono_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
6466 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, error
);
6467 mono_error_cleanup (error
);
6473 mono_array_new_specific_checked (MonoVTable
*vtable
, uintptr_t n
, MonoError
*error
)
6475 MONO_REQ_GC_UNSAFE_MODE
;
6482 if (G_UNLIKELY (n
> MONO_ARRAY_MAX_INDEX
)) {
6483 mono_error_set_generic_error (error
, "System", "OverflowException", "");
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
);
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
);
6498 return (MonoArray
*)o
;
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
));
6510 ves_icall_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
6513 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, error
);
6514 mono_error_set_pending_exception (error
);
6520 * mono_string_empty_wrapper:
6522 * Returns: The same empty string instance as the managed string.Empty
6525 mono_string_empty_wrapper (void)
6527 MonoDomain
*domain
= mono_domain_get ();
6528 return mono_string_empty_internal (domain
);
6532 mono_string_empty_internal (MonoDomain
*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
6545 mono_string_empty (MonoDomain
*domain
)
6547 MONO_EXTERNAL_ONLY (MonoString
*, mono_string_empty_internal (domain
));
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.
6563 mono_string_new_utf16 (MonoDomain
*domain
, const mono_unichar2
*text
, gint32 len
)
6565 MONO_REQ_GC_UNSAFE_MODE
;
6568 MonoString
*res
= NULL
;
6569 res
= mono_string_new_utf16_checked (domain
, text
, len
, error
);
6570 mono_error_cleanup (error
);
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.
6584 mono_string_new_utf16_checked (MonoDomain
*domain
, const gunichar2
*text
, gint32 len
, MonoError
*error
)
6586 MONO_REQ_GC_UNSAFE_MODE
;
6592 s
= mono_string_new_size_checked (domain
, len
, error
);
6594 memcpy (mono_string_chars_internal (s
), text
, len
* 2);
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.
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.
6621 mono_string_new_utf32_checked (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
, MonoError
*error
)
6623 MONO_REQ_GC_UNSAFE_MODE
;
6626 mono_unichar2
*utf16_output
= NULL
;
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);
6639 g_free (utf16_output
);
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.
6651 mono_string_new_utf32 (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
)
6654 MonoString
*result
= mono_string_new_utf32_checked (domain
, text
, len
, error
);
6655 mono_error_cleanup (error
);
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
6666 mono_string_new_size (MonoDomain
*domain
, gint32 len
)
6669 MonoString
*str
= mono_string_new_size_checked (domain
, len
, error
);
6670 mono_error_cleanup (error
);
6676 mono_string_new_size_handle (MonoDomain
*domain
, gint32 len
, MonoError
*error
)
6678 MONO_REQ_GC_UNSAFE_MODE
;
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
);
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.
6720 mono_string_new_len (MonoDomain
*domain
, const char *text
, guint length
)
6722 HANDLE_FUNCTION_ENTER ();
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.
6743 mono_string_new_utf8_len (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6745 MONO_REQ_GC_UNSAFE_MODE
;
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
);
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
);
6764 o
= mono_string_new_utf16_handle (domain
, ut
, items_written
, error
);
6773 mono_string_new_len_checked (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6775 HANDLE_FUNCTION_ENTER ();
6777 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_utf8_len (domain
, text
, length
, error
));
6782 mono_string_new_internal (MonoDomain
*domain
, const char *text
)
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
6791 if (mono_error_get_error_code (error
) == MONO_ERROR_OUT_OF_MEMORY
)
6792 mono_error_assert_ok (error
);
6794 mono_error_cleanup (error
);
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.
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.
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
;
6827 glong items_written
;
6832 len
= strlen (text
);
6834 ut
= g_utf8_to_utf16 (text
, len
, NULL
, &items_written
, &eg_error
);
6837 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6839 mono_error_set_execution_engine (error
, "String conversion error: %s", eg_error
->message
);
6840 g_error_free (eg_error
);
6845 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6850 MonoString
*o
= NULL
;
6852 if (!g_utf8_validate (text
, -1, &end
)) {
6853 mono_error_set_argument (error
, "text", "Not a valid utf8 string");
6857 len
= g_utf8_strlen (text
, -1);
6858 o
= mono_string_new_size_checked (domain
, len
, error
);
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
);
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.
6882 mono_string_new_wtf8_len_checked (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6884 MONO_REQ_GC_UNSAFE_MODE
;
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
);
6896 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6898 g_error_free (eg_error
);
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.
6917 mono_string_new_wrapper (const char *text
)
6919 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoString
*, mono_string_new_wrapper_internal (text
));
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.
6929 mono_value_box (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
)
6932 MONO_ENTER_GC_UNSAFE
;
6934 result
= mono_value_box_checked (domain
, klass
, value
, error
);
6935 mono_error_cleanup (error
);
6936 MONO_EXIT_GC_UNSAFE
;
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.
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
;
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
);
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
;
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
);
6992 *(guint8
*)data
= *(guint8
*) value
;
6995 *(guint16
*)(data
) = *(guint16
*) value
;
6998 *(guint32
*)(data
) = *(guint32
*) value
;
7001 *(guint64
*)(data
) = *(guint64
*) value
;
7004 mono_gc_memmove_atomic (data
, value
, size
);
7007 MONO_EXIT_NO_SAFEPOINTS
;
7009 if (m_class_has_finalize (klass
))
7010 mono_object_register_finalizer_handle (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.
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
));
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
);
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.
7048 mono_value_copy (gpointer dest
, gpointer src
, MonoClass
*klass
)
7050 mono_value_copy_internal (dest
, src
, klass
);
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
)));
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.
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
));
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
);
7095 mono_object_get_vtable (MonoObject
*obj
)
7097 MONO_EXTERNAL_ONLY (MonoVTable
*, mono_object_get_vtable_internal (obj
));
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
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.
7126 mono_object_get_class (MonoObject
*obj
)
7128 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoClass
*, mono_object_class (obj
));
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
) {
7145 size
+= sizeof (MonoArrayBounds
) * o
->vtable
->rank
;
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
7159 mono_object_get_size (MonoObject
*o
)
7161 MONO_EXTERNAL_ONLY (unsigned, mono_object_get_size_internal (o
));
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
7178 * This method will assert if the object passed is not a valuetype.
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.
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
);
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.
7216 mono_object_isinst_checked (MonoObject
*obj_raw
, MonoClass
*klass
, MonoError
*error
)
7218 MONO_REQ_GC_UNSAFE_MODE
;
7220 HANDLE_FUNCTION_ENTER ();
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.
7236 mono_object_handle_isinst (MonoObjectHandle obj
, MonoClass
*klass
, MonoError
*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
);
7255 * mono_object_isinst_mbyref:
7258 mono_object_isinst_mbyref (MonoObject
*obj_raw
, MonoClass
*klass
)
7260 MONO_REQ_GC_UNSAFE_MODE
;
7262 HANDLE_FUNCTION_ENTER ();
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
);
7271 mono_object_handle_isinst_mbyref (MonoObjectHandle obj
, MonoClass
*klass
, MonoError
*error
)
7273 gboolean success
= FALSE
;
7276 MonoObjectHandle result
= MONO_HANDLE_NEW (MonoObject
, NULL
);
7278 if (MONO_HANDLE_IS_NULL (obj
))
7281 success
= mono_object_handle_isinst_mbyref_raw (obj
, klass
, error
);
7282 if (success
&& is_ok (error
))
7283 MONO_HANDLE_ASSIGN (result
, obj
);
7290 mono_object_handle_isinst_mbyref_raw (MonoObjectHandle obj
, MonoClass
*klass
, MonoError
*error
)
7294 gboolean result
= FALSE
;
7296 if (MONO_HANDLE_IS_NULL (obj
))
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
))) {
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
)) {
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
))) {
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
)) {
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
)
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
;
7347 im
= mono_class_get_method_from_name_checked (rpklass
, "CanCastTo", -1, 0, error
);
7348 goto_if_nok (error
, leave
);
7350 mono_error_set_not_supported (error
, "Linked away.");
7353 im
= mono_object_handle_get_virtual_method (rp
, im
, error
);
7354 goto_if_nok (error
, leave
);
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
);
7373 #endif /* DISABLE_REMOTING */
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.
7385 mono_object_castclass_mbyref (MonoObject
*obj_raw
, MonoClass
*klass
)
7387 MONO_REQ_GC_UNSAFE_MODE
;
7388 HANDLE_FUNCTION_ENTER ();
7390 MONO_HANDLE_DCL (MonoObject
, obj
);
7391 MonoObjectHandle result
= MONO_HANDLE_NEW (MonoObject
, NULL
);
7392 if (MONO_HANDLE_IS_NULL (obj
))
7394 MONO_HANDLE_ASSIGN (result
, mono_object_handle_isinst_mbyref (obj
, klass
, error
));
7395 mono_error_cleanup (error
);
7397 HANDLE_FUNCTION_RETURN_OBJ (result
);
7400 static MonoStringHandle
7401 mono_string_get_pinned (MonoStringHandle str
, MonoError
*error
)
7403 MONO_REQ_GC_UNSAFE_MODE
;
7407 /* We only need to make a pinned version of a string if this is a moving GC */
7408 if (!mono_gc_is_moving ())
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
);
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
);
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
;
7438 MonoString
*res
= (MonoString
*)mono_g_hash_table_lookup (ldstr_table
, MONO_HANDLE_RAW (str
));
7441 return MONO_HANDLE_NEW (MonoString
, res
);
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.
7452 res
= (MonoString
*)mono_g_hash_table_lookup (ldstr_table
, MONO_HANDLE_RAW (str
));
7454 MONO_HANDLE_ASSIGN_RAW (s
, res
);
7456 mono_g_hash_table_insert_internal (ldstr_table
, MONO_HANDLE_RAW (s
), MONO_HANDLE_RAW (s
));
7462 * mono_string_is_interned:
7463 * \param o String to probe
7464 * \returns Whether the string has been interned.
7467 mono_string_is_interned (MonoString
*str_raw
)
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.
7486 mono_string_intern (MonoString
*str_raw
)
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
);
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.
7506 mono_ldstr (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
)
7509 MonoString
*result
= mono_ldstr_checked (domain
, image
, idx
, error
);
7510 mono_error_cleanup (error
);
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.
7525 mono_ldstr_checked (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
, MonoError
*error
)
7527 MONO_REQ_GC_UNSAFE_MODE
;
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
);
7538 if (!mono_verifier_verify_string_signature (image
, idx
, error
))
7541 str
= MONO_HANDLE_RAW (mono_ldstr_metadata_sig (domain
, mono_metadata_user_string (image
, idx
), error
));
7543 HANDLE_FUNCTION_RETURN_VAL (str
);
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
));
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
);
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
);
7569 return mono_utf16_to_utf8 ((const gunichar2
*)str
, len
, error
);
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
;
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
]);
7596 return mono_string_intern_checked (o
, error
);
7602 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
7606 mono_ldstr_utf8 (MonoImage
*image
, guint32 idx
, MonoError
*error
)
7612 GError
*gerror
= NULL
;
7616 if (!mono_verifier_verify_string_signature (image
, idx
, error
))
7618 str
= mono_metadata_user_string (image
, idx
);
7620 len2
= mono_metadata_decode_blob_size (str
, &str
);
7623 as
= g_utf16_to_utf8 ((gunichar2
*)str
, len2
, NULL
, &written
, &gerror
);
7625 mono_error_set_argument (error
, "string", gerror
->message
);
7626 g_error_free (gerror
);
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
);
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().
7649 mono_string_to_utf8 (MonoString
*s
)
7653 result
= mono_string_to_utf8_checked_internal (s
, error
);
7655 if (!is_ok (error
)) {
7656 mono_error_cleanup (error
);
7663 * mono_utf16_to_utf8len:
7666 mono_utf16_to_utf8len (const gunichar2
*s
, gsize slength
, gsize
*utf8_length
, MonoError
*error
)
7668 MONO_REQ_GC_UNSAFE_MODE
;
7673 GError
*gerror
= NULL
;
7681 return g_strdup ("");
7683 as
= g_utf16_to_utf8 (s
, slength
, NULL
, &written
, &gerror
);
7684 *utf8_length
= written
;
7686 mono_error_set_argument (error
, "string", gerror
->message
);
7687 g_error_free (gerror
);
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
);
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.
7707 * mono_utf16_to_utf8:
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
);
7717 mono_string_to_utf8_checked_internal (MonoString
*s
, MonoError
*error
)
7719 MONO_REQ_GC_UNSAFE_MODE
;
7727 return g_strdup ("");
7729 return mono_utf16_to_utf8 (mono_string_chars_internal (s
), s
->length
, error
);
7733 mono_string_to_utf8len (MonoStringHandle s
, gsize
*utf8len
, MonoError
*error
)
7736 if (MONO_HANDLE_IS_NULL (s
))
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
;
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().
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
));
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().
7778 mono_string_to_utf8_ignore (MonoString
*s
)
7780 MONO_REQ_GC_UNSAFE_MODE
;
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
);
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
)
7814 int const length
= mono_string_handle_length (s
);
7815 mono_unichar2
* const as
= (mono_unichar2
*)g_malloc ((length
+ 1) * sizeof (*as
));
7819 memcpy (as
, mono_string_chars_internal (MONO_HANDLE_RAW (s
)), length
* sizeof (*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.
7833 mono_string_to_utf16 (MonoString
*string_obj
)
7837 MONO_EXTERNAL_ONLY (mono_unichar2
*, mono_string_to_utf16_internal (string_obj
));
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
)
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().
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.
7871 mono_string_from_utf16 (gunichar2
*data
)
7874 MonoString
*result
= mono_string_from_utf16_checked (data
, error
);
7875 mono_error_cleanup (error
);
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.
7887 mono_string_from_utf16_checked (const gunichar2
*data
, MonoError
*error
)
7889 MONO_REQ_GC_UNSAFE_MODE
;
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.
7903 mono_string_from_utf32 (/*const*/ mono_unichar4
*data
)
7906 MonoString
*result
= mono_string_from_utf32_checked (data
, error
);
7907 mono_error_cleanup (error
);
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.
7919 mono_string_from_utf32_checked (const mono_unichar4
*data
, MonoError
*error
)
7921 MONO_REQ_GC_UNSAFE_MODE
;
7924 MonoString
* result
= NULL
;
7925 mono_unichar2
*utf16_output
= NULL
;
7926 GError
*gerror
= NULL
;
7927 glong items_written
;
7933 while (data
[len
]) len
++;
7935 utf16_output
= g_ucs4_to_utf16 (data
, len
, NULL
, &items_written
, &gerror
);
7938 g_error_free (gerror
);
7940 result
= mono_string_from_utf16_checked (utf16_output
, error
);
7941 g_free (utf16_output
);
7946 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, MonoError
*error
)
7948 MONO_REQ_GC_UNSAFE_MODE
;
7954 r
= mono_string_to_utf8_checked_internal (s
, error
);
7961 len
= strlen (r
) + 1;
7963 mp_s
= (char *)mono_mempool_alloc (mp
, len
);
7965 mp_s
= (char *)mono_image_alloc (image
, len
);
7967 memcpy (mp_s
, r
, len
);
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.
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.
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
;
8004 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks
*cbs
)
8006 eh_callbacks
= *cbs
;
8009 MonoRuntimeExceptionHandlingCallbacks
*
8010 mono_get_eh_callbacks (void)
8012 return &eh_callbacks
;
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.
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.
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.
8054 mono_reraise_exception (MonoException
*ex
)
8056 mono_reraise_exception_deprecated (ex
);
8060 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
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.
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.
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
;
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. */
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
);
8113 mono_wait_handle_get_handle (MonoWaitHandle
*handle
)
8115 MONO_REQ_GC_UNSAFE_MODE
;
8117 static MonoClassField
*f_safe_handle
= NULL
;
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
);
8130 * Returns the MonoMethod to call to Capture the ExecutionContext.
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
) {
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
);
8150 mono_runtime_capture_context (MonoDomain
*domain
, MonoError
*error
)
8153 return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL
, NULL
, error
);
8155 MONO_REQ_GC_UNSAFE_MODE
;
8157 RuntimeInvokeFunction runtime_invoke
;
8161 if (!domain
->capture_context_runtime_invoke
|| !domain
->capture_context_method
) {
8162 MonoMethod
*method
= mono_get_context_capture_method ();
8163 MonoMethod
*wrapper
;
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
);
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.
8191 mono_async_result_new (MonoDomain
*domain
, HANDLE handle
, MonoObject
*state
, gpointer data
, MonoObject
*object_data
, MonoError
*error
)
8193 MONO_REQ_GC_UNSAFE_MODE
;
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 */
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
);
8212 MONO_OBJECT_SETREF_INTERNAL (res
, handle
, (MonoObject
*) wait_handle
);
8214 res
->sync_completed
= FALSE
;
8215 res
->completed
= FALSE
;
8221 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult
*ares
)
8223 MONO_REQ_GC_UNSAFE_MODE
;
8230 g_assert (ares
->async_delegate
);
8232 ac
= (MonoAsyncCall
*) ares
->object_data
;
8234 res
= mono_runtime_delegate_invoke_checked (ares
->async_delegate
, (void**) &ares
->async_state
, error
);
8235 if (mono_error_set_pending_exception (error
))
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
;
8251 mono_error_cleanup (error
);
8254 MONO_OBJECT_SETREF_INTERNAL (ac
, res
, res
);
8256 mono_monitor_enter_internal ((MonoObject
*) ares
);
8257 ares
->completed
= 1;
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
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
))
8279 mono_message_init (MonoDomain
*domain
,
8280 MonoMethodMessage
*this_obj
,
8281 MonoReflectionMethod
*method
,
8282 MonoArray
*out_args
,
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
);
8296 /* FIXME set domain instead? */
8297 g_assert (domain
== mono_domain_get ());
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.
8322 mono_remoting_invoke (MonoObject
*real_proxy
, MonoMethodMessage
*msg
, MonoObject
**exc
, MonoArray
**out_args
, MonoError
*error
)
8324 MONO_REQ_GC_UNSAFE_MODE
;
8327 MonoMethod
*im
= real_proxy
->vtable
->domain
->private_invoke_method
;
8334 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
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
);
8340 mono_error_set_not_supported (error
, "Linked away.");
8343 real_proxy
->vtable
->domain
->private_invoke_method
= im
;
8346 pa
[0] = real_proxy
;
8351 o
= mono_runtime_try_invoke (im
, NULL
, pa
, exc
, error
);
8352 return_val_if_nok (error
, NULL
);
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
;
8369 MonoMethodSignature
*sig
;
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
;
8379 return mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, exc
, out_args
, error
);
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
)
8393 if (!object_array_klass
) {
8396 klass
= mono_class_create_array (mono_defaults
.object_class
, 1);
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
);
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
) {
8417 arg
= (MonoObject
*)mono_array_get_internal (msg
->args
, gpointer
, i
);
8418 mono_array_setref_internal (*out_args
, j
, arg
);
8427 * prepare_to_string_method:
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.
8434 prepare_to_string_method (MonoObject
*obj
, void **target
)
8436 MONO_REQ_GC_UNSAFE_MODE
;
8438 static MonoMethod
*to_string
= NULL
;
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
);
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.
8467 mono_object_to_string (MonoObject
*obj
, MonoObject
**exc
)
8470 MonoString
*s
= NULL
;
8472 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
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
);
8478 mono_error_cleanup (error
);
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 */
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,
8497 mono_object_try_to_string (MonoObject
*obj
, MonoObject
**exc
, MonoError
*error
)
8502 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
8503 return (MonoString
*) mono_runtime_try_invoke (method
, target
, NULL
, exc
, error
);
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.
8523 mono_print_unhandled_exception_internal (MonoObject
*exc
)
8525 MONO_REQ_GC_UNSAFE_MODE
;
8528 char *message
= (char*)"";
8529 gboolean free_message
= FALSE
;
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
;
8540 if (((MonoException
*)exc
)->native_trace_ips
) {
8541 message
= get_native_backtrace ((MonoException
*)exc
);
8542 free_message
= TRUE
;
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
);
8549 mono_error_cleanup (error
);
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
;
8561 message
= mono_string_to_utf8_checked_internal (str
, error
);
8562 if (!is_ok (error
)) {
8563 mono_error_cleanup (error
);
8564 message
= (char *) "";
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
);
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.
8602 mono_delegate_ctor_with_method (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoMethod
*method
, MonoError
*error
)
8604 MONO_REQ_GC_UNSAFE_MODE
;
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
));
8615 MONO_HANDLE_SETVAL (delegate
, method
, MonoMethod
*, method
);
8617 UnlockedIncrement (&mono_stats
.delegate_creations
);
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
));
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
);
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
);
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.
8654 mono_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
8656 MONO_REQ_GC_UNSAFE_MODE
;
8659 MonoDomain
*domain
= mono_domain_get ();
8661 MonoMethod
*method
= NULL
;
8665 ji
= mono_jit_info_table_find (domain
, mono_get_addr_from_ftnptr (addr
));
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
));
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.
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
;
8696 MonoDomain
*domain
= mono_domain_get ();
8697 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
8698 MonoMethodMessage
*msg
;
8701 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
8702 return_val_if_nok (error
, NULL
);
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;
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
++) {
8723 if (sig
->params
[i
]->byref
)
8724 vpos
= *((gpointer
*)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
);
8734 arg
= *((MonoObject
**)vpos
);
8736 mono_array_setref_internal (msg
->args
, i
, arg
);
8739 if (cb
!= NULL
&& state
!= NULL
) {
8740 *cb
= *((MonoDelegate
**)params
[i
]);
8742 *state
= *((MonoObject
**)params
[i
]);
8749 * mono_method_return_message_restore:
8751 * Restore results from message based processing back to arguments pointers
8754 mono_method_return_message_restore (MonoMethod
*method
, gpointer
*params
, MonoArray
*out_args
, MonoError
*error
)
8756 MONO_REQ_GC_UNSAFE_MODE
;
8760 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
8761 int i
, j
, type
, size
, out_len
;
8763 if (out_args
== NULL
)
8765 out_len
= mono_array_length_internal (out_args
);
8769 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
8770 MonoType
*pt
= sig
->params
[i
];
8775 mono_error_set_execution_engine (error
, "The proxy call returned an incorrect number of output arguments");
8779 arg
= (char *)mono_array_get_internal (out_args
, gpointer
, j
);
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
);
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
);
8793 mono_gc_memmove_atomic (*((gpointer
*)params
[i
]), mono_object_get_data ((MonoObject
*)arg
), size
);
8795 size
= mono_class_value_size (mono_class_from_mono_type_internal (pt
), NULL
);
8796 mono_gc_bzero_atomic (*((gpointer
*)params
[i
]), size
);
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.
8820 mono_load_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
)
8823 gpointer result
= mono_load_remote_field_checked (this_obj
, klass
, field
, res
, error
);
8824 mono_error_cleanup (error
);
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.
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
;
8850 MonoDomain
*domain
= mono_domain_get ();
8851 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this_obj
;
8852 MonoClass
*field_class
;
8853 MonoMethodMessage
*msg
;
8854 MonoArray
*out_args
;
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
);
8867 getter
= mono_class_get_method_from_name_checked (mono_defaults
.object_class
, "FieldGetter", -1, 0, error
);
8868 return_val_if_nok (error
, NULL
);
8870 mono_error_set_not_supported (error
, "Linked away.");
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
);
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
);
8899 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
8903 if (mono_array_length_internal (out_args
) == 0)
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
);
8915 * mono_load_remote_field_new:
8919 * Missing documentation.
8922 mono_load_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
)
8926 MonoObject
*result
= mono_load_remote_field_new_checked (this_obj
, klass
, field
, error
);
8927 mono_error_cleanup (error
);
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.
8943 mono_load_remote_field_new_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoError
*error
)
8945 MONO_REQ_GC_UNSAFE_MODE
;
8949 static MonoMethod
*tp_load
= NULL
;
8951 g_assert (mono_object_is_transparent_proxy (this_obj
));
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
);
8957 mono_error_set_not_supported (error
, "Linked away.");
8962 /* MonoType *type = m_class_get_byval_arg (klass); */
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.
8982 mono_store_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
)
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.
9002 mono_store_remote_field_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
, MonoError
*error
)
9005 MONO_REQ_GC_UNSAFE_MODE
;
9009 MonoDomain
*domain
= mono_domain_get ();
9010 MonoClass
*field_class
;
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
);
9021 arg
= *((MonoObject
**)val
);
9024 return mono_store_remote_field_new_checked (this_obj
, klass
, field
, arg
, error
);
9028 * mono_store_remote_field_new:
9033 * Missing documentation
9036 mono_store_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
)
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:
9050 * Missing documentation
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
;
9061 g_assert (mono_object_is_transparent_proxy (this_obj
));
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
);
9067 mono_error_set_not_supported (error
, "Linked away.");
9077 mono_runtime_invoke_checked (tp_store
, this_obj
, args
, error
);
9078 return is_ok (error
);
9083 * mono_create_ftnptr:
9085 * Given a function address, create a function descriptor for it.
9086 * This is only needed on some platforms.
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.
9101 mono_get_addr_from_ftnptr (gpointer descr
)
9103 return callbacks
.get_addr_from_ftnptr (descr
);
9107 mono_string_chars_internal (MonoString
*s
)
9109 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
9115 * mono_string_chars:
9116 * \param s a \c MonoString
9117 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
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
;
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.
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
);
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.
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
));
9191 mono_glist_to_array (GList
*list
, MonoClass
*eclass
, MonoError
*error
)
9193 MonoDomain
*domain
= mono_domain_get ();
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
);
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
9221 mono_class_value_size (MonoClass
*klass
, guint32
*align
)
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
);
9233 *align
= m_class_get_min_align (klass
);
9239 * mono_object_get_data:
9241 * Return a pointer to the beginning of data inside a MonoObject.
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.
9255 mono_vtype_get_field_addr (gpointer vtype
, MonoClassField
*field
)
9257 return ((char*)vtype
) + field
->offset
- MONO_ABI_SIZEOF (MonoObject
);
9263 * The following section is purely to declare prototypes and
9264 * document the API, as these C files are processed by our
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
)
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
)