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
, MonoStringHandleOut string_handle
, MonoError
*error
);
76 mono_ldstr_metadata_sig (MonoDomain
*domain
, const char* sig
, MonoStringHandleOut string_handle
, 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
)
113 MONO_ENTER_GC_UNSAFE
;
115 mono_runtime_object_init_checked (this_obj
, error
);
116 mono_error_assert_ok (error
);
121 * mono_runtime_object_init_handle:
122 * \param this_obj the object to initialize
123 * \param error set on error.
124 * This function calls the zero-argument constructor (which must
125 * exist) for the given object and returns TRUE on success, or FALSE
126 * on error and sets \p error.
129 mono_runtime_object_init_handle (MonoObjectHandle this_obj
, MonoError
*error
)
131 MONO_REQ_GC_UNSAFE_MODE
;
133 HANDLE_FUNCTION_ENTER ();
136 MonoClass
* const klass
= MONO_HANDLE_GETVAL (this_obj
, vtable
)->klass
;
137 MonoMethod
* const method
= mono_class_get_method_from_name_checked (klass
, ".ctor", 0, 0, error
);
138 mono_error_assert_msg_ok (error
, "Could not lookup zero argument constructor");
139 g_assertf (method
, "Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass
));
141 if (m_class_is_valuetype (method
->klass
)) {
143 gpointer raw
= mono_object_handle_pin_unbox (this_obj
, &gchandle
);
144 mono_runtime_invoke_checked (method
, raw
, NULL
, error
);
145 mono_gchandle_free_internal (gchandle
);
147 mono_runtime_invoke_handle_void (method
, this_obj
, NULL
, error
);
150 HANDLE_FUNCTION_RETURN_VAL (is_ok (error
));
154 * mono_runtime_object_init_checked:
155 * \param this_obj the object to initialize
156 * \param error set on error.
157 * This function calls the zero-argument constructor (which must
158 * exist) for the given object and returns TRUE on success, or FALSE
159 * on error and sets \p error.
162 mono_runtime_object_init_checked (MonoObject
*this_obj_raw
, MonoError
*error
)
164 HANDLE_FUNCTION_ENTER ();
165 MONO_HANDLE_DCL (MonoObject
, this_obj
);
166 gboolean
const result
= mono_runtime_object_init_handle (this_obj
, error
);
167 HANDLE_FUNCTION_RETURN_VAL (result
);
170 /* The pseudo algorithm for type initialization from the spec
171 Note it doesn't say anything about domains - only threads.
173 2. If the type is initialized you are done.
174 2.1. If the type is not yet initialized, try to take an
176 2.2. If successful, record this thread as responsible for
177 initializing the type and proceed to step 2.3.
178 2.2.1. If not, see whether this thread or any thread
179 waiting for this thread to complete already holds the lock.
180 2.2.2. If so, return since blocking would create a deadlock. This thread
181 will now see an incompletely initialized state for the type,
182 but no deadlock will arise.
183 2.2.3 If not, block until the type is initialized then return.
184 2.3 Initialize the parent type and then all interfaces implemented
186 2.4 Execute the type initialization code for this type.
187 2.5 Mark the type as initialized, release the initialization lock,
188 awaken any threads waiting for this type to be initialized,
195 MonoNativeThreadId initializing_tid
;
196 guint32 waiting_count
;
199 /* condvar used to wait for 'done' becoming TRUE */
201 } TypeInitializationLock
;
203 /* for locking access to type_initialization_hash and blocked_thread_hash */
204 static MonoCoopMutex type_initialization_section
;
207 mono_type_initialization_lock (void)
209 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
210 mono_coop_mutex_lock (&type_initialization_section
);
214 mono_type_initialization_unlock (void)
216 mono_coop_mutex_unlock (&type_initialization_section
);
220 mono_type_init_lock (TypeInitializationLock
*lock
)
222 MONO_REQ_GC_NEUTRAL_MODE
;
224 mono_coop_mutex_lock (&lock
->mutex
);
228 mono_type_init_unlock (TypeInitializationLock
*lock
)
230 mono_coop_mutex_unlock (&lock
->mutex
);
233 /* from vtable to lock */
234 static GHashTable
*type_initialization_hash
;
236 /* from thread id to thread id being waited on */
237 static GHashTable
*blocked_thread_hash
;
240 static MonoThread
*main_thread
;
242 /* Functions supplied by the runtime */
243 static MonoRuntimeCallbacks callbacks
;
246 * mono_thread_set_main:
247 * \param thread thread to set as the main thread
248 * This function can be used to instruct the runtime to treat \p thread
249 * as the main thread, ie, the thread that would normally execute the \c Main
250 * method. This basically means that at the end of \p thread, the runtime will
251 * wait for the existing foreground threads to quit and other such details.
254 mono_thread_set_main (MonoThread
*thread
)
256 MONO_REQ_GC_UNSAFE_MODE
;
258 static gboolean registered
= FALSE
;
261 void *key
= thread
->internal_thread
? (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread
->internal_thread
->tid
) : NULL
;
262 MONO_GC_REGISTER_ROOT_SINGLE (main_thread
, MONO_ROOT_SOURCE_THREADING
, key
, "Thread Main Object");
266 main_thread
= thread
;
270 * mono_thread_get_main:
273 mono_thread_get_main (void)
275 MONO_REQ_GC_UNSAFE_MODE
;
281 mono_type_initialization_init (void)
283 mono_coop_mutex_init_recursive (&type_initialization_section
);
284 type_initialization_hash
= g_hash_table_new (NULL
, NULL
);
285 blocked_thread_hash
= g_hash_table_new (NULL
, NULL
);
286 mono_coop_mutex_init (&ldstr_section
);
287 mono_register_jit_icall (ves_icall_string_alloc
, mono_icall_sig_object_int
, FALSE
);
291 mono_type_initialization_cleanup (void)
294 /* This is causing race conditions with
295 * mono_release_type_locks
297 mono_coop_mutex_destroy (&type_initialization_section
);
298 g_hash_table_destroy (type_initialization_hash
);
299 type_initialization_hash
= NULL
;
301 mono_coop_mutex_destroy (&ldstr_section
);
302 g_hash_table_destroy (blocked_thread_hash
);
303 blocked_thread_hash
= NULL
;
308 static MonoException
*
309 mono_get_exception_type_initialization_checked (const gchar
*type_name
, MonoException
* inner_raw
, MonoError
*error
)
311 HANDLE_FUNCTION_ENTER ();
312 MONO_HANDLE_DCL (MonoException
, inner
);
313 HANDLE_FUNCTION_RETURN_OBJ (mono_get_exception_type_initialization_handle (type_name
, inner
, error
));
317 * get_type_init_exception_for_vtable:
319 * Return the stored type initialization exception for VTABLE.
321 static MonoException
*
322 get_type_init_exception_for_vtable (MonoVTable
*vtable
)
324 MONO_REQ_GC_UNSAFE_MODE
;
327 MonoDomain
*domain
= vtable
->domain
;
328 MonoClass
*klass
= vtable
->klass
;
332 if (!vtable
->init_failed
)
333 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass
));
336 * If the initializing thread was rudely aborted, the exception is not stored
340 mono_domain_lock (domain
);
341 if (domain
->type_init_exception_hash
)
342 ex
= (MonoException
*)mono_g_hash_table_lookup (domain
->type_init_exception_hash
, klass
);
343 mono_domain_unlock (domain
);
346 const char *klass_name_space
= m_class_get_name_space (klass
);
347 const char *klass_name
= m_class_get_name (klass
);
348 if (klass_name_space
&& *klass_name_space
)
349 full_name
= g_strdup_printf ("%s.%s", klass_name_space
, klass_name
);
351 full_name
= g_strdup (klass_name
);
352 ex
= mono_get_exception_type_initialization_checked (full_name
, NULL
, error
);
354 return_val_if_nok (error
, NULL
);
361 * mono_runtime_class_init:
362 * \param vtable vtable that needs to be initialized
363 * This routine calls the class constructor for \p vtable.
366 mono_runtime_class_init (MonoVTable
*vtable
)
368 MONO_REQ_GC_UNSAFE_MODE
;
371 mono_runtime_class_init_full (vtable
, error
);
372 mono_error_assert_ok (error
);
376 * Returns TRUE if the lock was freed.
377 * LOCKING: Caller should hold type_initialization_lock.
380 unref_type_lock (TypeInitializationLock
*lock
)
382 --lock
->waiting_count
;
383 if (lock
->waiting_count
== 0) {
384 mono_coop_mutex_destroy (&lock
->mutex
);
385 mono_coop_cond_destroy (&lock
->cond
);
394 * mono_runtime_run_module_cctor:
395 * \param image the image whose module ctor to run
396 * \param domain the domain to load the module class vtable in
397 * \param error set on error
398 * This routine runs the module ctor for \p image, if it hasn't already run
401 mono_runtime_run_module_cctor (MonoImage
*image
, MonoDomain
*domain
, MonoError
*error
) {
402 MONO_REQ_GC_UNSAFE_MODE
;
404 if (!image
->checked_module_cctor
) {
405 mono_image_check_for_module_cctor (image
);
406 if (image
->has_module_cctor
) {
407 MonoClass
*module_klass
;
408 MonoVTable
*module_vtable
;
410 module_klass
= mono_class_get_checked (image
, MONO_TOKEN_TYPE_DEF
| 1, error
);
415 module_vtable
= mono_class_vtable_checked (domain
, module_klass
, error
);
418 if (!mono_runtime_class_init_full (module_vtable
, error
))
426 * mono_runtime_class_init_full:
427 * \param vtable that neeeds to be initialized
428 * \param error set on error
429 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
432 mono_runtime_class_init_full (MonoVTable
*vtable
, MonoError
*error
)
434 MONO_REQ_GC_UNSAFE_MODE
;
436 MonoDomain
*domain
= vtable
->domain
;
440 if (vtable
->initialized
)
443 MonoClass
*klass
= vtable
->klass
;
445 MonoImage
*klass_image
= m_class_get_image (klass
);
446 if (!mono_runtime_run_module_cctor(klass_image
, vtable
->domain
, error
)) {
449 MonoMethod
*method
= mono_class_get_cctor (klass
);
451 vtable
->initialized
= 1;
455 MonoNativeThreadId tid
= mono_native_thread_id_get ();
458 * Due some preprocessing inside a global lock. If we are the first thread
459 * trying to initialize this class, create a separate lock+cond var, and
460 * acquire it before leaving the global lock. The other threads will wait
464 mono_type_initialization_lock ();
465 /* double check... */
466 if (vtable
->initialized
) {
467 mono_type_initialization_unlock ();
471 gboolean do_initialization
= FALSE
;
472 MonoDomain
*last_domain
= NULL
;
473 TypeInitializationLock
*lock
= NULL
;
474 gboolean pending_tae
= FALSE
;
476 gboolean ret
= FALSE
;
478 HANDLE_FUNCTION_ENTER ();
480 if (vtable
->init_failed
) {
481 /* The type initialization already failed once, rethrow the same exception */
482 MonoException
*exp
= get_type_init_exception_for_vtable (vtable
);
483 MONO_HANDLE_NEW (MonoException
, exp
);
484 /* Reset the stack_trace and trace_ips because the exception is reused */
485 exp
->stack_trace
= NULL
;
486 exp
->trace_ips
= NULL
;
487 mono_type_initialization_unlock ();
488 mono_error_set_exception_instance (error
, exp
);
491 lock
= (TypeInitializationLock
*)g_hash_table_lookup (type_initialization_hash
, vtable
);
493 /* This thread will get to do the initialization */
494 if (mono_domain_get () != domain
) {
495 /* Transfer into the target domain */
496 last_domain
= mono_domain_get ();
497 if (!mono_domain_set_fast (domain
, FALSE
)) {
498 vtable
->initialized
= 1;
499 mono_type_initialization_unlock ();
500 mono_error_set_exception_instance (error
, mono_get_exception_appdomain_unloaded ());
504 lock
= (TypeInitializationLock
*)g_malloc0 (sizeof (TypeInitializationLock
));
505 mono_coop_mutex_init_recursive (&lock
->mutex
);
506 mono_coop_cond_init (&lock
->cond
);
507 lock
->initializing_tid
= tid
;
508 lock
->waiting_count
= 1;
510 g_hash_table_insert (type_initialization_hash
, vtable
, lock
);
511 do_initialization
= TRUE
;
514 TypeInitializationLock
*pending_lock
;
516 if (mono_native_thread_id_equals (lock
->initializing_tid
, tid
)) {
517 mono_type_initialization_unlock ();
520 /* see if the thread doing the initialization is already blocked on this thread */
521 gboolean is_blocked
= TRUE
;
522 blocked
= GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock
->initializing_tid
));
523 while ((pending_lock
= (TypeInitializationLock
*) g_hash_table_lookup (blocked_thread_hash
, blocked
))) {
524 if (mono_native_thread_id_equals (pending_lock
->initializing_tid
, tid
)) {
525 if (!pending_lock
->done
) {
526 mono_type_initialization_unlock ();
529 /* the thread doing the initialization is blocked on this thread,
530 but on a lock that has already been freed. It just hasn't got
536 blocked
= GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock
->initializing_tid
));
538 ++lock
->waiting_count
;
539 /* record the fact that we are waiting on the initializing thread */
541 g_hash_table_insert (blocked_thread_hash
, GUINT_TO_POINTER (tid
), lock
);
543 mono_type_initialization_unlock ();
545 if (do_initialization
) {
546 MonoException
*exc
= NULL
;
548 /* We are holding the per-vtable lock, do the actual initialization */
550 mono_threads_begin_abort_protected_block ();
551 mono_runtime_try_invoke (method
, NULL
, NULL
, (MonoObject
**) &exc
, error
);
552 MonoExceptionHandle exch
= MONO_HANDLE_NEW (MonoException
, exc
);
553 mono_threads_end_abort_protected_block ();
555 //exception extracted, error will be set to the right value later
556 if (exc
== NULL
&& !is_ok (error
)) { // invoking failed but exc was not set
557 exc
= mono_error_convert_to_exception (error
);
558 MONO_HANDLE_ASSIGN_RAW (exch
, exc
);
560 mono_error_cleanup (error
);
562 error_init_reuse (error
);
564 const char *klass_name_space
= m_class_get_name_space (klass
);
565 const char *klass_name
= m_class_get_name (klass
);
566 /* If the initialization failed, mark the class as unusable. */
567 /* Avoid infinite loops */
569 (klass_image
== mono_defaults
.corlib
&&
570 !strcmp (klass_name_space
, "System") &&
571 !strcmp (klass_name
, "TypeInitializationException")))) {
572 vtable
->init_failed
= 1;
576 if (klass_name_space
&& *klass_name_space
)
577 full_name
= g_strdup_printf ("%s.%s", klass_name_space
, klass_name
);
579 full_name
= g_strdup (klass_name
);
581 MonoException
*exc_to_throw
= mono_get_exception_type_initialization_checked (full_name
, exc
, error
);
582 MONO_HANDLE_NEW (MonoException
, exc_to_throw
);
585 mono_error_assert_ok (error
); //We can't recover from this, no way to fail a type we can't alloc a failure.
588 * Store the exception object so it could be thrown on subsequent
591 mono_domain_lock (domain
);
592 if (!domain
->type_init_exception_hash
)
593 domain
->type_init_exception_hash
= mono_g_hash_table_new_type_internal (mono_aligned_addr_hash
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_DOMAIN
, domain
, "Domain Type Initialization Exception Table");
594 mono_g_hash_table_insert_internal (domain
->type_init_exception_hash
, klass
, exc_to_throw
);
595 mono_domain_unlock (domain
);
599 mono_domain_set_fast (last_domain
, TRUE
);
601 /* Signal to the other threads that we are done */
602 mono_type_init_lock (lock
);
604 mono_coop_cond_broadcast (&lock
->cond
);
605 mono_type_init_unlock (lock
);
608 * This can happen if the cctor self-aborts. We need to reactivate tae
609 * (next interruption checkpoint will throw it) and make sure we won't
610 * throw tie for the type.
612 if (exc
&& mono_object_class (exc
) == mono_defaults
.threadabortexception_class
) {
614 mono_thread_resume_interruption (FALSE
);
617 /* this just blocks until the initializing thread is done */
618 mono_type_init_lock (lock
);
620 mono_coop_cond_wait (&lock
->cond
, &lock
->mutex
);
621 mono_type_init_unlock (lock
);
624 /* Do cleanup and setting vtable->initialized inside the global lock again */
625 mono_type_initialization_lock ();
626 if (!do_initialization
)
627 g_hash_table_remove (blocked_thread_hash
, GUINT_TO_POINTER (tid
));
630 gboolean deleted
= unref_type_lock (lock
);
632 g_hash_table_remove (type_initialization_hash
, vtable
);
635 /* Have to set this here since we check it inside the global lock */
636 if (do_initialization
&& !vtable
->init_failed
)
637 vtable
->initialized
= 1;
638 mono_type_initialization_unlock ();
640 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
641 if (vtable
->init_failed
&& !pending_tae
) {
642 /* Either we were the initializing thread or we waited for the initialization */
643 mono_error_set_exception_instance (error
, get_type_init_exception_for_vtable (vtable
));
652 HANDLE_FUNCTION_RETURN_VAL (ret
);
656 mono_vtable_domain_internal (MonoVTable
*vtable
)
658 return vtable
->domain
;
662 mono_vtable_domain (MonoVTable
*vtable
)
664 MONO_EXTERNAL_ONLY (MonoDomain
*, mono_vtable_domain_internal (vtable
));
668 mono_vtable_class_internal (MonoVTable
*vtable
)
670 return vtable
->klass
;
674 mono_vtable_class (MonoVTable
*vtable
)
676 MONO_EXTERNAL_ONLY (MonoClass
*, mono_vtable_class_internal (vtable
));
680 gboolean
release_type_locks (gpointer key
, gpointer value
, gpointer user
)
682 MONO_REQ_GC_NEUTRAL_MODE
;
684 MonoVTable
*vtable
= (MonoVTable
*)key
;
686 TypeInitializationLock
*lock
= (TypeInitializationLock
*) value
;
687 if (mono_native_thread_id_equals (lock
->initializing_tid
, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user
))) && !lock
->done
) {
690 * Have to set this since it cannot be set by the normal code in
691 * mono_runtime_class_init (). In this case, the exception object is not stored,
692 * and get_type_init_exception_for_class () needs to be aware of this.
694 mono_type_init_lock (lock
);
695 vtable
->init_failed
= 1;
696 mono_coop_cond_broadcast (&lock
->cond
);
697 mono_type_init_unlock (lock
);
698 gboolean deleted
= unref_type_lock (lock
);
706 mono_release_type_locks (MonoInternalThread
*thread
)
708 MONO_REQ_GC_UNSAFE_MODE
;
710 mono_type_initialization_lock ();
711 g_hash_table_foreach_remove (type_initialization_hash
, release_type_locks
, GUINT_TO_POINTER (thread
->tid
));
712 mono_type_initialization_unlock ();
715 #ifndef DISABLE_REMOTING
718 create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
720 if (!callbacks
.create_remoting_trampoline
)
721 g_error ("remoting not installed");
722 return callbacks
.create_remoting_trampoline (domain
, method
, target
, error
);
727 static MonoImtTrampolineBuilder imt_trampoline_builder
;
728 static gboolean always_build_imt_trampolines
;
730 #if (MONO_IMT_SIZE > 32)
731 #error "MONO_IMT_SIZE cannot be larger than 32"
735 mono_install_callbacks (MonoRuntimeCallbacks
*cbs
)
737 memcpy (&callbacks
, cbs
, sizeof (*cbs
));
740 MonoRuntimeCallbacks
*
741 mono_get_runtime_callbacks (void)
747 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func
)
749 imt_trampoline_builder
= func
;
753 mono_set_always_build_imt_trampolines (gboolean value
)
755 always_build_imt_trampolines
= value
;
759 * mono_compile_method:
760 * \param method The method to compile.
761 * This JIT-compiles the method, and returns the pointer to the native code
765 mono_compile_method (MonoMethod
*method
)
769 MONO_ENTER_GC_UNSAFE
;
772 result
= mono_compile_method_checked (method
, error
);
773 mono_error_cleanup (error
);
781 * mono_compile_method_checked:
782 * \param method The method to compile.
783 * \param error set on error.
784 * This JIT-compiles the method, and returns the pointer to the native code
785 * produced. On failure returns NULL and sets \p error.
788 mono_compile_method_checked (MonoMethod
*method
, MonoError
*error
)
792 MONO_REQ_GC_NEUTRAL_MODE
796 g_assert (callbacks
.compile_method
);
797 res
= callbacks
.compile_method (method
, error
);
802 mono_runtime_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
, MonoError
*error
)
806 MONO_REQ_GC_NEUTRAL_MODE
;
809 res
= callbacks
.create_jump_trampoline (domain
, method
, add_sync_wrapper
, error
);
814 mono_runtime_create_delegate_trampoline (MonoClass
*klass
)
816 MONO_REQ_GC_NEUTRAL_MODE
818 g_assert (callbacks
.create_delegate_trampoline
);
819 return callbacks
.create_delegate_trampoline (mono_domain_get (), klass
);
823 * mono_runtime_free_method:
824 * \param domain domain where the method is hosted
825 * \param method method to release
826 * This routine is invoked to free the resources associated with
827 * a method that has been JIT compiled. This is used to discard
828 * methods that were used only temporarily (for example, used in marshalling)
831 mono_runtime_free_method (MonoDomain
*domain
, MonoMethod
*method
)
833 MONO_REQ_GC_NEUTRAL_MODE
835 if (callbacks
.free_method
)
836 callbacks
.free_method (domain
, method
);
838 mono_method_clear_object (domain
, method
);
840 mono_free_method (method
);
844 * The vtables in the root appdomain are assumed to be reachable by other
845 * roots, and we don't use typed allocation in the other domains.
848 /* The sync block is no longer a GC pointer */
849 #define GC_HEADER_BITMAP (0)
851 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
853 #define MONO_OBJECT_HEADER_BITS (MONO_ABI_SIZEOF (MonoObject) / MONO_ABI_SIZEOF (gpointer))
856 compute_class_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
, int *max_set
, gboolean static_fields
)
858 MONO_REQ_GC_NEUTRAL_MODE
;
860 MonoClassField
*field
;
863 int max_size
, wordsize
;
865 wordsize
= TARGET_SIZEOF_VOID_P
;
868 max_size
= mono_class_data_size (klass
) / wordsize
;
870 max_size
= m_class_get_instance_size (klass
) / wordsize
;
871 if (max_size
> size
) {
872 g_assert (offset
<= 0);
873 bitmap
= (gsize
*)g_malloc0 ((max_size
+ BITMAP_EL_SIZE
- 1) / BITMAP_EL_SIZE
* sizeof (gsize
));
877 /* An Ephemeron cannot be marked by sgen */
878 if (mono_gc_is_moving () && !static_fields
&& m_class_get_image (klass
) == mono_defaults
.corlib
&& !strcmp ("Ephemeron", m_class_get_name (klass
))) {
880 memset (bitmap
, 0, size
/ 8);
884 for (p
= klass
; p
!= NULL
; p
= m_class_get_parent (p
)) {
885 gpointer iter
= NULL
;
886 while ((field
= mono_class_get_fields_internal (p
, &iter
))) {
890 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
892 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
895 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
898 /* FIXME: should not happen, flag as type load error */
899 if (field
->type
->byref
)
902 if (static_fields
&& field
->offset
== -1)
906 pos
= field
->offset
/ TARGET_SIZEOF_VOID_P
;
909 type
= mono_type_get_underlying_type (field
->type
);
910 switch (type
->type
) {
914 case MONO_TYPE_FNPTR
:
916 case MONO_TYPE_STRING
:
917 case MONO_TYPE_SZARRAY
:
918 case MONO_TYPE_CLASS
:
919 case MONO_TYPE_OBJECT
:
920 case MONO_TYPE_ARRAY
:
921 g_assert ((field
->offset
% wordsize
) == 0);
923 g_assert (pos
< size
|| pos
<= max_size
);
924 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
925 *max_set
= MAX (*max_set
, pos
);
927 case MONO_TYPE_GENERICINST
:
928 if (!mono_type_generic_inst_is_valuetype (type
)) {
929 g_assert ((field
->offset
% wordsize
) == 0);
931 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
932 *max_set
= MAX (*max_set
, pos
);
937 case MONO_TYPE_VALUETYPE
: {
938 MonoClass
*fclass
= mono_class_from_mono_type_internal (field
->type
);
939 if (m_class_has_references (fclass
)) {
940 /* remove the object header */
941 compute_class_bitmap (fclass
, bitmap
, size
, pos
- MONO_OBJECT_HEADER_BITS
, max_set
, FALSE
);
955 case MONO_TYPE_BOOLEAN
:
959 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type
->type
, mono_type_get_full_name (field
->parent
), field
->name
);
970 * mono_class_compute_bitmap:
972 * Mono internal function to compute a bitmap of reference fields in a class.
975 mono_class_compute_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
, int *max_set
, gboolean static_fields
)
977 MONO_REQ_GC_NEUTRAL_MODE
;
979 return compute_class_bitmap (klass
, bitmap
, size
, offset
, max_set
, static_fields
);
984 * similar to the above, but sets the bits in the bitmap for any non-ref field
985 * and ignores static fields
988 compute_class_non_ref_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
)
990 MonoClassField
*field
;
993 int max_size
, wordsize
;
995 wordsize
= TARGET_SIZEOF_VOID_P
;
997 max_size
= class->instance_size
/ wordsize
;
998 if (max_size
>= size
)
999 bitmap
= g_malloc0 (sizeof (gsize
) * ((max_size
) + 1));
1001 for (p
= class; p
!= NULL
; p
= p
->parent
) {
1002 gpointer iter
= NULL
;
1003 while ((field
= mono_class_get_fields_internal (p
, &iter
))) {
1006 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
1008 /* FIXME: should not happen, flag as type load error */
1009 if (field
->type
->byref
)
1012 pos
= field
->offset
/ wordsize
;
1015 type
= mono_type_get_underlying_type (field
->type
);
1016 switch (type
->type
) {
1017 #if SIZEOF_VOID_P == 8
1021 case MONO_TYPE_FNPTR
:
1026 if ((((field
->offset
+ 7) / wordsize
) + offset
) != pos
) {
1027 pos2
= ((field
->offset
+ 7) / wordsize
) + offset
;
1028 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
1031 #if SIZEOF_VOID_P == 4
1035 case MONO_TYPE_FNPTR
:
1040 if ((((field
->offset
+ 3) / wordsize
) + offset
) != pos
) {
1041 pos2
= ((field
->offset
+ 3) / wordsize
) + offset
;
1042 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
1045 case MONO_TYPE_CHAR
:
1048 if ((((field
->offset
+ 1) / wordsize
) + offset
) != pos
) {
1049 pos2
= ((field
->offset
+ 1) / wordsize
) + offset
;
1050 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
1053 case MONO_TYPE_BOOLEAN
:
1056 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
1058 case MONO_TYPE_STRING
:
1059 case MONO_TYPE_SZARRAY
:
1060 case MONO_TYPE_CLASS
:
1061 case MONO_TYPE_OBJECT
:
1062 case MONO_TYPE_ARRAY
:
1064 case MONO_TYPE_GENERICINST
:
1065 if (!mono_type_generic_inst_is_valuetype (type
)) {
1070 case MONO_TYPE_VALUETYPE
: {
1071 MonoClass
*fclass
= mono_class_from_mono_type_internal (field
->type
);
1072 /* remove the object header */
1073 compute_class_non_ref_bitmap (fclass
, bitmap
, size
, pos
- MONO_OBJECT_HEADER_BITS
);
1077 g_assert_not_reached ();
1086 * mono_class_insecure_overlapping:
1087 * check if a class with explicit layout has references and non-references
1088 * fields overlapping.
1090 * Returns: TRUE if it is insecure to load the type.
1093 mono_class_insecure_overlapping (MonoClass
*klass
)
1097 gsize default_bitmap
[4] = {0};
1099 gsize default_nrbitmap
[4] = {0};
1100 int i
, insecure
= FALSE
;
1103 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
1104 nrbitmap
= compute_class_non_ref_bitmap (klass
, default_nrbitmap
, sizeof (default_nrbitmap
) * 8, 0);
1106 for (i
= 0; i
<= max_set
; i
+= sizeof (bitmap
[0]) * 8) {
1107 int idx
= i
% (sizeof (bitmap
[0]) * 8);
1108 if (bitmap
[idx
] & nrbitmap
[idx
]) {
1113 if (bitmap
!= default_bitmap
)
1115 if (nrbitmap
!= default_nrbitmap
)
1118 g_print ("class %s.%s in assembly %s has overlapping references\n", klass
->name_space
, klass
->name
, klass
->image
->name
);
1126 ves_icall_string_alloc_impl (int length
, MonoError
*error
)
1128 MonoString
*s
= mono_string_new_size_checked (mono_domain_get (), length
, error
);
1129 return_val_if_nok (error
, NULL_HANDLE_STRING
);
1130 return MONO_HANDLE_NEW (MonoString
, s
);
1133 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
1135 /* LOCKING: Acquires the loader lock */
1137 * Sets the following fields in KLASS:
1142 mono_class_compute_gc_descriptor (MonoClass
*klass
)
1144 MONO_REQ_GC_NEUTRAL_MODE
;
1148 gsize default_bitmap
[4] = {0};
1149 MonoGCDescriptor gc_descr
;
1151 if (!m_class_is_inited (klass
))
1152 mono_class_init_internal (klass
);
1154 if (m_class_is_gc_descr_inited (klass
))
1157 bitmap
= default_bitmap
;
1158 if (klass
== mono_defaults
.string_class
) {
1159 gc_descr
= mono_gc_make_descr_for_string (bitmap
, 2);
1160 } else if (m_class_get_rank (klass
)) {
1161 MonoClass
*klass_element_class
= m_class_get_element_class (klass
);
1162 mono_class_compute_gc_descriptor (klass_element_class
);
1163 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (klass_element_class
))) {
1165 gc_descr
= mono_gc_make_descr_for_array (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
, &abm
, 1, sizeof (gpointer
));
1166 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1167 class->name_space, class->name);*/
1169 /* remove the object header */
1170 bitmap
= mono_class_compute_bitmap (klass_element_class
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(MONO_OBJECT_HEADER_BITS
), &max_set
, FALSE
);
1171 gc_descr
= mono_gc_make_descr_for_array (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
, bitmap
, mono_array_element_size (klass
) / sizeof (gpointer
), mono_array_element_size (klass
));
1172 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1173 class->name_space, class->name);*/
1176 /*static int count = 0;
1179 bitmap
= mono_class_compute_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
1181 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1182 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1184 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1186 if (m_class_has_weak_fields (klass
)) {
1187 gsize
*weak_bitmap
= NULL
;
1188 int weak_bitmap_nbits
= 0;
1190 weak_bitmap
= (gsize
*)mono_class_alloc0 (klass
, m_class_get_instance_size (klass
) / sizeof (gsize
));
1191 if (mono_class_has_static_metadata (klass
)) {
1192 for (MonoClass
*p
= klass
; p
!= NULL
; p
= m_class_get_parent (p
)) {
1193 gpointer iter
= NULL
;
1194 guint32 first_field_idx
= mono_class_get_first_field_idx (p
);
1195 MonoClassField
*field
;
1197 MonoClassField
*p_fields
= m_class_get_fields (p
);
1198 MonoImage
*p_image
= m_class_get_image (p
);
1199 while ((field
= mono_class_get_fields_internal (p
, &iter
))) {
1200 guint32 field_idx
= first_field_idx
+ (field
- p_fields
);
1201 if (MONO_TYPE_IS_REFERENCE (field
->type
) && mono_assembly_is_weak_field (p_image
, field_idx
+ 1)) {
1202 int pos
= field
->offset
/ sizeof (gpointer
);
1203 if (pos
+ 1 > weak_bitmap_nbits
)
1204 weak_bitmap_nbits
= pos
+ 1;
1205 weak_bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
1211 for (int pos
= 0; pos
< weak_bitmap_nbits
; ++pos
) {
1212 if (weak_bitmap
[pos
/ BITMAP_EL_SIZE
] & ((gsize
)1) << (pos
% BITMAP_EL_SIZE
)) {
1213 /* Clear the normal bitmap so these refs don't keep an object alive */
1214 bitmap
[pos
/ BITMAP_EL_SIZE
] &= ~(((gsize
)1) << (pos
% BITMAP_EL_SIZE
));
1218 mono_loader_lock ();
1219 mono_class_set_weak_bitmap (klass
, weak_bitmap_nbits
, weak_bitmap
);
1220 mono_loader_unlock ();
1223 gc_descr
= mono_gc_make_descr_for_object (bitmap
, max_set
+ 1, m_class_get_instance_size (klass
));
1226 if (bitmap
!= default_bitmap
)
1229 /* Publish the data */
1230 mono_class_publish_gc_descriptor (klass
, gc_descr
);
1234 * field_is_special_static:
1235 * @fklass: The MonoClass to look up.
1236 * @field: The MonoClassField describing the field.
1238 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1239 * SPECIAL_STATIC_NONE otherwise.
1242 field_is_special_static (MonoClass
*fklass
, MonoClassField
*field
)
1244 MONO_REQ_GC_NEUTRAL_MODE
;
1247 MonoCustomAttrInfo
*ainfo
;
1249 ainfo
= mono_custom_attrs_from_field_checked (fklass
, field
, error
);
1250 mono_error_cleanup (error
); /* FIXME don't swallow the error? */
1253 for (i
= 0; i
< ainfo
->num_attrs
; ++i
) {
1254 MonoClass
*klass
= ainfo
->attrs
[i
].ctor
->klass
;
1255 if (m_class_get_image (klass
) == mono_defaults
.corlib
) {
1256 const char *klass_name
= m_class_get_name (klass
);
1257 if (strcmp (klass_name
, "ThreadStaticAttribute") == 0) {
1258 mono_custom_attrs_free (ainfo
);
1259 return SPECIAL_STATIC_THREAD
;
1261 else if (strcmp (klass_name
, "ContextStaticAttribute") == 0) {
1262 mono_custom_attrs_free (ainfo
);
1263 return SPECIAL_STATIC_CONTEXT
;
1267 mono_custom_attrs_free (ainfo
);
1268 return SPECIAL_STATIC_NONE
;
1271 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1272 #define mix(a,b,c) { \
1273 a -= c; a ^= rot(c, 4); c += b; \
1274 b -= a; b ^= rot(a, 6); a += c; \
1275 c -= b; c ^= rot(b, 8); b += a; \
1276 a -= c; a ^= rot(c,16); c += b; \
1277 b -= a; b ^= rot(a,19); a += c; \
1278 c -= b; c ^= rot(b, 4); b += a; \
1280 #define mono_final(a,b,c) { \
1281 c ^= b; c -= rot(b,14); \
1282 a ^= c; a -= rot(c,11); \
1283 b ^= a; b -= rot(a,25); \
1284 c ^= b; c -= rot(b,16); \
1285 a ^= c; a -= rot(c,4); \
1286 b ^= a; b -= rot(a,14); \
1287 c ^= b; c -= rot(b,24); \
1291 * mono_method_get_imt_slot:
1293 * The IMT slot is embedded into AOTed code, so this must return the same value
1294 * for the same method across all executions. This means:
1295 * - pointers shouldn't be used as hash values.
1296 * - mono_metadata_str_hash () should be used for hashing strings.
1299 mono_method_get_imt_slot (MonoMethod
*method
)
1301 MONO_REQ_GC_NEUTRAL_MODE
;
1303 MonoMethodSignature
*sig
;
1305 guint32
*hashes_start
, *hashes
;
1309 /* This can be used to stress tests the collision code */
1313 * We do this to simplify generic sharing. It will hurt
1314 * performance in cases where a class implements two different
1315 * instantiations of the same generic interface.
1316 * The code in build_imt_slots () depends on this.
1318 if (method
->is_inflated
)
1319 method
= ((MonoMethodInflated
*)method
)->declaring
;
1321 sig
= mono_method_signature_internal (method
);
1322 hashes_count
= sig
->param_count
+ 4;
1323 hashes_start
= (guint32
*)g_malloc (hashes_count
* sizeof (guint32
));
1324 hashes
= hashes_start
;
1326 if (! MONO_CLASS_IS_INTERFACE_INTERNAL (method
->klass
)) {
1327 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1328 m_class_get_name_space (method
->klass
), m_class_get_name (method
->klass
), method
->name
);
1331 /* Initialize hashes */
1332 hashes
[0] = mono_metadata_str_hash (m_class_get_name (method
->klass
));
1333 hashes
[1] = mono_metadata_str_hash (m_class_get_name_space (method
->klass
));
1334 hashes
[2] = mono_metadata_str_hash (method
->name
);
1335 hashes
[3] = mono_metadata_type_hash (sig
->ret
);
1336 for (i
= 0; i
< sig
->param_count
; i
++) {
1337 hashes
[4 + i
] = mono_metadata_type_hash (sig
->params
[i
]);
1340 /* Setup internal state */
1341 a
= b
= c
= 0xdeadbeef + (((guint32
)hashes_count
)<<2);
1343 /* Handle most of the hashes */
1344 while (hashes_count
> 3) {
1353 /* Handle the last 3 hashes (all the case statements fall through) */
1354 switch (hashes_count
) {
1355 case 3 : c
+= hashes
[2];
1356 case 2 : b
+= hashes
[1];
1357 case 1 : a
+= hashes
[0];
1359 case 0: /* nothing left to add */
1363 g_free (hashes_start
);
1364 /* Report the result */
1365 return c
% MONO_IMT_SIZE
;
1374 add_imt_builder_entry (MonoImtBuilderEntry
**imt_builder
, MonoMethod
*method
, guint32
*imt_collisions_bitmap
, int vtable_slot
, int slot_num
) {
1375 MONO_REQ_GC_NEUTRAL_MODE
;
1377 guint32 imt_slot
= mono_method_get_imt_slot (method
);
1378 MonoImtBuilderEntry
*entry
;
1380 if (slot_num
>= 0 && imt_slot
!= slot_num
) {
1381 /* we build just a single imt slot and this is not it */
1385 entry
= (MonoImtBuilderEntry
*)g_malloc0 (sizeof (MonoImtBuilderEntry
));
1386 entry
->key
= method
;
1387 entry
->value
.vtable_slot
= vtable_slot
;
1388 entry
->next
= imt_builder
[imt_slot
];
1389 if (imt_builder
[imt_slot
] != NULL
) {
1390 entry
->children
= imt_builder
[imt_slot
]->children
+ 1;
1391 if (entry
->children
== 1) {
1392 UnlockedIncrement (&mono_stats
.imt_slots_with_collisions
);
1393 *imt_collisions_bitmap
|= (1 << imt_slot
);
1396 entry
->children
= 0;
1397 UnlockedIncrement (&mono_stats
.imt_used_slots
);
1399 imt_builder
[imt_slot
] = entry
;
1402 char *method_name
= mono_method_full_name (method
, TRUE
);
1403 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1404 method
, method_name
, imt_slot
, vtable_slot
, entry
->children
);
1405 g_free (method_name
);
1412 print_imt_entry (const char* message
, MonoImtBuilderEntry
*e
, int num
) {
1414 MonoMethod
*method
= e
->key
;
1415 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1419 method
->klass
->name_space
,
1420 method
->klass
->name
,
1423 printf (" * %s: NULL\n", message
);
1429 compare_imt_builder_entries (const void *p1
, const void *p2
) {
1430 MonoImtBuilderEntry
*e1
= *(MonoImtBuilderEntry
**) p1
;
1431 MonoImtBuilderEntry
*e2
= *(MonoImtBuilderEntry
**) p2
;
1433 return (e1
->key
< e2
->key
) ? -1 : ((e1
->key
> e2
->key
) ? 1 : 0);
1437 imt_emit_ir (MonoImtBuilderEntry
**sorted_array
, int start
, int end
, GPtrArray
*out_array
)
1439 MONO_REQ_GC_NEUTRAL_MODE
;
1441 int count
= end
- start
;
1442 int chunk_start
= out_array
->len
;
1445 for (i
= start
; i
< end
; ++i
) {
1446 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1447 item
->key
= sorted_array
[i
]->key
;
1448 item
->value
= sorted_array
[i
]->value
;
1449 item
->has_target_code
= sorted_array
[i
]->has_target_code
;
1450 item
->is_equals
= TRUE
;
1452 item
->check_target_idx
= out_array
->len
+ 1;
1454 item
->check_target_idx
= 0;
1455 g_ptr_array_add (out_array
, item
);
1458 int middle
= start
+ count
/ 2;
1459 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1461 item
->key
= sorted_array
[middle
]->key
;
1462 item
->is_equals
= FALSE
;
1463 g_ptr_array_add (out_array
, item
);
1464 imt_emit_ir (sorted_array
, start
, middle
, out_array
);
1465 item
->check_target_idx
= imt_emit_ir (sorted_array
, middle
, end
, out_array
);
1471 imt_sort_slot_entries (MonoImtBuilderEntry
*entries
) {
1472 MONO_REQ_GC_NEUTRAL_MODE
;
1474 int number_of_entries
= entries
->children
+ 1;
1475 MonoImtBuilderEntry
**sorted_array
= (MonoImtBuilderEntry
**)g_malloc (sizeof (MonoImtBuilderEntry
*) * number_of_entries
);
1476 GPtrArray
*result
= g_ptr_array_new ();
1477 MonoImtBuilderEntry
*current_entry
;
1480 for (current_entry
= entries
, i
= 0; current_entry
!= NULL
; current_entry
= current_entry
->next
, i
++) {
1481 sorted_array
[i
] = current_entry
;
1483 mono_qsort (sorted_array
, number_of_entries
, sizeof (MonoImtBuilderEntry
*), compare_imt_builder_entries
);
1485 /*for (i = 0; i < number_of_entries; i++) {
1486 print_imt_entry (" sorted array:", sorted_array [i], i);
1489 imt_emit_ir (sorted_array
, 0, number_of_entries
, result
);
1491 g_free (sorted_array
);
1496 initialize_imt_slot (MonoVTable
*vtable
, MonoDomain
*domain
, MonoImtBuilderEntry
*imt_builder_entry
, gpointer fail_tramp
)
1498 MONO_REQ_GC_NEUTRAL_MODE
;
1500 if (imt_builder_entry
!= NULL
) {
1501 if (imt_builder_entry
->children
== 0 && !fail_tramp
&& !always_build_imt_trampolines
) {
1502 /* No collision, return the vtable slot contents */
1503 return vtable
->vtable
[imt_builder_entry
->value
.vtable_slot
];
1505 /* Collision, build the trampoline */
1506 GPtrArray
*imt_ir
= imt_sort_slot_entries (imt_builder_entry
);
1509 result
= imt_trampoline_builder (vtable
, domain
,
1510 (MonoIMTCheckItem
**)imt_ir
->pdata
, imt_ir
->len
, fail_tramp
);
1511 for (i
= 0; i
< imt_ir
->len
; ++i
)
1512 g_free (g_ptr_array_index (imt_ir
, i
));
1513 g_ptr_array_free (imt_ir
, TRUE
);
1525 static MonoImtBuilderEntry
*
1526 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
);
1529 * LOCKING: requires the loader and domain locks.
1533 build_imt_slots (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
, int slot_num
)
1535 MONO_REQ_GC_NEUTRAL_MODE
;
1539 guint32 imt_collisions_bitmap
= 0;
1540 MonoImtBuilderEntry
**imt_builder
= (MonoImtBuilderEntry
**)g_calloc (MONO_IMT_SIZE
, sizeof (MonoImtBuilderEntry
*));
1541 int method_count
= 0;
1542 gboolean record_method_count_for_max_collisions
= FALSE
;
1543 gboolean has_generic_virtual
= FALSE
, has_variant_iface
= FALSE
;
1546 printf ("Building IMT for class %s.%s slot %d\n", m_class_get_name_space (klass
), m_class_get_name (klass
), slot_num
);
1548 int klass_interface_offsets_count
= m_class_get_interface_offsets_count (klass
);
1549 MonoClass
**klass_interfaces_packed
= m_class_get_interfaces_packed (klass
);
1550 guint16
*klass_interface_offsets_packed
= m_class_get_interface_offsets_packed (klass
);
1551 for (i
= 0; i
< klass_interface_offsets_count
; ++i
) {
1552 MonoClass
*iface
= klass_interfaces_packed
[i
];
1553 int interface_offset
= klass_interface_offsets_packed
[i
];
1554 int method_slot_in_interface
, vt_slot
;
1556 if (mono_class_has_variant_generic_params (iface
))
1557 has_variant_iface
= TRUE
;
1559 mono_class_setup_methods (iface
);
1560 vt_slot
= interface_offset
;
1561 int mcount
= mono_class_get_method_count (iface
);
1562 for (method_slot_in_interface
= 0; method_slot_in_interface
< mcount
; method_slot_in_interface
++) {
1565 if (slot_num
>= 0 && mono_class_is_ginst (iface
)) {
1567 * The imt slot of the method is the same as for its declaring method,
1568 * see the comment in mono_method_get_imt_slot (), so we can
1569 * avoid inflating methods which will be discarded by
1570 * add_imt_builder_entry anyway.
1572 method
= mono_class_get_method_by_index (mono_class_get_generic_class (iface
)->container_class
, method_slot_in_interface
);
1573 if (mono_method_get_imt_slot (method
) != slot_num
) {
1578 method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1579 if (method
->is_generic
) {
1580 has_generic_virtual
= TRUE
;
1585 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) {
1586 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, vt_slot
, slot_num
);
1591 if (extra_interfaces
) {
1592 int interface_offset
= m_class_get_vtable_size (klass
);
1594 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
1595 MonoClass
* iface
= (MonoClass
*)list_item
->data
;
1596 int method_slot_in_interface
;
1597 int mcount
= mono_class_get_method_count (iface
);
1598 for (method_slot_in_interface
= 0; method_slot_in_interface
< mcount
; method_slot_in_interface
++) {
1599 MonoMethod
*method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1601 if (method
->is_generic
)
1602 has_generic_virtual
= TRUE
;
1603 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, interface_offset
+ method_slot_in_interface
, slot_num
);
1605 interface_offset
+= mcount
;
1608 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
) {
1609 /* overwrite the imt slot only if we're building all the entries or if
1610 * we're building this specific one
1612 if (slot_num
< 0 || i
== slot_num
) {
1613 MonoImtBuilderEntry
*entries
= get_generic_virtual_entries (domain
, &imt
[i
]);
1616 if (imt_builder
[i
]) {
1617 MonoImtBuilderEntry
*entry
;
1619 /* Link entries with imt_builder [i] */
1620 for (entry
= entries
; entry
->next
; entry
= entry
->next
) {
1622 MonoMethod
*method
= (MonoMethod
*)entry
->key
;
1623 char *method_name
= mono_method_full_name (method
, TRUE
);
1624 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method
, method_name
, i
);
1625 g_free (method_name
);
1628 entry
->next
= imt_builder
[i
];
1629 entries
->children
+= imt_builder
[i
]->children
+ 1;
1631 imt_builder
[i
] = entries
;
1634 if (has_generic_virtual
|| has_variant_iface
) {
1636 * There might be collisions later when the the trampoline is expanded.
1638 imt_collisions_bitmap
|= (1 << i
);
1641 * The IMT trampoline might be called with an instance of one of the
1642 * generic virtual methods, so has to fallback to the IMT trampoline.
1644 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], callbacks
.get_imt_trampoline (vt
, i
));
1646 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], NULL
);
1649 printf ("initialize_imt_slot[%d]: %p methods %d\n", i
, imt
[i
], imt_builder
[i
]->children
+ 1);
1653 if (imt_builder
[i
] != NULL
) {
1654 int methods_in_slot
= imt_builder
[i
]->children
+ 1;
1655 if (methods_in_slot
> UnlockedRead (&mono_stats
.imt_max_collisions_in_slot
)) {
1656 UnlockedWrite (&mono_stats
.imt_max_collisions_in_slot
, methods_in_slot
);
1657 record_method_count_for_max_collisions
= TRUE
;
1659 method_count
+= methods_in_slot
;
1663 UnlockedAdd (&mono_stats
.imt_number_of_methods
, method_count
);
1664 if (record_method_count_for_max_collisions
) {
1665 UnlockedWrite (&mono_stats
.imt_method_count_when_max_collisions
, method_count
);
1668 for (i
= 0; i
< MONO_IMT_SIZE
; i
++) {
1669 MonoImtBuilderEntry
* entry
= imt_builder
[i
];
1670 while (entry
!= NULL
) {
1671 MonoImtBuilderEntry
* next
= entry
->next
;
1676 g_free (imt_builder
);
1677 /* we OR the bitmap since we may build just a single imt slot at a time */
1678 vt
->imt_collisions_bitmap
|= imt_collisions_bitmap
;
1682 build_imt (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
) {
1683 MONO_REQ_GC_NEUTRAL_MODE
;
1685 build_imt_slots (klass
, vt
, domain
, imt
, extra_interfaces
, -1);
1689 * mono_vtable_build_imt_slot:
1690 * \param vtable virtual object table struct
1691 * \param imt_slot slot in the IMT table
1692 * Fill the given \p imt_slot in the IMT table of \p vtable with
1693 * a trampoline or a trampoline for the case of collisions.
1694 * This is part of the internal mono API.
1695 * LOCKING: Take the domain lock.
1698 mono_vtable_build_imt_slot (MonoVTable
* vtable
, int imt_slot
)
1700 MONO_REQ_GC_NEUTRAL_MODE
;
1702 gpointer
*imt
= (gpointer
*)vtable
;
1703 imt
-= MONO_IMT_SIZE
;
1704 g_assert (imt_slot
>= 0 && imt_slot
< MONO_IMT_SIZE
);
1706 /* no support for extra interfaces: the proxy objects will need
1707 * to build the complete IMT
1708 * Update and heck needs to ahppen inside the proper domain lock, as all
1709 * the changes made to a MonoVTable.
1711 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1712 mono_domain_lock (vtable
->domain
);
1713 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1714 if (!callbacks
.imt_entry_inited (vtable
, imt_slot
))
1715 build_imt_slots (vtable
->klass
, vtable
, vtable
->domain
, imt
, NULL
, imt_slot
);
1716 mono_domain_unlock (vtable
->domain
);
1717 mono_loader_unlock ();
1720 #define THUNK_THRESHOLD 10
1723 * mono_method_alloc_generic_virtual_trampoline:
1724 * \param domain a domain
1725 * \param size size in bytes
1726 * Allocs \p size bytes to be used for the code of a generic virtual
1727 * trampoline. It's either allocated from the domain's code manager or
1728 * reused from a previously invalidated piece.
1729 * LOCKING: The domain lock must be held.
1732 (mono_method_alloc_generic_virtual_trampoline
) (MonoDomain
*domain
, int size
)
1734 MONO_REQ_GC_NEUTRAL_MODE
;
1736 static gboolean inited
= FALSE
;
1737 static int generic_virtual_trampolines_size
= 0;
1740 mono_counters_register ("Generic virtual trampoline bytes",
1741 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &generic_virtual_trampolines_size
);
1744 generic_virtual_trampolines_size
+= size
;
1746 return mono_domain_code_reserve (domain
, size
);
1749 typedef struct _GenericVirtualCase
{
1753 struct _GenericVirtualCase
*next
;
1754 } GenericVirtualCase
;
1757 * get_generic_virtual_entries:
1759 * Return IMT entries for the generic virtual method instances and
1760 * variant interface methods for vtable slot
1763 static MonoImtBuilderEntry
*
1764 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
)
1766 MONO_REQ_GC_NEUTRAL_MODE
;
1768 GenericVirtualCase
*list
;
1769 MonoImtBuilderEntry
*entries
;
1771 mono_domain_lock (domain
);
1772 if (!domain
->generic_virtual_cases
)
1773 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1775 list
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1778 for (; list
; list
= list
->next
) {
1779 MonoImtBuilderEntry
*entry
;
1781 if (list
->count
< THUNK_THRESHOLD
)
1784 entry
= g_new0 (MonoImtBuilderEntry
, 1);
1785 entry
->key
= list
->method
;
1786 entry
->value
.target_code
= mono_get_addr_from_ftnptr (list
->code
);
1787 entry
->has_target_code
= 1;
1789 entry
->children
= entries
->children
+ 1;
1790 entry
->next
= entries
;
1794 mono_domain_unlock (domain
);
1796 /* FIXME: Leaking memory ? */
1801 * \param domain a domain
1802 * \param vtable_slot pointer to the vtable slot
1803 * \param method the inflated generic virtual method
1804 * \param code the method's code
1806 * Registers a call via unmanaged code to a generic virtual method
1807 * instantiation or variant interface method. If the number of calls reaches a threshold
1808 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1809 * virtual method trampoline.
1812 mono_method_add_generic_virtual_invocation (MonoDomain
*domain
, MonoVTable
*vtable
,
1813 gpointer
*vtable_slot
,
1814 MonoMethod
*method
, gpointer code
)
1816 MONO_REQ_GC_NEUTRAL_MODE
;
1818 static gboolean inited
= FALSE
;
1819 static int num_added
= 0;
1820 static int num_freed
= 0;
1822 GenericVirtualCase
*gvc
, *list
;
1823 MonoImtBuilderEntry
*entries
;
1827 mono_domain_lock (domain
);
1828 if (!domain
->generic_virtual_cases
)
1829 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1832 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_added
);
1833 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_freed
);
1837 /* Check whether the case was already added */
1838 list
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1841 if (gvc
->method
== method
)
1846 /* If not found, make a new one */
1848 gvc
= (GenericVirtualCase
*)mono_domain_alloc (domain
, sizeof (GenericVirtualCase
));
1849 gvc
->method
= method
;
1852 gvc
->next
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1854 g_hash_table_insert (domain
->generic_virtual_cases
, vtable_slot
, gvc
);
1859 if (++gvc
->count
== THUNK_THRESHOLD
) {
1860 gpointer
*old_thunk
= (void **)*vtable_slot
;
1861 gpointer vtable_trampoline
= NULL
;
1862 gpointer imt_trampoline
= NULL
;
1864 if ((gpointer
)vtable_slot
< (gpointer
)vtable
) {
1865 int displacement
= (gpointer
*)vtable_slot
- (gpointer
*)vtable
;
1866 int imt_slot
= MONO_IMT_SIZE
+ displacement
;
1868 /* Force the rebuild of the trampoline at the next call */
1869 imt_trampoline
= callbacks
.get_imt_trampoline (vtable
, imt_slot
);
1870 *vtable_slot
= imt_trampoline
;
1872 vtable_trampoline
= callbacks
.get_vtable_trampoline
? callbacks
.get_vtable_trampoline (vtable
, (gpointer
*)vtable_slot
- (gpointer
*)vtable
->vtable
) : NULL
;
1874 entries
= get_generic_virtual_entries (domain
, vtable_slot
);
1876 sorted
= imt_sort_slot_entries (entries
);
1878 *vtable_slot
= imt_trampoline_builder (NULL
, domain
, (MonoIMTCheckItem
**)sorted
->pdata
, sorted
->len
,
1882 MonoImtBuilderEntry
*next
= entries
->next
;
1887 for (i
= 0; i
< sorted
->len
; ++i
)
1888 g_free (g_ptr_array_index (sorted
, i
));
1889 g_ptr_array_free (sorted
, TRUE
);
1891 if (old_thunk
!= vtable_trampoline
&& old_thunk
!= imt_trampoline
)
1896 mono_domain_unlock (domain
);
1899 static MonoVTable
*mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
);
1902 * mono_class_vtable:
1903 * \param domain the application domain
1904 * \param class the class to initialize
1905 * VTables are domain specific because we create domain specific code, and
1906 * they contain the domain specific static class data.
1907 * On failure, NULL is returned, and \c class->exception_type is set.
1910 mono_class_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1913 MONO_ENTER_GC_UNSAFE
;
1915 vtable
= mono_class_vtable_checked (domain
, klass
, error
);
1916 mono_error_cleanup (error
);
1917 MONO_EXIT_GC_UNSAFE
;
1922 * mono_class_vtable_checked:
1923 * \param domain the application domain
1924 * \param class the class to initialize
1925 * \param error set on failure.
1926 * VTables are domain specific because we create domain specific code, and
1927 * they contain the domain specific static class data.
1930 mono_class_vtable_checked (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
1932 MONO_REQ_GC_UNSAFE_MODE
;
1934 MonoClassRuntimeInfo
*runtime_info
;
1940 if (mono_class_has_failure (klass
)) {
1941 mono_error_set_for_class_failure (error
, klass
);
1945 /* this check can be inlined in jitted code, too */
1946 runtime_info
= m_class_get_runtime_info (klass
);
1947 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1948 return runtime_info
->domain_vtables
[domain
->domain_id
];
1949 return mono_class_create_runtime_vtable (domain
, klass
, error
);
1953 * mono_class_try_get_vtable:
1954 * \param domain the application domain
1955 * \param class the class to initialize
1956 * This function tries to get the associated vtable from \p class if
1957 * it was already created.
1960 mono_class_try_get_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1962 MONO_REQ_GC_NEUTRAL_MODE
;
1964 MonoClassRuntimeInfo
*runtime_info
;
1968 runtime_info
= m_class_get_runtime_info (klass
);
1969 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1970 return runtime_info
->domain_vtables
[domain
->domain_id
];
1975 alloc_vtable (MonoDomain
*domain
, size_t vtable_size
, size_t imt_table_bytes
)
1977 MONO_REQ_GC_NEUTRAL_MODE
;
1979 size_t alloc_offset
;
1982 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1983 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1984 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1986 if (sizeof (gpointer
) == 4 && (imt_table_bytes
& 7)) {
1987 g_assert ((imt_table_bytes
& 7) == 4);
1994 return (gpointer
*) ((char*)mono_domain_alloc0 (domain
, vtable_size
) + alloc_offset
);
1998 mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
2000 MONO_REQ_GC_UNSAFE_MODE
;
2002 HANDLE_FUNCTION_ENTER ();
2005 MonoClassRuntimeInfo
*runtime_info
;
2006 MonoClassField
*field
;
2008 int i
, vtable_slots
;
2009 size_t imt_table_bytes
;
2011 guint32 vtable_size
, class_size
;
2013 gpointer
*interface_offsets
;
2014 gboolean is_primitive_type_array
= FALSE
;
2015 gboolean use_interpreter
= callbacks
.is_interpreter_enabled ();
2017 mono_loader_lock (); /*FIXME mono_class_init_internal acquires it*/
2018 mono_domain_lock (domain
);
2020 runtime_info
= m_class_get_runtime_info (klass
);
2021 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
]) {
2022 mono_domain_unlock (domain
);
2023 mono_loader_unlock ();
2024 vt
= runtime_info
->domain_vtables
[domain
->domain_id
];
2027 if (!m_class_is_inited (klass
) || mono_class_has_failure (klass
)) {
2028 if (!mono_class_init_internal (klass
) || mono_class_has_failure (klass
)) {
2029 mono_domain_unlock (domain
);
2030 mono_loader_unlock ();
2031 mono_error_set_for_class_failure (error
, klass
);
2036 /* Array types require that their element type be valid*/
2037 if (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_ARRAY
|| m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
) {
2038 MonoClass
*element_class
= m_class_get_element_class (klass
);
2039 is_primitive_type_array
= m_class_is_primitive (element_class
);
2040 if (!m_class_is_inited (element_class
))
2041 mono_class_init_internal (element_class
);
2043 /*mono_class_init_internal can leave the vtable layout to be lazily done and we can't afford this here*/
2044 if (!mono_class_has_failure (element_class
) && !m_class_get_vtable_size (element_class
))
2045 mono_class_setup_vtable (element_class
);
2047 if (mono_class_has_failure (element_class
)) {
2048 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2049 if (!mono_class_has_failure (klass
))
2050 mono_class_set_type_load_failure (klass
, "");
2051 mono_domain_unlock (domain
);
2052 mono_loader_unlock ();
2053 mono_error_set_for_class_failure (error
, klass
);
2059 * For some classes, mono_class_init_internal () already computed klass->vtable_size, and
2060 * that is all that is needed because of the vtable trampolines.
2062 if (!m_class_get_vtable_size (klass
))
2063 mono_class_setup_vtable (klass
);
2065 if (mono_class_is_ginst (klass
) && !m_class_get_vtable (klass
))
2066 mono_class_check_vtable_constraints (klass
, NULL
);
2068 /* Initialize klass->has_finalize */
2069 mono_class_has_finalizer (klass
);
2071 if (mono_class_has_failure (klass
)) {
2072 mono_domain_unlock (domain
);
2073 mono_loader_unlock ();
2074 mono_error_set_for_class_failure (error
, klass
);
2078 vtable_slots
= m_class_get_vtable_size (klass
);
2079 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2080 class_size
= mono_class_data_size (klass
);
2084 if (m_class_get_interface_offsets_count (klass
)) {
2085 imt_table_bytes
= sizeof (gpointer
) * (MONO_IMT_SIZE
);
2086 /* Interface table for the interpreter */
2087 if (use_interpreter
)
2088 imt_table_bytes
*= 2;
2089 UnlockedIncrement (&mono_stats
.imt_number_of_tables
);
2090 UnlockedAdd (&mono_stats
.imt_tables_size
, imt_table_bytes
);
2092 imt_table_bytes
= 0;
2095 vtable_size
= imt_table_bytes
+ MONO_SIZEOF_VTABLE
+ vtable_slots
* sizeof (gpointer
);
2097 UnlockedIncrement (&mono_stats
.used_class_count
);
2098 UnlockedAdd (&mono_stats
.class_vtable_size
, vtable_size
);
2100 interface_offsets
= alloc_vtable (domain
, vtable_size
, imt_table_bytes
);
2101 vt
= (MonoVTable
*) ((char*)interface_offsets
+ imt_table_bytes
);
2102 /* If on interp, skip the interp interface table */
2103 if (use_interpreter
)
2104 interface_offsets
= (gpointer
*)((char*)interface_offsets
+ imt_table_bytes
/ 2);
2105 g_assert (!((gsize
)vt
& 7));
2108 vt
->rank
= m_class_get_rank (klass
);
2109 vt
->domain
= domain
;
2110 if ((vt
->rank
> 0) || klass
== mono_get_string_class ())
2111 vt
->flags
|= MONO_VT_FLAG_ARRAY_OR_STRING
;
2113 if (m_class_has_references (klass
))
2114 vt
->flags
|= MONO_VT_FLAG_HAS_REFERENCES
;
2116 if (is_primitive_type_array
)
2117 vt
->flags
|= MONO_VT_FLAG_ARRAY_IS_PRIMITIVE
;
2119 MONO_PROFILER_RAISE (vtable_loading
, (vt
));
2121 mono_class_compute_gc_descriptor (klass
);
2124 * We can't use typed allocation in the non-root domains, since the
2125 * collector needs the GC descriptor stored in the vtable even after
2126 * the mempool containing the vtable is destroyed when the domain is
2127 * unloaded. An alternative might be to allocate vtables in the GC
2128 * heap, but this does not seem to work (it leads to crashes inside
2129 * libgc). If that approach is tried, two gc descriptors need to be
2130 * allocated for each class: one for the root domain, and one for all
2131 * other domains. The second descriptor should contain a bit for the
2132 * vtable field in MonoObject, since we can no longer assume the
2133 * vtable is reachable by other roots after the appdomain is unloaded.
2135 if (!mono_gc_is_moving () && domain
!= mono_get_root_domain () && !mono_dont_free_domains
)
2136 vt
->gc_descr
= MONO_GC_DESCRIPTOR_NULL
;
2138 vt
->gc_descr
= m_class_get_gc_descr (klass
);
2140 gc_bits
= mono_gc_get_vtable_bits (klass
);
2141 g_assert (!(gc_bits
& ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS
) - 1)));
2143 vt
->gc_bits
= gc_bits
;
2146 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2147 if (m_class_has_static_refs (klass
)) {
2148 MonoGCDescriptor statics_gc_descr
;
2150 gsize default_bitmap
[4] = {0};
2153 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, TRUE
);
2154 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2155 statics_gc_descr
= mono_gc_make_descr_from_bitmap (bitmap
, max_set
+ 1);
2156 vt
->vtable
[m_class_get_vtable_size (klass
)] = mono_gc_alloc_fixed (class_size
, statics_gc_descr
, MONO_ROOT_SOURCE_STATIC
, vt
, "Static Fields");
2158 if (bitmap
!= default_bitmap
)
2161 vt
->vtable
[m_class_get_vtable_size (klass
)] = mono_domain_alloc0 (domain
, class_size
);
2163 vt
->has_static_fields
= TRUE
;
2164 UnlockedAdd (&mono_stats
.class_static_data_size
, class_size
);
2168 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
2169 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2171 if (mono_field_is_deleted (field
))
2173 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
2174 gint32 special_static
= m_class_has_no_special_static_fields (klass
) ? SPECIAL_STATIC_NONE
: field_is_special_static (klass
, field
);
2175 if (special_static
!= SPECIAL_STATIC_NONE
) {
2176 guint32 size
, offset
;
2178 gsize default_bitmap
[4] = {0};
2183 if (mono_type_is_reference (field
->type
)) {
2184 default_bitmap
[0] = 1;
2186 bitmap
= default_bitmap
;
2187 } else if (mono_type_is_struct (field
->type
)) {
2188 fclass
= mono_class_from_mono_type_internal (field
->type
);
2189 bitmap
= compute_class_bitmap (fclass
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(MONO_OBJECT_HEADER_BITS
), &max_set
, FALSE
);
2190 numbits
= max_set
+ 1;
2192 default_bitmap
[0] = 0;
2194 bitmap
= default_bitmap
;
2196 size
= mono_type_size (field
->type
, &align
);
2197 offset
= mono_alloc_special_static_data (special_static
, size
, align
, (uintptr_t*)bitmap
, numbits
);
2198 if (!domain
->special_static_fields
)
2199 domain
->special_static_fields
= g_hash_table_new (NULL
, NULL
);
2200 g_hash_table_insert (domain
->special_static_fields
, field
, GUINT_TO_POINTER (offset
));
2201 if (bitmap
!= default_bitmap
)
2204 * This marks the field as special static to speed up the
2205 * checks in mono_field_static_get/set_value ().
2211 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_RVA
)) {
2212 MonoClass
*fklass
= mono_class_from_mono_type_internal (field
->type
);
2213 const char *data
= mono_field_get_data (field
);
2215 g_assert (!(field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_DEFAULT
));
2216 t
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
2217 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2220 if (m_class_is_valuetype (fklass
)) {
2221 memcpy (t
, data
, mono_class_value_size (fklass
, NULL
));
2223 /* it's a pointer type: add check */
2224 g_assert ((m_class_get_byval_arg (fklass
)->type
== MONO_TYPE_PTR
) || (m_class_get_byval_arg (fklass
)->type
== MONO_TYPE_FNPTR
));
2231 vt
->max_interface_id
= m_class_get_max_interface_id (klass
);
2232 vt
->interface_bitmap
= m_class_get_interface_bitmap (klass
);
2234 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2235 // class->name, klass->interface_offsets_count);
2237 /* Initialize vtable */
2238 if (callbacks
.get_vtable_trampoline
) {
2239 // This also covers the AOT case
2240 for (i
= 0; i
< m_class_get_vtable_size (klass
); ++i
) {
2241 vt
->vtable
[i
] = callbacks
.get_vtable_trampoline (vt
, i
);
2244 mono_class_setup_vtable (klass
);
2246 for (i
= 0; i
< m_class_get_vtable_size (klass
); ++i
) {
2249 cm
= m_class_get_vtable (klass
) [i
];
2251 vt
->vtable
[i
] = callbacks
.create_jit_trampoline (domain
, cm
, error
);
2252 if (!is_ok (error
)) {
2253 mono_domain_unlock (domain
);
2254 mono_loader_unlock ();
2255 MONO_PROFILER_RAISE (vtable_failed
, (vt
));
2262 if (imt_table_bytes
) {
2263 /* Now that the vtable is full, we can actually fill up the IMT */
2264 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
)
2265 interface_offsets
[i
] = callbacks
.get_imt_trampoline (vt
, i
);
2269 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2270 * re-acquire them and check if another thread has created the vtable in the meantime.
2272 /* Special case System.MonoType to avoid infinite recursion */
2273 if (klass
!= mono_defaults
.runtimetype_class
) {
2274 MonoReflectionTypeHandle vt_type
= mono_type_get_object_handle (domain
, m_class_get_byval_arg (klass
), error
);
2275 vt
->type
= MONO_HANDLE_RAW (vt_type
);
2276 if (!is_ok (error
)) {
2277 mono_domain_unlock (domain
);
2278 mono_loader_unlock ();
2279 MONO_PROFILER_RAISE (vtable_failed
, (vt
));
2282 if (mono_handle_class (vt_type
) != mono_defaults
.runtimetype_class
)
2283 /* This is unregistered in
2284 unregister_vtable_reflection_type() in
2286 MONO_GC_REGISTER_ROOT_IF_MOVING (vt
->type
, MONO_ROOT_SOURCE_REFLECTION
, vt
, "Reflection Type Object");
2289 mono_vtable_set_is_remote (vt
, mono_class_is_contextbound (klass
));
2291 /* class_vtable_array keeps an array of created vtables
2293 g_ptr_array_add (domain
->class_vtable_array
, vt
);
2294 /* klass->runtime_info is protected by the loader lock, both when
2295 * it it enlarged and when it is stored info.
2299 * Store the vtable in klass->runtime_info.
2300 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2302 mono_memory_barrier ();
2304 mono_class_setup_runtime_info (klass
, domain
, vt
);
2306 if (klass
== mono_defaults
.runtimetype_class
) {
2307 MonoReflectionTypeHandle vt_type
= mono_type_get_object_handle (domain
, m_class_get_byval_arg (klass
), error
);
2308 vt
->type
= MONO_HANDLE_RAW (vt_type
);
2309 if (!is_ok (error
)) {
2310 mono_domain_unlock (domain
);
2311 mono_loader_unlock ();
2312 MONO_PROFILER_RAISE (vtable_failed
, (vt
));
2316 if (mono_handle_class (vt_type
) != mono_defaults
.runtimetype_class
)
2317 /* This is unregistered in
2318 unregister_vtable_reflection_type() in
2320 MONO_GC_REGISTER_ROOT_IF_MOVING(vt
->type
, MONO_ROOT_SOURCE_REFLECTION
, vt
, "Reflection Type Object");
2323 mono_domain_unlock (domain
);
2324 mono_loader_unlock ();
2326 /* make sure the parent is initialized */
2327 /*FIXME shouldn't this fail the current type?*/
2328 if (m_class_get_parent (klass
))
2329 mono_class_vtable_checked (domain
, m_class_get_parent (klass
), error
);
2331 MONO_PROFILER_RAISE (vtable_loaded
, (vt
));
2337 HANDLE_FUNCTION_RETURN_VAL (vt
);
2340 #ifndef DISABLE_REMOTING
2342 * mono_remote_class_is_interface_proxy:
2343 * \param remote_class
2345 * Returns TRUE if the given remote class is a proxying an interface (as
2346 * opposed to a class deriving from MarshalByRefObject).
2349 mono_remote_class_is_interface_proxy (MonoRemoteClass
*remote_class
)
2351 /* This if condition is taking advantage of how mono_remote_class ()
2352 * works: if that code changes, this needs to change too. */
2353 return (remote_class
->interface_count
>= 1 &&
2354 remote_class
->proxy_class
== mono_defaults
.marshalbyrefobject_class
);
2358 * mono_class_proxy_vtable:
2359 * \param domain the application domain
2360 * \param remove_class the remote class
2361 * \param error set on error
2362 * Creates a vtable for transparent proxies. It is basically
2363 * a copy of the real vtable of the class wrapped in \p remote_class,
2364 * but all function pointers invoke the remoting functions, and
2365 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2367 * On failure returns NULL and sets \p error
2370 mono_class_proxy_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRemotingTarget target_type
, MonoError
*error
)
2372 MONO_REQ_GC_UNSAFE_MODE
;
2374 MonoVTable
*vt
, *pvt
= NULL
;
2375 int i
, j
, vtsize
, extra_interface_vtsize
= 0;
2376 guint32 max_interface_id
;
2378 GSList
*extra_interfaces
= NULL
;
2379 MonoClass
*klass
= remote_class
->proxy_class
;
2380 gpointer
*interface_offsets
;
2381 uint8_t *bitmap
= NULL
;
2383 size_t imt_table_bytes
;
2384 gboolean use_interpreter
= callbacks
.is_interpreter_enabled ();
2386 #ifdef COMPRESSED_INTERFACE_BITMAP
2392 vt
= mono_class_vtable_checked (domain
, klass
, error
);
2395 max_interface_id
= vt
->max_interface_id
;
2397 /* Calculate vtable space for extra interfaces */
2398 for (j
= 0; j
< remote_class
->interface_count
; j
++) {
2399 MonoClass
* iclass
= remote_class
->interfaces
[j
];
2403 /*FIXME test for interfaces with variant generic arguments*/
2404 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, m_class_get_interface_id (iclass
)))
2405 continue; /* interface implemented by the class */
2406 if (g_slist_find (extra_interfaces
, iclass
))
2409 extra_interfaces
= g_slist_prepend (extra_interfaces
, iclass
);
2411 method_count
= mono_class_num_methods (iclass
);
2413 ifaces
= mono_class_get_implemented_interfaces (iclass
, error
);
2414 goto_if_nok (error
, failure
);
2416 for (i
= 0; i
< ifaces
->len
; ++i
) {
2417 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2418 /*FIXME test for interfaces with variant generic arguments*/
2419 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, m_class_get_interface_id (ic
)))
2420 continue; /* interface implemented by the class */
2421 if (g_slist_find (extra_interfaces
, ic
))
2423 extra_interfaces
= g_slist_prepend (extra_interfaces
, ic
);
2424 method_count
+= mono_class_num_methods (ic
);
2426 g_ptr_array_free (ifaces
, TRUE
);
2430 extra_interface_vtsize
+= method_count
* sizeof (gpointer
);
2431 if (m_class_get_max_interface_id (iclass
) > max_interface_id
) max_interface_id
= m_class_get_max_interface_id (iclass
);
2434 imt_table_bytes
= sizeof (gpointer
) * MONO_IMT_SIZE
;
2435 if (use_interpreter
)
2436 imt_table_bytes
*= 2;
2437 UnlockedIncrement (&mono_stats
.imt_number_of_tables
);
2438 UnlockedAdd (&mono_stats
.imt_tables_size
, imt_table_bytes
);
2440 vtsize
= imt_table_bytes
+ MONO_SIZEOF_VTABLE
+ m_class_get_vtable_size (klass
) * sizeof (gpointer
);
2442 UnlockedAdd (&mono_stats
.class_vtable_size
, vtsize
+ extra_interface_vtsize
);
2444 interface_offsets
= alloc_vtable (domain
, vtsize
+ extra_interface_vtsize
, imt_table_bytes
);
2445 pvt
= (MonoVTable
*) ((char*)interface_offsets
+ imt_table_bytes
);
2446 g_assert (!((gsize
)pvt
& 7));
2448 if (use_interpreter
)
2449 interface_offsets
= (gpointer
*)((char*)interface_offsets
+ imt_table_bytes
/ 2);
2451 memcpy (pvt
, vt
, MONO_SIZEOF_VTABLE
+ m_class_get_vtable_size (klass
) * sizeof (gpointer
));
2453 pvt
->interp_vtable
= NULL
;
2454 pvt
->klass
= mono_defaults
.transparent_proxy_class
;
2456 MONO_PROFILER_RAISE (vtable_loading
, (pvt
));
2458 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2459 pvt
->gc_descr
= m_class_get_gc_descr (mono_defaults
.transparent_proxy_class
);
2461 if (mono_remote_class_is_interface_proxy (remote_class
)) {
2462 /* If it's a transparent proxy for an interface, set the
2463 * MonoVTable:type to the interface type, not the placeholder
2464 * MarshalByRefObject class. This is used when mini JITs calls
2465 * to Object.GetType ()
2467 MonoType
*itf_proxy_type
= m_class_get_byval_arg (remote_class
->interfaces
[0]);
2468 pvt
->type
= mono_type_get_object_checked (domain
, itf_proxy_type
, error
);
2469 goto_if_nok (error
, failure
);
2472 /* initialize vtable */
2473 mono_class_setup_vtable (klass
);
2474 MonoMethod
**klass_vtable
;
2475 klass_vtable
= m_class_get_vtable (klass
);
2476 for (i
= 0; i
< m_class_get_vtable_size (klass
); ++i
) {
2479 if ((cm
= klass_vtable
[i
])) {
2480 pvt
->vtable
[i
] = create_remoting_trampoline (domain
, cm
, target_type
, error
);
2481 goto_if_nok (error
, failure
);
2483 pvt
->vtable
[i
] = NULL
;
2486 if (mono_class_is_abstract (klass
)) {
2487 /* create trampolines for abstract methods */
2488 for (k
= klass
; k
; k
= m_class_get_parent (k
)) {
2490 gpointer iter
= NULL
;
2491 while ((m
= mono_class_get_methods (k
, &iter
)))
2492 if (!pvt
->vtable
[m
->slot
]) {
2493 pvt
->vtable
[m
->slot
] = create_remoting_trampoline (domain
, m
, target_type
, error
);
2494 goto_if_nok (error
, failure
);
2499 pvt
->max_interface_id
= max_interface_id
;
2500 bsize
= sizeof (guint8
) * (max_interface_id
/8 + 1 );
2501 #ifdef COMPRESSED_INTERFACE_BITMAP
2502 bitmap
= (uint8_t *)g_malloc0 (bsize
);
2504 bitmap
= (uint8_t *)mono_domain_alloc0 (domain
, bsize
);
2507 for (i
= 0; i
< m_class_get_interface_offsets_count (klass
); ++i
) {
2508 int interface_id
= m_class_get_interface_id (m_class_get_interfaces_packed (klass
) [i
]);
2509 bitmap
[interface_id
>> 3] |= (1 << (interface_id
& 7));
2512 if (extra_interfaces
) {
2513 int slot
= m_class_get_vtable_size (klass
);
2519 /* Create trampolines for the methods of the interfaces */
2520 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
2521 interf
= (MonoClass
*)list_item
->data
;
2523 guint32 interf_interface_id
= m_class_get_interface_id (interf
);
2524 bitmap
[interf_interface_id
>> 3] |= (1 << (interf_interface_id
& 7));
2528 while ((cm
= mono_class_get_methods (interf
, &iter
))) {
2529 pvt
->vtable
[slot
+ j
++] = create_remoting_trampoline (domain
, cm
, target_type
, error
);
2530 goto_if_nok (error
, failure
);
2533 slot
+= mono_class_num_methods (interf
);
2537 /* Now that the vtable is full, we can actually fill up the IMT */
2538 build_imt (klass
, pvt
, domain
, interface_offsets
, extra_interfaces
);
2539 if (extra_interfaces
) {
2540 g_slist_free (extra_interfaces
);
2543 #ifdef COMPRESSED_INTERFACE_BITMAP
2544 bcsize
= mono_compress_bitmap (NULL
, bitmap
, bsize
);
2545 pvt
->interface_bitmap
= mono_domain_alloc0 (domain
, bcsize
);
2546 mono_compress_bitmap (pvt
->interface_bitmap
, bitmap
, bsize
);
2549 pvt
->interface_bitmap
= bitmap
;
2551 MONO_PROFILER_RAISE (vtable_loaded
, (pvt
));
2554 if (extra_interfaces
)
2555 g_slist_free (extra_interfaces
);
2556 #ifdef COMPRESSED_INTERFACE_BITMAP
2559 MONO_PROFILER_RAISE (vtable_failed
, (pvt
));
2563 #endif /* DISABLE_REMOTING */
2566 * mono_class_field_is_special_static:
2567 * \returns whether \p field is a thread/context static field.
2570 mono_class_field_is_special_static (MonoClassField
*field
)
2572 MONO_REQ_GC_NEUTRAL_MODE
2574 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2576 if (mono_field_is_deleted (field
))
2578 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
2579 if (field_is_special_static (field
->parent
, field
) != SPECIAL_STATIC_NONE
)
2586 * mono_class_field_get_special_static_type:
2587 * \param field The \c MonoClassField describing the field.
2588 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2589 * \c SPECIAL_STATIC_NONE otherwise.
2592 mono_class_field_get_special_static_type (MonoClassField
*field
)
2594 MONO_REQ_GC_NEUTRAL_MODE
2596 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2597 return SPECIAL_STATIC_NONE
;
2598 if (mono_field_is_deleted (field
))
2599 return SPECIAL_STATIC_NONE
;
2600 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
2601 return field_is_special_static (field
->parent
, field
);
2602 return SPECIAL_STATIC_NONE
;
2606 * mono_class_has_special_static_fields:
2607 * \returns whether \p klass has any thread/context static fields.
2610 mono_class_has_special_static_fields (MonoClass
*klass
)
2612 MONO_REQ_GC_NEUTRAL_MODE
2614 MonoClassField
*field
;
2618 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
2619 g_assert (field
->parent
== klass
);
2620 if (mono_class_field_is_special_static (field
))
2627 #ifndef DISABLE_REMOTING
2629 * create_remote_class_key:
2630 * Creates an array of pointers that can be used as a hash key for a remote class.
2631 * The first element of the array is the number of pointers.
2634 create_remote_class_key (MonoRemoteClass
*remote_class
, MonoClass
*extra_class
)
2636 MONO_REQ_GC_NEUTRAL_MODE
;
2641 if (remote_class
== NULL
) {
2642 if (mono_class_is_interface (extra_class
)) {
2643 key
= (void **)g_malloc (sizeof(gpointer
) * 3);
2644 key
[0] = GINT_TO_POINTER (2);
2645 key
[1] = mono_defaults
.marshalbyrefobject_class
;
2646 key
[2] = extra_class
;
2648 key
= (void **)g_malloc (sizeof(gpointer
) * 2);
2649 key
[0] = GINT_TO_POINTER (1);
2650 key
[1] = extra_class
;
2653 if (extra_class
!= NULL
&& mono_class_is_interface (extra_class
)) {
2654 key
= (void **)g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 3));
2655 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 2);
2656 key
[1] = remote_class
->proxy_class
;
2658 // Keep the list of interfaces sorted
2659 for (i
= 0, j
= 2; i
< remote_class
->interface_count
; i
++, j
++) {
2660 if (extra_class
&& remote_class
->interfaces
[i
] > extra_class
) {
2661 key
[j
++] = extra_class
;
2664 key
[j
] = remote_class
->interfaces
[i
];
2667 key
[j
] = extra_class
;
2669 // Replace the old class. The interface list is the same
2670 key
= (void **)g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 2));
2671 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 1);
2672 key
[1] = extra_class
!= NULL
? extra_class
: remote_class
->proxy_class
;
2673 for (i
= 0; i
< remote_class
->interface_count
; i
++)
2674 key
[2 + i
] = remote_class
->interfaces
[i
];
2682 * copy_remote_class_key:
2684 * Make a copy of KEY in the domain and return the copy.
2687 copy_remote_class_key (MonoDomain
*domain
, gpointer
*key
)
2689 MONO_REQ_GC_NEUTRAL_MODE
2691 int key_size
= (GPOINTER_TO_UINT (key
[0]) + 1) * sizeof (gpointer
);
2692 gpointer
*mp_key
= (gpointer
*)mono_domain_alloc (domain
, key_size
);
2694 memcpy (mp_key
, key
, key_size
);
2700 * mono_remote_class:
2701 * \param domain the application domain
2702 * \param class_name name of the remote class
2703 * \param error set on error
2704 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2705 * On failure returns NULL and sets \p error
2708 mono_remote_class (MonoDomain
*domain
, MonoStringHandle class_name
, MonoClass
*proxy_class
, MonoError
*error
)
2710 MONO_REQ_GC_UNSAFE_MODE
;
2712 MonoRemoteClass
*rc
;
2713 gpointer
* key
, *mp_key
;
2718 key
= create_remote_class_key (NULL
, proxy_class
);
2720 mono_domain_lock (domain
);
2721 rc
= (MonoRemoteClass
*)g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2725 mono_domain_unlock (domain
);
2729 name
= mono_string_to_utf8_mp (domain
->mp
, MONO_HANDLE_RAW (class_name
), error
);
2730 if (!is_ok (error
)) {
2732 mono_domain_unlock (domain
);
2736 mp_key
= copy_remote_class_key (domain
, key
);
2740 if (mono_class_is_interface (proxy_class
)) {
2741 /* If we need to proxy an interface, we use this stylized
2742 * representation (interface_count >= 1, proxy_class is
2743 * MarshalByRefObject). The code in
2744 * mono_remote_class_is_interface_proxy () depends on being
2745 * able to detect that we're doing this, so if this
2746 * representation changes, change GetType, too. */
2747 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*));
2748 rc
->interface_count
= 1;
2749 rc
->interfaces
[0] = proxy_class
;
2750 rc
->proxy_class
= mono_defaults
.marshalbyrefobject_class
;
2752 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
);
2753 rc
->interface_count
= 0;
2754 rc
->proxy_class
= proxy_class
;
2757 rc
->default_vtable
= NULL
;
2758 rc
->xdomain_vtable
= NULL
;
2759 rc
->proxy_class_name
= name
;
2760 #ifndef DISABLE_PERFCOUNTERS
2761 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, mono_string_length_internal (MONO_HANDLE_RAW (class_name
)) + 1);
2764 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2766 mono_domain_unlock (domain
);
2771 * clone_remote_class:
2772 * Creates a copy of the remote_class, adding the provided class or interface
2774 static MonoRemoteClass
*
2775 clone_remote_class (MonoDomain
*domain
, MonoRemoteClass
* remote_class
, MonoClass
*extra_class
)
2777 MONO_REQ_GC_NEUTRAL_MODE
;
2779 MonoRemoteClass
*rc
;
2780 gpointer
* key
, *mp_key
;
2782 key
= create_remote_class_key (remote_class
, extra_class
);
2783 rc
= (MonoRemoteClass
*)g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2789 mp_key
= copy_remote_class_key (domain
, key
);
2793 if (mono_class_is_interface (extra_class
)) {
2795 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * (remote_class
->interface_count
+ 1));
2796 rc
->proxy_class
= remote_class
->proxy_class
;
2797 rc
->interface_count
= remote_class
->interface_count
+ 1;
2799 // Keep the list of interfaces sorted, since the hash key of
2800 // the remote class depends on this
2801 for (i
= 0, j
= 0; i
< remote_class
->interface_count
; i
++, j
++) {
2802 if (remote_class
->interfaces
[i
] > extra_class
&& i
== j
)
2803 rc
->interfaces
[j
++] = extra_class
;
2804 rc
->interfaces
[j
] = remote_class
->interfaces
[i
];
2807 rc
->interfaces
[j
] = extra_class
;
2809 // Replace the old class. The interface array is the same
2810 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * remote_class
->interface_count
);
2811 rc
->proxy_class
= extra_class
;
2812 rc
->interface_count
= remote_class
->interface_count
;
2813 if (rc
->interface_count
> 0)
2814 memcpy (rc
->interfaces
, remote_class
->interfaces
, rc
->interface_count
* sizeof (MonoClass
*));
2817 rc
->default_vtable
= NULL
;
2818 rc
->xdomain_vtable
= NULL
;
2819 rc
->proxy_class_name
= remote_class
->proxy_class_name
;
2821 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2827 mono_remote_class_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRealProxyHandle rp
, MonoError
*error
)
2829 MONO_REQ_GC_UNSAFE_MODE
;
2831 gpointer result
= NULL
;
2834 mono_loader_lock (); /*FIXME mono_class_from_mono_type_internal and mono_class_proxy_vtable take it*/
2835 mono_domain_lock (domain
);
2836 gint32 target_domain_id
= MONO_HANDLE_GETVAL (rp
, target_domain_id
);
2837 if (target_domain_id
!= -1) {
2838 if (remote_class
->xdomain_vtable
== NULL
)
2839 remote_class
->xdomain_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_APPDOMAIN
, error
);
2840 goto_if_nok (error
, leave
);
2841 result
= remote_class
->xdomain_vtable
;
2844 if (remote_class
->default_vtable
== NULL
) {
2845 MonoReflectionTypeHandle reftype
= MONO_HANDLE_NEW (MonoReflectionType
, NULL
);
2846 MONO_HANDLE_GET (reftype
, rp
, class_to_proxy
);
2848 MonoType
*type
= MONO_HANDLE_GETVAL (reftype
, type
);
2849 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
2851 gboolean target_is_com
= FALSE
;
2852 if (mono_class_is_com_object (klass
) || (mono_class_get_com_object_class () && klass
== mono_class_get_com_object_class ())) {
2853 MonoVTable
*klass_vtable
= mono_class_vtable_checked (mono_domain_get (), klass
, error
);
2854 goto_if_nok (error
, leave
);
2855 if (!mono_vtable_is_remote (klass_vtable
))
2856 target_is_com
= TRUE
;
2859 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_COMINTEROP
, error
);
2862 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_UNKNOWN
, error
);
2863 /* N.B. both branches of the if modify error */
2864 goto_if_nok (error
, leave
);
2868 result
= remote_class
->default_vtable
;
2870 mono_domain_unlock (domain
);
2871 mono_loader_unlock ();
2876 * mono_upgrade_remote_class:
2877 * \param domain the application domain
2878 * \param tproxy the proxy whose remote class has to be upgraded.
2879 * \param klass class to which the remote class can be casted.
2880 * \param error set on error
2881 * Updates the vtable of the remote class by adding the necessary method slots
2882 * and interface offsets so it can be safely casted to klass. klass can be a
2883 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2886 mono_upgrade_remote_class (MonoDomain
*domain
, MonoObjectHandle proxy_object
, MonoClass
*klass
, MonoError
*error
)
2888 MONO_REQ_GC_UNSAFE_MODE
;
2892 MonoTransparentProxyHandle tproxy
= MONO_HANDLE_CAST (MonoTransparentProxy
, proxy_object
);
2893 MonoRemoteClass
*remote_class
= MONO_HANDLE_GETVAL (tproxy
, remote_class
);
2895 gboolean redo_vtable
;
2896 if (mono_class_is_interface (klass
)) {
2899 for (i
= 0; i
< remote_class
->interface_count
&& redo_vtable
; i
++)
2900 if (remote_class
->interfaces
[i
] == klass
)
2901 redo_vtable
= FALSE
;
2904 redo_vtable
= (remote_class
->proxy_class
!= klass
);
2907 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2908 mono_domain_lock (domain
);
2910 MonoRemoteClass
*fresh_remote_class
= clone_remote_class (domain
, remote_class
, klass
);
2911 MONO_HANDLE_SETVAL (tproxy
, remote_class
, MonoRemoteClass
*, fresh_remote_class
);
2912 MonoRealProxyHandle real_proxy
= MONO_HANDLE_NEW (MonoRealProxy
, NULL
);
2913 MONO_HANDLE_GET (real_proxy
, tproxy
, rp
);
2914 MONO_HANDLE_SETVAL (proxy_object
, vtable
, MonoVTable
*, (MonoVTable
*)mono_remote_class_vtable (domain
, fresh_remote_class
, real_proxy
, error
));
2915 goto_if_nok (error
, leave
);
2919 mono_domain_unlock (domain
);
2920 mono_loader_unlock ();
2921 return is_ok (error
);
2923 #endif /* DISABLE_REMOTING */
2926 mono_object_get_virtual_method_internal (MonoObject
*obj_raw
, MonoMethod
*method
)
2928 HANDLE_FUNCTION_ENTER ();
2931 MONO_HANDLE_DCL (MonoObject
, obj
);
2932 result
= mono_object_handle_get_virtual_method (obj
, method
, error
);
2933 mono_error_assert_ok (error
);
2934 HANDLE_FUNCTION_RETURN_VAL (result
);
2938 * mono_object_get_virtual_method:
2939 * \param obj object to operate on.
2940 * \param method method
2941 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2942 * the instance of a callvirt of \p method.
2945 mono_object_get_virtual_method (MonoObject
*obj
, MonoMethod
*method
)
2947 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoMethod
*, mono_object_get_virtual_method_internal (obj
, method
));
2951 * mono_object_handle_get_virtual_method:
2952 * \param obj object to operate on.
2953 * \param method method
2954 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2955 * the instance of a callvirt of \p method.
2958 mono_object_handle_get_virtual_method (MonoObjectHandle obj
, MonoMethod
*method
, MonoError
*error
)
2962 gboolean is_proxy
= FALSE
;
2963 MonoClass
*klass
= mono_handle_class (obj
);
2964 if (mono_class_is_transparent_proxy (klass
)) {
2965 MonoRemoteClass
*remote_class
= MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy
, obj
), remote_class
);
2966 klass
= remote_class
->proxy_class
;
2969 return mono_class_get_virtual_method (klass
, method
, is_proxy
, error
);
2973 mono_class_get_virtual_method (MonoClass
*klass
, MonoMethod
*method
, gboolean is_proxy
, MonoError
*error
)
2975 MONO_REQ_GC_NEUTRAL_MODE
;
2978 if (!is_proxy
&& ((method
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)))
2981 mono_class_setup_vtable (klass
);
2982 MonoMethod
**vtable
= m_class_get_vtable (klass
);
2984 if (method
->slot
== -1) {
2985 /* method->slot might not be set for instances of generic methods */
2986 if (method
->is_inflated
) {
2987 g_assert (((MonoMethodInflated
*)method
)->declaring
->slot
!= -1);
2988 method
->slot
= ((MonoMethodInflated
*)method
)->declaring
->slot
;
2991 g_assert_not_reached ();
2995 MonoMethod
*res
= NULL
;
2996 /* check method->slot is a valid index: perform isinstance? */
2997 if (method
->slot
!= -1) {
2998 if (mono_class_is_interface (method
->klass
)) {
3000 gboolean variance_used
= FALSE
;
3001 int iface_offset
= mono_class_interface_offset_with_variance (klass
, method
->klass
, &variance_used
);
3002 g_assert (iface_offset
> 0);
3003 res
= vtable
[iface_offset
+ method
->slot
];
3006 res
= vtable
[method
->slot
];
3010 #ifndef DISABLE_REMOTING
3012 /* It may be an interface, abstract class method or generic method */
3013 if (!res
|| mono_method_signature_internal (res
)->generic_param_count
)
3016 /* generic methods demand invoke_with_check */
3017 if (mono_method_signature_internal (res
)->generic_param_count
)
3018 res
= mono_marshal_get_remoting_invoke_with_check (res
, error
);
3021 if (klass
== mono_class_get_com_object_class () || mono_class_is_com_object (klass
))
3022 res
= mono_cominterop_get_invoke (res
);
3025 res
= mono_marshal_get_remoting_invoke (res
, error
);
3030 if (method
->is_inflated
) {
3031 /* Have to inflate the result */
3032 res
= mono_class_inflate_generic_method_checked (res
, &((MonoMethodInflated
*)method
)->context
, error
);
3040 do_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
3042 MONO_REQ_GC_UNSAFE_MODE
;
3044 MonoObject
*result
= NULL
;
3046 g_assert (callbacks
.runtime_invoke
);
3050 MONO_PROFILER_RAISE (method_begin_invoke
, (method
));
3052 result
= callbacks
.runtime_invoke (method
, obj
, params
, exc
, error
);
3054 MONO_PROFILER_RAISE (method_end_invoke
, (method
));
3063 * mono_runtime_invoke:
3064 * \param method method to invoke
3065 * \param obj object instance
3066 * \param params arguments to the method
3067 * \param exc exception information.
3068 * Invokes the method represented by \p method on the object \p obj.
3069 * \p obj is the \c this pointer, it should be NULL for static
3070 * methods, a \c MonoObject* for object instances and a pointer to
3071 * the value type for value types.
3073 * The params array contains the arguments to the method with the
3074 * same convention: \c MonoObject* pointers for object instances and
3075 * pointers to the value type otherwise.
3077 * From unmanaged code you'll usually use the
3078 * \c mono_runtime_invoke variant.
3080 * Note that this function doesn't handle virtual methods for
3081 * you, it will exec the exact method you pass: we still need to
3082 * expose a function to lookup the derived class implementation
3083 * of a virtual method (there are examples of this in the code,
3086 * You can pass NULL as the \p exc argument if you don't want to
3087 * catch exceptions, otherwise, \c *exc will be set to the exception
3088 * thrown, if any. if an exception is thrown, you can't use the
3089 * \c MonoObject* result from the function.
3091 * If the method returns a value type, it is boxed in an object
3095 mono_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
3098 MONO_ENTER_GC_UNSAFE
;
3101 res
= mono_runtime_try_invoke (method
, obj
, params
, exc
, error
);
3102 if (*exc
== NULL
&& !is_ok(error
)) {
3103 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3105 mono_error_cleanup (error
);
3107 res
= mono_runtime_invoke_checked (method
, obj
, params
, error
);
3108 mono_error_raise_exception_deprecated (error
); /* OK to throw, external only without a good alternative */
3110 MONO_EXIT_GC_UNSAFE
;
3115 * mono_runtime_try_invoke:
3116 * \param method method to invoke
3117 * \param obj object instance
3118 * \param params arguments to the method
3119 * \param exc exception information.
3120 * \param error set on error
3121 * Invokes the method represented by \p method on the object \p obj.
3123 * \p obj is the \c this pointer, it should be NULL for static
3124 * methods, a \c MonoObject* for object instances and a pointer to
3125 * the value type for value types.
3127 * The params array contains the arguments to the method with the
3128 * same convention: \c MonoObject* pointers for object instances and
3129 * pointers to the value type otherwise.
3131 * From unmanaged code you'll usually use the
3132 * mono_runtime_invoke() variant.
3134 * Note that this function doesn't handle virtual methods for
3135 * you, it will exec the exact method you pass: we still need to
3136 * expose a function to lookup the derived class implementation
3137 * of a virtual method (there are examples of this in the code,
3140 * For this function, you must not pass NULL as the \p exc argument if
3141 * you don't want to catch exceptions, use
3142 * mono_runtime_invoke_checked(). If an exception is thrown, you
3143 * can't use the \c MonoObject* result from the function.
3145 * If this method cannot be invoked, \p error will be set and \p exc and
3146 * the return value must not be used.
3148 * If the method returns a value type, it is boxed in an object
3152 mono_runtime_try_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
* error
)
3154 MONO_REQ_GC_UNSAFE_MODE
;
3156 g_assert (exc
!= NULL
);
3158 if (mono_runtime_get_no_exec ())
3159 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method
, TRUE
));
3161 return do_runtime_invoke (method
, obj
, params
, exc
, error
);
3165 mono_runtime_try_invoke_handle (MonoMethod
*method
, MonoObjectHandle obj
, void **params
, MonoError
* error
)
3167 // FIXME? typing of params
3168 MonoException
*exc
= NULL
;
3169 MonoObject
*obj_raw
= mono_runtime_try_invoke (method
, MONO_HANDLE_RAW (obj
), params
, (MonoObject
**)&exc
, error
);
3171 if (exc
&& is_ok (error
))
3172 mono_error_set_exception_instance (error
, exc
);
3174 return MONO_HANDLE_NEW (MonoObject
, obj_raw
);
3178 * mono_runtime_invoke_checked:
3179 * \param method method to invoke
3180 * \param obj object instance
3181 * \param params arguments to the method
3182 * \param error set on error
3183 * Invokes the method represented by \p method on the object \p obj.
3185 * \p obj is the \c this pointer, it should be NULL for static
3186 * methods, a \c MonoObject* for object instances and a pointer to
3187 * the value type for value types.
3189 * The \p params array contains the arguments to the method with the
3190 * same convention: \c MonoObject* pointers for object instances and
3191 * pointers to the value type otherwise.
3193 * From unmanaged code you'll usually use the
3194 * mono_runtime_invoke() variant.
3196 * Note that this function doesn't handle virtual methods for
3197 * you, it will exec the exact method you pass: we still need to
3198 * expose a function to lookup the derived class implementation
3199 * of a virtual method (there are examples of this in the code,
3202 * If an exception is thrown, you can't use the \c MonoObject* result
3203 * from the function.
3205 * If this method cannot be invoked, \p error will be set. If the
3206 * method throws an exception (and we're in coop mode) the exception
3207 * will be set in \p error.
3209 * If the method returns a value type, it is boxed in an object
3213 mono_runtime_invoke_checked (MonoMethod
*method
, void *obj
, void **params
, MonoError
* error
)
3215 MONO_REQ_GC_UNSAFE_MODE
;
3217 if (mono_runtime_get_no_exec ())
3218 g_error ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method
, TRUE
));
3220 return do_runtime_invoke (method
, obj
, params
, NULL
, error
);
3224 mono_runtime_invoke_handle (MonoMethod
*method
, MonoObjectHandle obj
, void **params
, MonoError
* error
)
3226 return MONO_HANDLE_NEW (MonoObject
, mono_runtime_invoke_checked (method
, MONO_HANDLE_RAW (obj
), params
, error
));
3230 mono_runtime_invoke_handle_void (MonoMethod
*method
, MonoObjectHandle obj
, void **params
, MonoError
* error
)
3232 mono_runtime_invoke_checked (method
, MONO_HANDLE_RAW (obj
), params
, error
);
3236 * mono_method_get_unmanaged_thunk:
3237 * \param method method to generate a thunk for.
3239 * Returns an \c unmanaged->managed thunk that can be used to call
3240 * a managed method directly from C.
3242 * The thunk's C signature closely matches the managed signature:
3244 * C#: <code>public bool Equals (object obj);</code>
3246 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3248 * The 1st (<code>this</code>) parameter must not be used with static methods:
3250 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3252 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3254 * The last argument must be a non-null \c MonoException* pointer.
3255 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3256 * exception has been thrown in managed code. Otherwise it will point
3257 * to the \c MonoException* caught by the thunk. In this case, the result of
3258 * the thunk is undefined:
3261 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3263 * MonoException *ex = NULL;
3265 * Equals func = mono_method_get_unmanaged_thunk (method);
3267 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3271 * // handle exception
3276 * The calling convention of the thunk matches the platform's default
3277 * convention. This means that under Windows, C declarations must
3278 * contain the \c __stdcall attribute:
3280 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3284 * Value type arguments and return values are treated as they were objects:
3286 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3287 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3289 * Arguments must be properly boxed upon trunk's invocation, while return
3290 * values must be unboxed.
3293 mono_method_get_unmanaged_thunk (MonoMethod
*method
)
3295 MONO_REQ_GC_NEUTRAL_MODE
;
3296 MONO_REQ_API_ENTRYPOINT
;
3301 MONO_ENTER_GC_UNSAFE
;
3302 method
= mono_marshal_get_thunk_invoke_wrapper (method
);
3303 res
= mono_compile_method_checked (method
, error
);
3304 mono_error_cleanup (error
);
3305 MONO_EXIT_GC_UNSAFE
;
3311 mono_copy_value (MonoType
*type
, void *dest
, void *value
, int deref_pointer
)
3313 MONO_REQ_GC_UNSAFE_MODE
;
3317 /* object fields cannot be byref, so we don't need a
3319 gpointer
*p
= (gpointer
*)dest
;
3326 case MONO_TYPE_BOOLEAN
:
3328 case MONO_TYPE_U1
: {
3329 guint8
*p
= (guint8
*)dest
;
3330 *p
= value
? *(guint8
*)value
: 0;
3335 case MONO_TYPE_CHAR
: {
3336 guint16
*p
= (guint16
*)dest
;
3337 *p
= value
? *(guint16
*)value
: 0;
3340 #if SIZEOF_VOID_P == 4
3345 case MONO_TYPE_U4
: {
3346 gint32
*p
= (gint32
*)dest
;
3347 *p
= value
? *(gint32
*)value
: 0;
3350 #if SIZEOF_VOID_P == 8
3355 case MONO_TYPE_U8
: {
3356 gint64
*p
= (gint64
*)dest
;
3357 *p
= value
? *(gint64
*)value
: 0;
3360 case MONO_TYPE_R4
: {
3361 float *p
= (float*)dest
;
3362 *p
= value
? *(float*)value
: 0;
3365 case MONO_TYPE_R8
: {
3366 double *p
= (double*)dest
;
3367 *p
= value
? *(double*)value
: 0;
3370 case MONO_TYPE_STRING
:
3371 case MONO_TYPE_SZARRAY
:
3372 case MONO_TYPE_CLASS
:
3373 case MONO_TYPE_OBJECT
:
3374 case MONO_TYPE_ARRAY
:
3375 mono_gc_wbarrier_generic_store_internal (dest
, deref_pointer
? *(MonoObject
**)value
: (MonoObject
*)value
);
3377 case MONO_TYPE_FNPTR
:
3378 case MONO_TYPE_PTR
: {
3379 gpointer
*p
= (gpointer
*)dest
;
3380 *p
= deref_pointer
? *(gpointer
*)value
: value
;
3383 case MONO_TYPE_VALUETYPE
:
3384 /* note that 't' and 'type->type' can be different */
3385 if (type
->type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (type
->data
.klass
)) {
3386 t
= mono_class_enum_basetype_internal (type
->data
.klass
)->type
;
3389 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
3390 int size
= mono_class_value_size (klass
, NULL
);
3392 mono_gc_bzero_atomic (dest
, size
);
3394 mono_gc_wbarrier_value_copy_internal (dest
, value
, 1, klass
);
3397 case MONO_TYPE_GENERICINST
:
3398 t
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
)->type
;
3401 g_error ("got type %x", type
->type
);
3406 mono_field_set_value_internal (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3410 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3413 dest
= (char*)obj
+ field
->offset
;
3415 mono_copy_value (field
->type
, dest
, value
, value
&& field
->type
->type
== MONO_TYPE_PTR
);
3417 mono_copy_value (field
->type
, dest
, value
, FALSE
);
3422 * mono_field_set_value:
3423 * \param obj Instance object
3424 * \param field \c MonoClassField describing the field to set
3425 * \param value The value to be set
3427 * Sets the value of the field described by \p field in the object instance \p obj
3428 * to the value passed in \p value. This method should only be used for instance
3429 * fields. For static fields, use \c mono_field_static_set_value.
3431 * The value must be in the native format of the field type.
3434 mono_field_set_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3436 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_set_value_internal (obj
, field
, value
));
3440 mono_field_static_set_value_internal (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3444 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) == 0)
3446 /* you cant set a constant! */
3447 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
3450 if (field
->offset
== -1) {
3451 /* Special static */
3454 mono_domain_lock (vt
->domain
);
3455 addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3456 mono_domain_unlock (vt
->domain
);
3457 dest
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
3459 dest
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3461 mono_copy_value (field
->type
, dest
, value
, FALSE
);
3465 * mono_field_static_set_value:
3466 * \param field \c MonoClassField describing the field to set
3467 * \param value The value to be set
3468 * Sets the value of the static field described by \p field
3469 * to the value passed in \p value.
3470 * The value must be in the native format of the field type.
3473 mono_field_static_set_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3475 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_static_set_value_internal (vt
, field
, value
));
3479 * mono_vtable_get_static_field_data:
3481 * Internal use function: return a pointer to the memory holding the static fields
3482 * for a class or NULL if there are no static fields.
3483 * This is exported only for use by the debugger.
3486 mono_vtable_get_static_field_data (MonoVTable
*vt
)
3488 MONO_REQ_GC_NEUTRAL_MODE
3490 if (!vt
->has_static_fields
)
3492 return vt
->vtable
[m_class_get_vtable_size (vt
->klass
)];
3496 mono_field_get_addr (MonoObject
*obj
, MonoVTable
*vt
, MonoClassField
*field
)
3498 MONO_REQ_GC_UNSAFE_MODE
;
3502 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3503 if (field
->offset
== -1) {
3504 /* Special static */
3507 mono_domain_lock (vt
->domain
);
3508 addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3509 mono_domain_unlock (vt
->domain
);
3510 src
= (guint8
*)mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
3512 src
= (guint8
*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3515 src
= (guint8
*)obj
+ field
->offset
;
3522 * mono_field_get_value:
3523 * \param obj Object instance
3524 * \param field \c MonoClassField describing the field to fetch information from
3525 * \param value pointer to the location where the value will be stored
3526 * Use this routine to get the value of the field \p field in the object
3529 * The pointer provided by value must be of the field type, for reference
3530 * types this is a \c MonoObject*, for value types its the actual pointer to
3538 * mono_field_get_value (obj, int_field, &i);
3542 mono_field_get_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3544 MONO_EXTERNAL_ONLY_GC_UNSAFE_VOID (mono_field_get_value_internal (obj
, field
, value
));
3548 mono_field_get_value_internal (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3550 MONO_REQ_GC_UNSAFE_MODE
;
3556 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
));
3558 src
= (char*)obj
+ field
->offset
;
3559 mono_copy_value (field
->type
, value
, src
, TRUE
);
3563 * mono_field_get_value_object:
3564 * \param domain domain where the object will be created (if boxing)
3565 * \param field \c MonoClassField describing the field to fetch information from
3566 * \param obj The object instance for the field.
3567 * \returns a new \c MonoObject with the value from the given field. If the
3568 * field represents a value type, the value is boxed.
3571 mono_field_get_value_object (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
)
3574 MONO_ENTER_GC_UNSAFE
;
3576 result
= mono_field_get_value_object_checked (domain
, field
, obj
, error
);
3577 mono_error_assert_ok (error
);
3578 MONO_EXIT_GC_UNSAFE
;
3583 * mono_static_field_get_value_handle:
3584 * \param domain domain where the object will be created (if boxing)
3585 * \param field \c MonoClassField describing the field to fetch information from
3586 * \param obj The object instance for the field.
3587 * \returns a new \c MonoObject with the value from the given field. If the
3588 * field represents a value type, the value is boxed.
3591 mono_static_field_get_value_handle (MonoDomain
*domain
, MonoClassField
*field
, MonoError
*error
)
3594 HANDLE_FUNCTION_ENTER ();
3595 HANDLE_FUNCTION_RETURN_REF (MonoObject
, MONO_HANDLE_NEW (MonoObject
, mono_field_get_value_object_checked (domain
, field
, NULL
, error
)));
3599 * mono_field_get_value_object_checked:
3600 * \param domain domain where the object will be created (if boxing)
3601 * \param field \c MonoClassField describing the field to fetch information from
3602 * \param obj The object instance for the field.
3603 * \param error Set on error.
3604 * \returns a new \c MonoObject with the value from the given field. If the
3605 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3608 mono_field_get_value_object_checked (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
, MonoError
*error
)
3612 HANDLE_FUNCTION_ENTER ();
3614 MONO_REQ_GC_UNSAFE_MODE
;
3618 MonoObject
*o
= NULL
;
3620 MonoVTable
*vtable
= NULL
;
3622 gboolean is_static
= FALSE
;
3623 gboolean is_ref
= FALSE
;
3624 gboolean is_literal
= FALSE
;
3625 gboolean is_ptr
= FALSE
;
3627 MonoStringHandle string_handle
= MONO_HANDLE_NEW (MonoString
, NULL
);
3629 MonoType
*type
= mono_field_get_type_checked (field
, error
);
3631 goto_if_nok (error
, return_null
);
3633 switch (type
->type
) {
3634 case MONO_TYPE_STRING
:
3635 case MONO_TYPE_OBJECT
:
3636 case MONO_TYPE_CLASS
:
3637 case MONO_TYPE_ARRAY
:
3638 case MONO_TYPE_SZARRAY
:
3643 case MONO_TYPE_BOOLEAN
:
3646 case MONO_TYPE_CHAR
:
3655 case MONO_TYPE_VALUETYPE
:
3656 is_ref
= type
->byref
;
3658 case MONO_TYPE_GENERICINST
:
3659 is_ref
= !mono_type_generic_inst_is_valuetype (type
);
3665 g_error ("type 0x%x not handled in "
3666 "mono_field_get_value_object", type
->type
);
3670 if (type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
3673 if (type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3677 vtable
= mono_class_vtable_checked (domain
, field
->parent
, error
);
3678 goto_if_nok (error
, return_null
);
3680 if (!vtable
->initialized
) {
3681 mono_runtime_class_init_full (vtable
, error
);
3682 goto_if_nok (error
, return_null
);
3691 get_default_field_value (domain
, field
, &o
, string_handle
, error
);
3692 goto_if_nok (error
, return_null
);
3693 } else if (is_static
) {
3694 mono_field_static_get_value_checked (vtable
, field
, &o
, string_handle
, error
);
3695 goto_if_nok (error
, return_null
);
3697 mono_field_get_value_internal (obj
, field
, &o
);
3706 MONO_STATIC_POINTER_INIT (MonoMethod
, m
)
3708 MonoClass
*ptr_klass
= mono_class_get_pointer_class ();
3709 m
= mono_class_get_method_from_name_checked (ptr_klass
, "Box", 2, METHOD_ATTRIBUTE_STATIC
, error
);
3710 goto_if_nok (error
, return_null
);
3713 MONO_STATIC_POINTER_INIT_END (MonoMethod
, m
)
3717 get_default_field_value (domain
, field
, v
, string_handle
, error
);
3718 goto_if_nok (error
, return_null
);
3719 } else if (is_static
) {
3720 mono_field_static_get_value_checked (vtable
, field
, v
, string_handle
, error
);
3721 goto_if_nok (error
, return_null
);
3723 mono_field_get_value_internal (obj
, field
, v
);
3729 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3730 args
[0] = ptr
? *ptr
: NULL
;
3732 args
[1] = mono_type_get_object_checked (mono_domain_get (), type
, error
);
3733 goto_if_nok (error
, return_null
);
3735 o
= mono_runtime_invoke_checked (m
, NULL
, args
, error
);
3736 goto_if_nok (error
, return_null
);
3741 /* boxed value type */
3742 klass
= mono_class_from_mono_type_internal (type
);
3744 if (mono_class_is_nullable (klass
)) {
3745 o
= mono_nullable_box (mono_field_get_addr (obj
, vtable
, field
), klass
, error
);
3749 o
= mono_object_new_checked (domain
, klass
, error
);
3750 goto_if_nok (error
, return_null
);
3751 v
= mono_object_get_data (o
);
3754 get_default_field_value (domain
, field
, v
, string_handle
, error
);
3755 goto_if_nok (error
, return_null
);
3756 } else if (is_static
) {
3757 mono_field_static_get_value_checked (vtable
, field
, v
, string_handle
, error
);
3758 goto_if_nok (error
, return_null
);
3760 mono_field_get_value_internal (obj
, field
, v
);
3767 HANDLE_FUNCTION_RETURN_VAL (o
);
3771 * Important detail, if type is MONO_TYPE_STRING we return a blob encoded string (ie, utf16 + leb128 prefixed size)
3774 mono_metadata_read_constant_value (const char *blob
, MonoTypeEnum type
, void *value
, MonoError
*error
)
3777 gboolean retval
= TRUE
;
3778 const char *p
= blob
;
3779 mono_metadata_decode_blob_size (p
, &p
);
3782 case MONO_TYPE_BOOLEAN
:
3785 *(guint8
*) value
= *p
;
3787 case MONO_TYPE_CHAR
:
3790 *(guint16
*) value
= read16 (p
);
3794 *(guint32
*) value
= read32 (p
);
3798 *(guint64
*) value
= read64 (p
);
3801 readr4 (p
, (float*) value
);
3804 readr8 (p
, (double*) value
);
3806 case MONO_TYPE_STRING
:
3807 *(const char**) value
= blob
;
3809 case MONO_TYPE_CLASS
:
3810 *(gpointer
*) value
= NULL
;
3814 mono_error_set_execution_engine (error
, "Type 0x%02x should not be in constant table", type
);
3820 mono_get_constant_value_from_blob (MonoDomain
* domain
, MonoTypeEnum type
, const char *blob
, void *value
, MonoStringHandleOut string_handle
, MonoError
*error
)
3822 MONO_REQ_GC_UNSAFE_MODE
;
3824 // FIXMEcoop excess frame, but mono_ldstr_metadata_sig does allocate a handle.
3825 HANDLE_FUNCTION_ENTER ();
3827 gboolean result
= FALSE
;
3829 if (!mono_metadata_read_constant_value (blob
, type
, value
, error
))
3832 if (type
== MONO_TYPE_STRING
) {
3833 mono_ldstr_metadata_sig (domain
, *(const char**)value
, string_handle
, error
);
3834 *(gpointer
*)value
= MONO_HANDLE_RAW (string_handle
);
3838 HANDLE_FUNCTION_RETURN_VAL (result
);
3842 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
, MonoStringHandleOut string_handle
, MonoError
*error
)
3844 MONO_REQ_GC_NEUTRAL_MODE
;
3846 MonoTypeEnum def_type
;
3851 data
= mono_class_get_field_default_value (field
, &def_type
);
3852 (void)mono_get_constant_value_from_blob (domain
, def_type
, data
, value
, string_handle
, error
);
3856 mono_field_static_get_value_for_thread (MonoInternalThread
*thread
, MonoVTable
*vt
, MonoClassField
*field
, void *value
, MonoStringHandleOut string_handle
, MonoError
*error
)
3858 MONO_REQ_GC_UNSAFE_MODE
;
3864 g_return_if_fail (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3866 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
) {
3867 get_default_field_value (vt
->domain
, field
, value
, string_handle
, error
);
3871 if (field
->offset
== -1) {
3872 /* Special static */
3873 gpointer addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3874 src
= mono_get_special_static_data_for_thread (thread
, GPOINTER_TO_UINT (addr
));
3876 src
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3878 mono_copy_value (field
->type
, value
, src
, TRUE
);
3882 * mono_field_static_get_value:
3883 * \param vt vtable to the object
3884 * \param field \c MonoClassField describing the field to fetch information from
3885 * \param value where the value is returned
3886 * Use this routine to get the value of the static field \p field value.
3888 * The pointer provided by value must be of the field type, for reference
3889 * types this is a \c MonoObject*, for value types its the actual pointer to
3897 * mono_field_static_get_value (vt, int_field, &i);
3901 mono_field_static_get_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3903 MONO_REQ_GC_NEUTRAL_MODE
;
3906 mono_field_static_get_value_checked (vt
, field
, value
, MONO_HANDLE_NEW (MonoString
, NULL
), error
);
3907 mono_error_cleanup (error
);
3911 * mono_field_static_get_value_checked:
3912 * \param vt vtable to the object
3913 * \param field \c MonoClassField describing the field to fetch information from
3914 * \param value where the value is returned
3915 * \param error set on error
3916 * Use this routine to get the value of the static field \p field value.
3918 * The pointer provided by value must be of the field type, for reference
3919 * types this is a \c MonoObject*, for value types its the actual pointer to
3924 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3925 * if (!is_ok (error)) { ... }
3927 * On failure sets \p error.
3930 mono_field_static_get_value_checked (MonoVTable
*vt
, MonoClassField
*field
, void *value
, MonoStringHandleOut string_handle
, MonoError
*error
)
3932 MONO_REQ_GC_NEUTRAL_MODE
;
3934 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt
, field
, value
, string_handle
, error
);
3938 * mono_property_set_value:
3939 * \param prop MonoProperty to set
3940 * \param obj instance object on which to act
3941 * \param params parameters to pass to the propery
3942 * \param exc optional exception
3943 * Invokes the property's set method with the given arguments on the
3944 * object instance obj (or NULL for static properties).
3946 * You can pass NULL as the exc argument if you don't want to
3947 * catch exceptions, otherwise, \c *exc will be set to the exception
3948 * thrown, if any. if an exception is thrown, you can't use the
3949 * \c MonoObject* result from the function.
3952 mono_property_set_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3954 MONO_ENTER_GC_UNSAFE
;
3957 do_runtime_invoke (prop
->set
, obj
, params
, exc
, error
);
3958 if (exc
&& *exc
== NULL
&& !is_ok (error
)) {
3959 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
3961 mono_error_cleanup (error
);
3963 MONO_EXIT_GC_UNSAFE
;
3967 * mono_property_set_value_handle:
3968 * \param prop \c MonoProperty to set
3969 * \param obj instance object on which to act
3970 * \param params parameters to pass to the propery
3971 * \param error set on error
3972 * Invokes the property's set method with the given arguments on the
3973 * object instance \p obj (or NULL for static properties).
3974 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3975 * If an exception is thrown, it will be caught and returned via \p error.
3978 mono_property_set_value_handle (MonoProperty
*prop
, MonoObjectHandle obj
, void **params
, MonoError
*error
)
3980 MONO_REQ_GC_UNSAFE_MODE
;
3985 do_runtime_invoke (prop
->set
, MONO_HANDLE_RAW (obj
), params
, &exc
, error
);
3986 if (exc
!= NULL
&& is_ok (error
))
3987 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
3988 return is_ok (error
);
3992 * mono_property_get_value:
3993 * \param prop \c MonoProperty to fetch
3994 * \param obj instance object on which to act
3995 * \param params parameters to pass to the propery
3996 * \param exc optional exception
3997 * Invokes the property's \c get method with the given arguments on the
3998 * object instance \p obj (or NULL for static properties).
4000 * You can pass NULL as the \p exc argument if you don't want to
4001 * catch exceptions, otherwise, \c *exc will be set to the exception
4002 * thrown, if any. if an exception is thrown, you can't use the
4003 * \c MonoObject* result from the function.
4005 * \returns the value from invoking the \c get method on the property.
4008 mono_property_get_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
4011 MONO_ENTER_GC_UNSAFE
;
4014 val
= do_runtime_invoke (prop
->get
, obj
, params
, exc
, error
);
4015 if (exc
&& *exc
== NULL
&& !is_ok (error
)) {
4016 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
4018 mono_error_cleanup (error
); /* FIXME don't raise here */
4020 MONO_EXIT_GC_UNSAFE
;
4025 * mono_property_get_value_checked:
4026 * \param prop \c MonoProperty to fetch
4027 * \param obj instance object on which to act
4028 * \param params parameters to pass to the propery
4029 * \param error set on error
4030 * Invokes the property's \c get method with the given arguments on the
4031 * object instance obj (or NULL for static properties).
4033 * If an exception is thrown, you can't use the
4034 * \c MonoObject* result from the function. The exception will be propagated via \p error.
4036 * \returns the value from invoking the get method on the property. On
4037 * failure returns NULL and sets \p error.
4040 mono_property_get_value_checked (MonoProperty
*prop
, void *obj
, void **params
, MonoError
*error
)
4042 MONO_REQ_GC_UNSAFE_MODE
;
4045 MonoObject
*val
= do_runtime_invoke (prop
->get
, obj
, params
, &exc
, error
);
4046 if (exc
!= NULL
&& !is_ok (error
))
4047 mono_error_set_exception_instance (error
, (MonoException
*) exc
);
4053 static MonoClassField
*
4054 nullable_class_get_value_field (MonoClass
*klass
)
4056 mono_class_setup_fields (klass
);
4057 g_assert (m_class_is_fields_inited (klass
));
4059 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
4060 return &klass_fields
[1];
4063 static MonoClassField
*
4064 nullable_class_get_has_value_field (MonoClass
*klass
)
4066 mono_class_setup_fields (klass
);
4067 g_assert (m_class_is_fields_inited (klass
));
4069 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
4070 return &klass_fields
[0];
4074 nullable_get_has_value_field_addr (guint8
*nullable
, MonoClass
*klass
)
4076 MonoClassField
*has_value_field
= nullable_class_get_has_value_field (klass
);
4078 return mono_vtype_get_field_addr (nullable
, has_value_field
);
4082 nullable_get_value_field_addr (guint8
*nullable
, MonoClass
*klass
)
4084 MonoClassField
*has_value_field
= nullable_class_get_value_field (klass
);
4086 return mono_vtype_get_field_addr (nullable
, has_value_field
);
4090 * mono_nullable_init:
4091 * @buf: The nullable structure to initialize.
4092 * @value: the value to initialize from
4093 * @klass: the type for the object
4095 * Initialize the nullable structure pointed to by @buf from @value which
4096 * should be a boxed value type. The size of @buf should be able to hold
4097 * as much data as the @klass->instance_size (which is the number of bytes
4098 * that will be copies).
4100 * Since Nullables have variable structure, we can not define a C
4101 * structure for them.
4104 mono_nullable_init (guint8
*buf
, MonoObject
*value
, MonoClass
*klass
)
4106 MONO_REQ_GC_UNSAFE_MODE
;
4108 MonoClass
*param_class
= m_class_get_cast_class (klass
);
4109 gpointer has_value_field_addr
= nullable_get_has_value_field_addr (buf
, klass
);
4110 gpointer value_field_addr
= nullable_get_value_field_addr (buf
, klass
);
4112 *(guint8
*)(has_value_field_addr
) = value
? 1 : 0;
4114 if (m_class_has_references (param_class
))
4115 mono_gc_wbarrier_value_copy_internal (value_field_addr
, mono_object_unbox_internal (value
), 1, param_class
);
4117 mono_gc_memmove_atomic (value_field_addr
, mono_object_unbox_internal (value
), mono_class_value_size (param_class
, NULL
));
4119 mono_gc_bzero_atomic (value_field_addr
, mono_class_value_size (param_class
, NULL
));
4124 * mono_nullable_init_from_handle:
4125 * @buf: The nullable structure to initialize.
4126 * @value: the value to initialize from
4127 * @klass: the type for the object
4129 * Initialize the nullable structure pointed to by @buf from @value which
4130 * should be a boxed value type. The size of @buf should be able to hold
4131 * as much data as the @klass->instance_size (which is the number of bytes
4132 * that will be copies).
4134 * Since Nullables have variable structure, we can not define a C
4135 * structure for them.
4138 mono_nullable_init_from_handle (guint8
*buf
, MonoObjectHandle value
, MonoClass
*klass
)
4140 MONO_REQ_GC_UNSAFE_MODE
;
4142 if (!MONO_HANDLE_IS_NULL (value
)) {
4143 uint32_t value_gchandle
= 0;
4144 gpointer src
= mono_object_handle_pin_unbox (value
, &value_gchandle
);
4145 mono_nullable_init_unboxed (buf
, src
, klass
);
4147 mono_gchandle_free_internal (value_gchandle
);
4149 mono_nullable_init_unboxed (buf
, NULL
, klass
);
4154 * mono_nullable_init_unboxed
4156 * @buf: The nullable structure to initialize.
4157 * @value: the unboxed address of the value to initialize from
4158 * @klass: the type for the object
4160 * Initialize the nullable structure pointed to by @buf from @value which
4161 * should be a boxed value type. The size of @buf should be able to hold
4162 * as much data as the @klass->instance_size (which is the number of bytes
4163 * that will be copies).
4165 * Since Nullables have variable structure, we can not define a C
4166 * structure for them.
4168 * This function expects all objects to be pinned or for
4169 * MONO_ENTER_NO_SAFEPOINTS to be used in a caller.
4172 mono_nullable_init_unboxed (guint8
*buf
, gpointer value
, MonoClass
*klass
)
4174 MONO_REQ_GC_UNSAFE_MODE
;
4176 MonoClass
*param_class
= m_class_get_cast_class (klass
);
4177 gpointer has_value_field_addr
= nullable_get_has_value_field_addr (buf
, klass
);
4178 gpointer value_field_addr
= nullable_get_value_field_addr (buf
, klass
);
4180 *(guint8
*)(has_value_field_addr
) = (value
== NULL
) ? 0 : 1;
4182 if (m_class_has_references (param_class
))
4183 mono_gc_wbarrier_value_copy_internal (value_field_addr
, value
, 1, param_class
);
4185 mono_gc_memmove_atomic (value_field_addr
, value
, mono_class_value_size (param_class
, NULL
));
4187 mono_gc_bzero_atomic (value_field_addr
, mono_class_value_size (param_class
, NULL
));
4192 * mono_nullable_box:
4193 * \param buf The buffer representing the data to be boxed
4194 * \param klass the type to box it as.
4195 * \param error set on error
4197 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
4198 * \p buf. On failure returns NULL and sets \p error.
4201 mono_nullable_box (gpointer vbuf
, MonoClass
*klass
, MonoError
*error
)
4203 guint8
*buf
= (guint8
*)vbuf
;
4204 MONO_REQ_GC_UNSAFE_MODE
;
4207 MonoClass
*param_class
= m_class_get_cast_class (klass
);
4208 gpointer has_value_field_addr
= nullable_get_has_value_field_addr (buf
, klass
);
4209 gpointer value_field_addr
= nullable_get_value_field_addr (buf
, klass
);
4211 g_assertf (!m_class_is_byreflike (param_class
), "Unexpected Nullable<%s> - generic type instantiated with IsByRefLike type", mono_type_get_full_name (param_class
));
4213 if (*(guint8
*)(has_value_field_addr
)) {
4214 MonoObject
*o
= mono_object_new_checked (mono_domain_get (), param_class
, error
);
4215 return_val_if_nok (error
, NULL
);
4216 if (m_class_has_references (param_class
))
4217 mono_gc_wbarrier_value_copy_internal (mono_object_unbox_internal (o
), value_field_addr
, 1, param_class
);
4219 mono_gc_memmove_atomic (mono_object_unbox_internal (o
), value_field_addr
, mono_class_value_size (param_class
, NULL
));
4227 mono_nullable_box_handle (gpointer buf
, MonoClass
*klass
, MonoError
*error
)
4229 // FIXMEcoop gpointer buf needs more attention
4230 return MONO_HANDLE_NEW (MonoObject
, mono_nullable_box (buf
, klass
, error
));
4234 mono_get_delegate_invoke_internal (MonoClass
*klass
)
4238 result
= mono_get_delegate_invoke_checked (klass
, error
);
4239 /* FIXME: better external API that doesn't swallow the error */
4240 mono_error_cleanup (error
);
4245 * mono_get_delegate_invoke:
4246 * \param klass The delegate class
4247 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
4250 mono_get_delegate_invoke (MonoClass
*klass
)
4252 MONO_EXTERNAL_ONLY (MonoMethod
*, mono_get_delegate_invoke_internal (klass
));
4256 * mono_get_delegate_invoke_checked:
4257 * \param klass The delegate class
4258 * \param error set on error
4259 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type or not a delegate class.
4261 * Sets \p error on error
4264 mono_get_delegate_invoke_checked (MonoClass
*klass
, MonoError
*error
)
4266 MONO_REQ_GC_NEUTRAL_MODE
;
4270 /* This is called at runtime, so avoid the slower search in metadata */
4271 mono_class_setup_methods (klass
);
4272 if (mono_class_has_failure (klass
))
4274 im
= mono_class_get_method_from_name_checked (klass
, "Invoke", -1, 0, error
);
4279 mono_get_delegate_begin_invoke_internal (MonoClass
*klass
)
4283 result
= mono_get_delegate_begin_invoke_checked (klass
, error
);
4284 /* FIXME: better external API that doesn't swallow the error */
4285 mono_error_cleanup (error
);
4290 * mono_get_delegate_begin_invoke:
4291 * \param klass The delegate class
4292 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4295 mono_get_delegate_begin_invoke (MonoClass
*klass
)
4297 MONO_EXTERNAL_ONLY (MonoMethod
*, mono_get_delegate_begin_invoke_internal (klass
));
4301 * mono_get_delegate_begin_invoke_checked:
4302 * \param klass The delegate class
4303 * \param error set on error
4304 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type or not a delegate class.
4306 * Sets \p error on error
4309 mono_get_delegate_begin_invoke_checked (MonoClass
*klass
, MonoError
*error
)
4311 MONO_REQ_GC_NEUTRAL_MODE
;
4315 /* This is called at runtime, so avoid the slower search in metadata */
4316 mono_class_setup_methods (klass
);
4317 if (mono_class_has_failure (klass
))
4319 im
= mono_class_get_method_from_name_checked (klass
, "BeginInvoke", -1, 0, error
);
4324 mono_get_delegate_end_invoke_internal (MonoClass
*klass
)
4328 result
= mono_get_delegate_end_invoke_checked (klass
, error
);
4329 /* FIXME: better external API that doesn't swallow the error */
4330 mono_error_cleanup (error
);
4335 * mono_get_delegate_end_invoke:
4336 * \param klass The delegate class
4337 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
4340 mono_get_delegate_end_invoke (MonoClass
*klass
)
4342 MONO_EXTERNAL_ONLY (MonoMethod
*, mono_get_delegate_end_invoke_internal (klass
));
4346 * mono_get_delegate_end_invoke_checked:
4347 * \param klass The delegate class
4348 * \param error set on error
4349 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type or not a delegate class.
4351 * Sets \p error on error
4354 mono_get_delegate_end_invoke_checked (MonoClass
*klass
, MonoError
*error
)
4356 MONO_REQ_GC_NEUTRAL_MODE
;
4360 /* This is called at runtime, so avoid the slower search in metadata */
4361 mono_class_setup_methods (klass
);
4362 if (mono_class_has_failure (klass
))
4364 im
= mono_class_get_method_from_name_checked (klass
, "EndInvoke", -1, 0, error
);
4369 * mono_runtime_delegate_invoke:
4370 * \param delegate pointer to a delegate object.
4371 * \param params parameters for the delegate.
4372 * \param exc Pointer to the exception result.
4374 * Invokes the delegate method \p delegate with the parameters provided.
4376 * You can pass NULL as the \p exc argument if you don't want to
4377 * catch exceptions, otherwise, \c *exc will be set to the exception
4378 * thrown, if any. if an exception is thrown, you can't use the
4379 * \c MonoObject* result from the function.
4382 mono_runtime_delegate_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
)
4384 MONO_REQ_GC_UNSAFE_MODE
;
4388 MonoObject
*result
= mono_runtime_delegate_try_invoke (delegate
, params
, exc
, error
);
4390 mono_error_cleanup (error
);
4394 *exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
4398 MonoObject
*result
= mono_runtime_delegate_invoke_checked (delegate
, params
, error
);
4399 mono_error_raise_exception_deprecated (error
); /* OK to throw, external only without a good alternative */
4405 * mono_runtime_delegate_try_invoke:
4406 * \param delegate pointer to a delegate object.
4407 * \param params parameters for the delegate.
4408 * \param exc Pointer to the exception result.
4409 * \param error set on error
4410 * Invokes the delegate method \p delegate with the parameters provided.
4412 * You can pass NULL as the \p exc argument if you don't want to
4413 * catch exceptions, otherwise, \c *exc will be set to the exception
4414 * thrown, if any. On failure to execute, \p error will be set.
4415 * if an exception is thrown, you can't use the
4416 * \c MonoObject* result from the function.
4419 mono_runtime_delegate_try_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
, MonoError
*error
)
4421 MONO_REQ_GC_UNSAFE_MODE
;
4425 MonoClass
*klass
= delegate
->vtable
->klass
;
4428 im
= mono_get_delegate_invoke_internal (klass
);
4429 g_assertf (im
, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass
));
4432 o
= mono_runtime_try_invoke (im
, delegate
, params
, exc
, error
);
4434 o
= mono_runtime_invoke_checked (im
, delegate
, params
, error
);
4440 static MonoObjectHandle
4441 mono_runtime_delegate_try_invoke_handle (MonoObjectHandle delegate
, void **params
, MonoError
*error
)
4443 MONO_REQ_GC_UNSAFE_MODE
;
4445 MonoClass
* const klass
= MONO_HANDLE_GETVAL (delegate
, vtable
)->klass
;
4446 MonoMethod
* const im
= mono_get_delegate_invoke_internal (klass
);
4447 g_assertf (im
, "Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass
));
4449 return mono_runtime_try_invoke_handle (im
, delegate
, params
, error
);
4453 * mono_runtime_delegate_invoke_checked:
4454 * \param delegate pointer to a delegate object.
4455 * \param params parameters for the delegate.
4456 * \param error set on error
4457 * Invokes the delegate method \p delegate with the parameters provided.
4458 * On failure \p error will be set and you can't use the \c MonoObject*
4459 * result from the function.
4462 mono_runtime_delegate_invoke_checked (MonoObject
*delegate
, void **params
, MonoError
*error
)
4465 return mono_runtime_delegate_try_invoke (delegate
, params
, NULL
, error
);
4468 static char **main_args
= NULL
;
4469 static int num_main_args
= 0;
4472 * mono_runtime_get_main_args:
4473 * \returns A \c MonoArray with the arguments passed to the main program
4476 mono_runtime_get_main_args (void)
4478 HANDLE_FUNCTION_ENTER ();
4479 MONO_REQ_GC_UNSAFE_MODE
;
4481 MonoArrayHandle result
= MONO_HANDLE_NEW (MonoArray
, NULL
);
4483 MonoArrayHandle arg_array
= mono_runtime_get_main_args_handle (error
);
4484 goto_if_nok (error
, leave
);
4485 MONO_HANDLE_ASSIGN (result
, arg_array
);
4487 /* FIXME: better external API that doesn't swallow the error */
4488 mono_error_cleanup (error
);
4489 HANDLE_FUNCTION_RETURN_OBJ (result
);
4493 handle_main_arg_array_set (MonoDomain
*domain
, int idx
, MonoArrayHandle dest
, MonoError
*error
)
4495 HANDLE_FUNCTION_ENTER ();
4497 MonoStringHandle value
= mono_string_new_handle (domain
, main_args
[idx
], error
);
4498 goto_if_nok (error
, leave
);
4499 MONO_HANDLE_ARRAY_SETREF (dest
, idx
, value
);
4501 HANDLE_FUNCTION_RETURN_VAL (is_ok (error
));
4505 * mono_runtime_get_main_args_handle:
4506 * \param error set on error
4507 * \returns a \c MonoArray with the arguments passed to the main
4508 * program. On failure returns NULL and sets \p error.
4511 mono_runtime_get_main_args_handle (MonoError
*error
)
4513 HANDLE_FUNCTION_ENTER ();
4514 MonoArrayHandle array
;
4516 MonoDomain
*domain
= mono_domain_get ();
4519 array
= mono_array_new_handle (domain
, mono_defaults
.string_class
, num_main_args
, error
);
4520 if (!is_ok (error
)) {
4521 array
= MONO_HANDLE_CAST (MonoArray
, NULL_HANDLE
);
4524 for (i
= 0; i
< num_main_args
; ++i
) {
4525 if (!handle_main_arg_array_set (domain
, i
, array
, error
))
4529 HANDLE_FUNCTION_RETURN_REF (MonoArray
, array
);
4533 free_main_args (void)
4535 MONO_REQ_GC_NEUTRAL_MODE
;
4539 for (i
= 0; i
< num_main_args
; ++i
)
4540 g_free (main_args
[i
]);
4547 * mono_runtime_set_main_args:
4548 * \param argc number of arguments from the command line
4549 * \param argv array of strings from the command line
4550 * Set the command line arguments from an embedding application that doesn't otherwise call
4551 * \c mono_runtime_run_main.
4554 mono_runtime_set_main_args (int argc
, char* argv
[])
4556 MONO_REQ_GC_NEUTRAL_MODE
;
4561 main_args
= g_new0 (char*, argc
);
4562 num_main_args
= argc
;
4564 for (i
= 0; i
< argc
; ++i
) {
4567 utf8_arg
= mono_utf8_from_external (argv
[i
]);
4568 if (utf8_arg
== NULL
) {
4569 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i
, argv
[i
]);
4570 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4574 main_args
[i
] = utf8_arg
;
4577 MONO_EXTERNAL_ONLY (int, 0);
4581 * Prepare an array of arguments in order to execute a standard Main()
4582 * method (argc/argv contains the executable name). This method also
4583 * sets the command line argument value needed by System.Environment.
4587 prepare_run_main (MonoMethod
*method
, int argc
, char *argv
[])
4589 MONO_REQ_GC_UNSAFE_MODE
;
4593 MonoArray
*args
= NULL
;
4594 MonoDomain
*domain
= mono_domain_get ();
4595 gchar
*utf8_fullpath
;
4596 MonoMethodSignature
*sig
;
4598 g_assert (method
!= NULL
);
4600 mono_thread_set_main (mono_thread_current ());
4602 main_args
= g_new0 (char*, argc
);
4603 num_main_args
= argc
;
4605 if (!g_path_is_absolute (argv
[0])) {
4606 gchar
*basename
= g_path_get_basename (argv
[0]);
4607 gchar
*fullpath
= g_build_filename (m_class_get_image (method
->klass
)->assembly
->basedir
,
4611 utf8_fullpath
= mono_utf8_from_external (fullpath
);
4612 if(utf8_fullpath
== NULL
) {
4613 /* Printing the arg text will cause glib to
4614 * whinge about "Invalid UTF-8", but at least
4615 * its relevant, and shows the problem text
4618 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath
);
4619 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4626 utf8_fullpath
= mono_utf8_from_external (argv
[0]);
4627 if(utf8_fullpath
== NULL
) {
4628 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv
[0]);
4629 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4634 main_args
[0] = utf8_fullpath
;
4636 for (i
= 1; i
< argc
; ++i
) {
4639 utf8_arg
=mono_utf8_from_external (argv
[i
]);
4640 if(utf8_arg
==NULL
) {
4641 /* Ditto the comment about Invalid UTF-8 here */
4642 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i
, argv
[i
]);
4643 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4647 main_args
[i
] = utf8_arg
;
4652 sig
= mono_method_signature_internal (method
);
4654 g_print ("Unable to load Main method.\n");
4658 if (sig
->param_count
) {
4659 args
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, argc
, error
);
4660 mono_error_assert_ok (error
);
4661 for (i
= 0; i
< argc
; ++i
) {
4662 /* The encodings should all work, given that
4663 * we've checked all these args for the
4666 gchar
*str
= mono_utf8_from_external (argv
[i
]);
4667 MonoString
*arg
= mono_string_new_checked (domain
, str
, error
);
4668 mono_error_assert_ok (error
);
4669 mono_array_setref_internal (args
, i
, arg
);
4673 args
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, 0, error
);
4674 mono_error_assert_ok (error
);
4677 mono_assembly_set_main (m_class_get_image (method
->klass
)->assembly
);
4683 * mono_runtime_run_main:
4684 * \param method the method to start the application with (usually <code>Main</code>)
4685 * \param argc number of arguments from the command line
4686 * \param argv array of strings from the command line
4687 * \param exc excetption results
4688 * Execute a standard \c Main method (\p argc / \p argv contains the
4689 * executable name). This method also sets the command line argument value
4690 * needed by \c System.Environment.
4693 mono_runtime_run_main (MonoMethod
*method
, int argc
, char* argv
[],
4698 MONO_REQ_GC_UNSAFE_MODE
;
4702 MONO_ENTER_GC_UNSAFE
;
4704 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4706 res
= mono_runtime_try_exec_main (method
, args
, exc
);
4708 res
= mono_runtime_exec_main_checked (method
, args
, error
);
4710 MONO_EXIT_GC_UNSAFE
;
4713 mono_error_raise_exception_deprecated (error
); /* OK to throw, external only without a better alternative */
4719 * mono_runtime_run_main_checked:
4720 * \param method the method to start the application with (usually \c Main)
4721 * \param argc number of arguments from the command line
4722 * \param argv array of strings from the command line
4723 * \param error set on error
4725 * Execute a standard \c Main method (\p argc / \p argv contains the
4726 * executable name). This method also sets the command line argument value
4727 * needed by \c System.Environment. On failure sets \p error.
4730 mono_runtime_run_main_checked (MonoMethod
*method
, int argc
, char* argv
[],
4734 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4735 return mono_runtime_exec_main_checked (method
, args
, error
);
4739 * mono_runtime_try_run_main:
4740 * \param method the method to start the application with (usually \c Main)
4741 * \param argc number of arguments from the command line
4742 * \param argv array of strings from the command line
4743 * \param exc set if \c Main throws an exception
4744 * \param error set if \c Main can't be executed
4745 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4746 * name). This method also sets the command line argument value needed
4747 * by \c System.Environment. On failure sets \p error if Main can't be
4748 * executed or \p exc if it threw an exception.
4751 mono_runtime_try_run_main (MonoMethod
*method
, int argc
, char* argv
[],
4755 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4756 return mono_runtime_try_exec_main (method
, args
, exc
);
4760 mono_new_null (void) // A code size optimization (source and object).
4762 return MONO_HANDLE_NEW (MonoObject
, NULL
);
4765 static MonoObjectHandle
4766 serialize_or_deserialize_object (MonoObjectHandle obj
, const gchar
*method_name
, MonoMethod
**method
, MonoError
*error
)
4769 MonoClass
*klass
= mono_class_get_remoting_services_class ();
4770 *method
= mono_class_get_method_from_name_checked (klass
, method_name
, -1, 0, error
);
4771 return_val_if_nok (error
, mono_new_null ());
4775 mono_error_set_exception_instance (error
, NULL
);
4776 return mono_new_null ();
4779 void *params
[ ] = { MONO_HANDLE_RAW (obj
) };
4780 return mono_runtime_try_invoke_handle (*method
, NULL_HANDLE
, params
, error
);
4783 static MonoMethod
*serialize_method
;
4785 static MonoObjectHandle
4786 serialize_object (MonoObjectHandle obj
, MonoError
*error
)
4788 g_assert (!mono_class_is_marshalbyref (mono_handle_class (obj
)));
4789 return serialize_or_deserialize_object (obj
, "SerializeCallData", &serialize_method
, error
);
4792 static MonoMethod
*deserialize_method
;
4794 static MonoObjectHandle
4795 deserialize_object (MonoObjectHandle obj
, MonoError
*error
)
4797 MONO_REQ_GC_UNSAFE_MODE
;
4798 return serialize_or_deserialize_object (obj
, "DeserializeCallData", &deserialize_method
, error
);
4801 #ifndef DISABLE_REMOTING
4802 static MonoObjectHandle
4803 make_transparent_proxy (MonoObjectHandle obj
, MonoError
*error
)
4805 MONO_REQ_GC_UNSAFE_MODE
;
4807 static MonoMethod
*get_proxy_method
;
4809 if (!get_proxy_method
) {
4810 get_proxy_method
= mono_class_get_method_from_name_checked (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0, 0, error
);
4811 mono_error_assert_ok (error
);
4814 g_assert (mono_class_is_marshalbyref (MONO_HANDLE_GETVAL (obj
, vtable
)->klass
));
4816 MonoDomain
*domain
= mono_domain_get ();
4817 MonoRealProxyHandle real_proxy
= MONO_HANDLE_CAST (MonoRealProxy
, mono_object_new_handle (domain
, mono_defaults
.real_proxy_class
, error
));
4818 goto_if_nok (error
, return_null
);
4819 MonoReflectionTypeHandle reflection_type
;
4820 reflection_type
= mono_type_get_object_handle (domain
, m_class_get_byval_arg (mono_handle_class (obj
)), error
);
4821 goto_if_nok (error
, return_null
);
4823 MONO_HANDLE_SET (real_proxy
, class_to_proxy
, reflection_type
);
4824 MONO_HANDLE_SET (real_proxy
, unwrapped_server
, obj
);
4826 return mono_runtime_try_invoke_handle (get_proxy_method
, MONO_HANDLE_CAST (MonoObject
, real_proxy
), NULL
, error
);
4828 return mono_new_null ();
4830 #endif /* DISABLE_REMOTING */
4833 * mono_object_xdomain_representation
4834 * \param obj an object
4835 * \param target_domain a domain
4836 * \param error set on error.
4837 * Creates a representation of obj in the domain \p target_domain. This
4838 * is either a copy of \p obj arrived through via serialization and
4839 * deserialization or a proxy, depending on whether the object is
4840 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4841 * If the object cannot be represented in \p target_domain, NULL is
4842 * returned and \p error is set appropriately.
4845 mono_object_xdomain_representation (MonoObjectHandle obj
, MonoDomain
*target_domain
, MonoError
*error
)
4847 HANDLE_FUNCTION_ENTER ();
4849 MONO_REQ_GC_UNSAFE_MODE
;
4851 MonoObjectHandle deserialized
;
4853 #ifndef DISABLE_REMOTING
4854 if (mono_class_is_marshalbyref (mono_handle_class (obj
))) {
4855 deserialized
= make_transparent_proxy (obj
, error
);
4860 MonoDomain
*domain
= mono_domain_get ();
4862 mono_domain_set_internal_with_options (MONO_HANDLE_DOMAIN (obj
), FALSE
);
4863 MonoObjectHandle serialized
= serialize_object (obj
, error
);
4864 mono_domain_set_internal_with_options (target_domain
, FALSE
);
4866 deserialized
= deserialize_object (serialized
, error
);
4868 deserialized
= mono_new_null ();
4870 if (domain
!= target_domain
)
4871 mono_domain_set_internal_with_options (domain
, FALSE
);
4874 HANDLE_FUNCTION_RETURN_REF (MonoObject
, deserialized
);
4877 /* Used in call_unhandled_exception_delegate */
4878 static MonoObjectHandle
4879 create_unhandled_exception_eventargs (MonoObjectHandle exc
, MonoError
*error
)
4881 MONO_REQ_GC_UNSAFE_MODE
;
4883 MonoClass
* const klass
= mono_class_get_unhandled_exception_event_args_class ();
4884 mono_class_init_internal (klass
);
4886 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4887 MonoMethod
* const method
= mono_class_get_method_from_name_checked (klass
, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC
, error
);
4888 goto_if_nok (error
, return_null
);
4892 MonoBoolean is_terminating
= TRUE
;
4894 gpointer args
[ ] = {
4895 MONO_HANDLE_RAW (exc
), // FIXMEcoop (ok as long as handles are pinning)
4899 MonoObjectHandle obj
= mono_object_new_handle (mono_domain_get (), klass
, error
);
4900 goto_if_nok (error
, return_null
);
4902 mono_runtime_invoke_handle_void (method
, obj
, args
, error
);
4903 goto_if_nok (error
, return_null
);
4908 return MONO_HANDLE_NEW (MonoObject
, NULL
);
4911 /* Used in mono_unhandled_exception_internal */
4913 call_unhandled_exception_delegate (MonoDomain
*domain
, MonoObjectHandle delegate
, MonoObjectHandle exc
)
4915 MONO_REQ_GC_UNSAFE_MODE
;
4918 MonoDomain
*current_domain
= mono_domain_get ();
4920 if (domain
!= current_domain
)
4921 mono_domain_set_internal_with_options (domain
, FALSE
);
4923 g_assert (domain
== mono_object_domain (domain
->domain
));
4925 if (MONO_HANDLE_DOMAIN (exc
) != domain
) {
4927 exc
= mono_object_xdomain_representation (exc
, domain
, error
);
4928 if (MONO_HANDLE_IS_NULL (exc
)) {
4929 ERROR_DECL (inner_error
);
4930 if (!is_ok (error
)) {
4931 MonoExceptionHandle serialization_exc
= mono_error_convert_to_exception_handle (error
);
4932 exc
= mono_object_xdomain_representation (MONO_HANDLE_CAST (MonoObject
, serialization_exc
), domain
, inner_error
);
4934 exc
= MONO_HANDLE_CAST (MonoObject
, mono_exception_new_serialization ("Could not serialize unhandled exception.", inner_error
));
4936 mono_error_assert_ok (inner_error
);
4939 g_assert (MONO_HANDLE_DOMAIN (exc
) == domain
);
4943 MONO_HANDLE_RAW (create_unhandled_exception_eventargs (exc
, error
)) // FIXMEcoop
4945 mono_error_assert_ok (error
);
4946 mono_runtime_delegate_try_invoke_handle (delegate
, pa
, error
);
4948 if (domain
!= current_domain
)
4949 mono_domain_set_internal_with_options (current_domain
, FALSE
);
4951 if (!is_ok (error
)) {
4952 g_warning ("exception inside UnhandledException handler: %s\n", mono_error_get_message (error
));
4953 mono_error_cleanup (error
);
4957 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy
= MONO_UNHANDLED_POLICY_CURRENT
;
4960 * mono_runtime_unhandled_exception_policy_set:
4961 * \param policy the new policy
4962 * This is a VM internal routine.
4963 * Sets the runtime policy for handling unhandled exceptions.
4966 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy
)
4968 runtime_unhandled_exception_policy
= policy
;
4972 * mono_runtime_unhandled_exception_policy_get:
4974 * This is a VM internal routine.
4976 * Gets the runtime policy for handling unhandled exceptions.
4978 MonoRuntimeUnhandledExceptionPolicy
4979 mono_runtime_unhandled_exception_policy_get (void)
4981 return runtime_unhandled_exception_policy
;
4985 mono_unhandled_exception_internal (MonoObject
*exc_raw
)
4988 HANDLE_FUNCTION_ENTER ();
4989 MONO_HANDLE_DCL (MonoObject
, exc
);
4990 mono_unhandled_exception_checked (exc
, error
);
4991 mono_error_assert_ok (error
);
4992 HANDLE_FUNCTION_RETURN ();
4996 * mono_unhandled_exception:
4997 * \param exc exception thrown
4998 * This is a VM internal routine.
5000 * We call this function when we detect an unhandled exception
5001 * in the default domain.
5003 * It invokes the \c UnhandledException event in \c AppDomain or prints
5004 * a warning to the console
5007 mono_unhandled_exception (MonoObject
*exc
)
5009 MONO_EXTERNAL_ONLY_VOID (mono_unhandled_exception_internal (exc
));
5013 * mono_unhandled_exception_checked:
5014 * @exc: exception thrown
5016 * This is a VM internal routine.
5018 * We call this function when we detect an unhandled exception
5019 * in the default domain.
5021 * It invokes the * UnhandledException event in AppDomain or prints
5022 * a warning to the console
5025 mono_unhandled_exception_checked (MonoObjectHandle exc
, MonoError
*error
)
5027 MONO_REQ_GC_UNSAFE_MODE
;
5029 MonoClassField
*field
;
5030 MonoDomain
*current_domain
, *root_domain
;
5031 MonoObjectHandle current_appdomain_delegate
= MONO_HANDLE_NEW (MonoObject
, NULL
);
5033 MonoClass
*klass
= mono_handle_class (exc
);
5035 * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
5036 * a thread started in unmanaged world.
5037 * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
5039 gboolean no_event
= (klass
== mono_defaults
.threadabortexception_class
);
5040 #ifndef ENABLE_NETCORE
5041 no_event
= no_event
||
5042 (klass
== mono_class_get_appdomain_unloaded_exception_class () &&
5043 mono_thread_info_current ()->runtime_thread
);
5048 field
= mono_class_get_field_from_name_full (mono_defaults
.appdomain_class
, "UnhandledException", NULL
);
5051 current_domain
= mono_domain_get ();
5052 root_domain
= mono_get_root_domain ();
5054 MonoObjectHandle root_appdomain_delegate
= MONO_HANDLE_NEW (MonoObject
, mono_field_get_value_object_checked (root_domain
, field
, (MonoObject
*) root_domain
->domain
, error
)); /* FIXME use handles for mono_field_get_value_object_checked */
5055 return_if_nok (error
);
5056 if (current_domain
!= root_domain
) {
5057 MONO_HANDLE_ASSIGN (current_appdomain_delegate
, MONO_HANDLE_NEW (MonoObject
, mono_field_get_value_object_checked (current_domain
, field
, (MonoObject
*) current_domain
->domain
, error
))); /* FIXME use handles for mono_field_get_value_object_checked */
5058 return_if_nok (error
);
5061 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate
) && MONO_HANDLE_IS_NULL (root_appdomain_delegate
)) {
5062 mono_print_unhandled_exception_internal (MONO_HANDLE_RAW (exc
)); /* FIXME use handles for mono_print_unhandled_exception */
5064 /* unhandled exception callbacks must not be aborted */
5065 mono_threads_begin_abort_protected_block ();
5066 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate
))
5067 call_unhandled_exception_delegate (root_domain
, root_appdomain_delegate
, exc
);
5068 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate
))
5069 call_unhandled_exception_delegate (current_domain
, current_appdomain_delegate
, exc
);
5070 mono_threads_end_abort_protected_block ();
5073 /* set exitcode only if we will abort the process */
5074 if ((main_thread
&& mono_thread_internal_current () == main_thread
->internal_thread
)
5075 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
)
5077 mono_environment_exitcode_set (1);
5082 * mono_runtime_exec_managed_code:
5083 * \param domain Application domain
5084 * \param main_func function to invoke from the execution thread
5085 * \param main_args parameter to the main_func
5086 * Launch a new thread to execute a function
5088 * \p main_func is called back from the thread with main_args as the
5089 * parameter. The callback function is expected to start \c Main
5090 * eventually. This function then waits for all managed threads to
5092 * It is not necessary anymore to execute managed code in a subthread,
5093 * so this function should not be used anymore by default: just
5094 * execute the code and then call mono_thread_manage().
5097 mono_runtime_exec_managed_code (MonoDomain
*domain
,
5098 MonoMainThreadFunc mfunc
,
5101 // This function is external_only.
5102 MONO_ENTER_GC_UNSAFE
;
5105 mono_thread_create_checked (domain
, mfunc
, margs
, error
);
5106 mono_error_assert_ok (error
);
5108 mono_thread_manage_internal ();
5110 MONO_EXIT_GC_UNSAFE
;
5114 prepare_thread_to_exec_main (MonoDomain
*domain
, MonoMethod
*method
)
5116 MONO_REQ_GC_UNSAFE_MODE
;
5117 MonoInternalThread
* thread
= mono_thread_internal_current ();
5118 MonoCustomAttrInfo
* cinfo
;
5119 gboolean has_stathread_attribute
;
5121 if (!domain
->entry_assembly
) {
5124 MonoAssembly
*assembly
;
5126 assembly
= m_class_get_image (method
->klass
)->assembly
;
5127 domain
->entry_assembly
= assembly
;
5128 /* Domains created from another domain already have application_base and configuration_file set */
5129 if (domain
->setup
->application_base
== NULL
) {
5130 MonoString
*basedir
= mono_string_new_checked (domain
, assembly
->basedir
, error
);
5131 mono_error_assert_ok (error
);
5132 MONO_OBJECT_SETREF_INTERNAL (domain
->setup
, application_base
, basedir
);
5135 if (domain
->setup
->configuration_file
== NULL
) {
5136 str
= g_strconcat (assembly
->image
->name
, ".config", (const char*)NULL
);
5137 MonoString
*config_file
= mono_string_new_checked (domain
, str
, error
);
5138 mono_error_assert_ok (error
);
5139 MONO_OBJECT_SETREF_INTERNAL (domain
->setup
, configuration_file
, config_file
);
5141 mono_domain_set_options_from_config (domain
);
5145 ERROR_DECL (cattr_error
);
5146 cinfo
= mono_custom_attrs_from_method_checked (method
, cattr_error
);
5147 mono_error_cleanup (cattr_error
); /* FIXME warn here? */
5149 has_stathread_attribute
= mono_custom_attrs_has_attr (cinfo
, mono_class_get_sta_thread_attribute_class ());
5151 mono_custom_attrs_free (cinfo
);
5153 has_stathread_attribute
= FALSE
;
5155 if (has_stathread_attribute
) {
5156 thread
->apartment_state
= ThreadApartmentState_STA
;
5158 thread
->apartment_state
= ThreadApartmentState_MTA
;
5160 mono_thread_init_apartment_state ();
5165 do_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*error
)
5167 MONO_REQ_GC_UNSAFE_MODE
;
5177 /* FIXME: check signature of method */
5178 if (mono_method_signature_internal (method
)->ret
->type
== MONO_TYPE_I4
) {
5180 res
= mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5182 rval
= *(guint32
*)(mono_object_get_data (res
));
5185 mono_environment_exitcode_set (rval
);
5187 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5199 do_try_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
5201 MONO_REQ_GC_UNSAFE_MODE
;
5211 /* FIXME: check signature of method */
5212 if (mono_method_signature_internal (method
)->ret
->type
== MONO_TYPE_I4
) {
5213 ERROR_DECL (inner_error
);
5215 res
= mono_runtime_try_invoke (method
, NULL
, pa
, exc
, inner_error
);
5216 if (*exc
== NULL
&& !is_ok (inner_error
))
5217 *exc
= (MonoObject
*) mono_error_convert_to_exception (inner_error
);
5219 mono_error_cleanup (inner_error
);
5222 rval
= *(guint32
*)(mono_object_get_data (res
));
5226 mono_environment_exitcode_set (rval
);
5228 ERROR_DECL (inner_error
);
5229 mono_runtime_try_invoke (method
, NULL
, pa
, exc
, inner_error
);
5230 if (*exc
== NULL
&& !is_ok (inner_error
))
5231 *exc
= (MonoObject
*) mono_error_convert_to_exception (inner_error
);
5233 mono_error_cleanup (inner_error
);
5238 /* If the return type of Main is void, only
5239 * set the exitcode if an exception was thrown
5240 * (we don't want to blow away an
5241 * explicitly-set exit code)
5244 mono_environment_exitcode_set (rval
);
5252 * Execute a standard Main() method (args doesn't contain the
5256 mono_runtime_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
5259 MONO_ENTER_GC_UNSAFE
;
5261 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
5263 rval
= do_try_exec_main (method
, args
, exc
);
5265 rval
= do_exec_main_checked (method
, args
, error
);
5266 // FIXME Maybe change mode back here?
5267 mono_error_raise_exception_deprecated (error
); /* OK to throw, external only with no better option */
5269 MONO_EXIT_GC_UNSAFE
;
5274 * Execute a standard Main() method (args doesn't contain the
5277 * On failure sets @error
5280 mono_runtime_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*error
)
5283 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
5284 return do_exec_main_checked (method
, args
, error
);
5288 * Execute a standard Main() method (args doesn't contain the
5291 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
5294 mono_runtime_try_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
5296 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
5297 return do_try_exec_main (method
, args
, exc
);
5300 /** invoke_array_extract_argument:
5301 * @params: array of arguments to the method.
5302 * @i: the index of the argument to extract.
5303 * @t: ith type from the method signature.
5304 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
5305 * @error: set on error.
5307 * Given an array of method arguments, return the ith one using the corresponding type
5308 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
5310 * On failure sets @error and returns NULL.
5313 invoke_array_extract_argument (MonoArray
*params
, int i
, MonoType
*t
, gboolean
* has_byref_nullables
, MonoError
*error
)
5315 MonoType
*t_orig
= t
;
5316 gpointer result
= NULL
;
5322 case MONO_TYPE_BOOLEAN
:
5325 case MONO_TYPE_CHAR
:
5334 case MONO_TYPE_VALUETYPE
:
5335 if (t
->type
== MONO_TYPE_VALUETYPE
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t_orig
))) {
5336 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
5337 result
= mono_array_get_internal (params
, MonoObject
*, i
);
5339 *has_byref_nullables
= TRUE
;
5341 /* MS seems to create the objects if a null is passed in */
5342 gboolean was_null
= FALSE
;
5343 if (!mono_array_get_internal (params
, MonoObject
*, i
)) {
5344 MonoObject
*o
= mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type_internal (t_orig
), error
);
5345 return_val_if_nok (error
, NULL
);
5346 mono_array_setref_internal (params
, i
, o
);
5352 * We can't pass the unboxed vtype byref to the callee, since
5353 * that would mean the callee would be able to modify boxed
5354 * primitive types. So we (and MS) make a copy of the boxed
5355 * object, pass that to the callee, and replace the original
5356 * boxed object in the arg array with the copy.
5358 MonoObject
*orig
= mono_array_get_internal (params
, MonoObject
*, i
);
5359 MonoObject
*copy
= mono_value_box_checked (mono_domain_get (), orig
->vtable
->klass
, mono_object_unbox_internal (orig
), error
);
5360 return_val_if_nok (error
, NULL
);
5361 mono_array_setref_internal (params
, i
, copy
);
5364 result
= mono_object_unbox_internal (mono_array_get_internal (params
, MonoObject
*, i
));
5365 if (!t
->byref
&& was_null
)
5366 mono_array_setref_internal (params
, i
, NULL
);
5369 case MONO_TYPE_STRING
:
5370 case MONO_TYPE_OBJECT
:
5371 case MONO_TYPE_CLASS
:
5372 case MONO_TYPE_ARRAY
:
5373 case MONO_TYPE_SZARRAY
:
5375 result
= mono_array_addr_internal (params
, MonoObject
*, i
);
5376 // FIXME: I need to check this code path
5378 result
= mono_array_get_internal (params
, MonoObject
*, i
);
5380 case MONO_TYPE_GENERICINST
:
5382 t
= m_class_get_this_arg (t
->data
.generic_class
->container_class
);
5384 t
= m_class_get_byval_arg (t
->data
.generic_class
->container_class
);
5386 case MONO_TYPE_PTR
: {
5389 /* The argument should be an IntPtr */
5390 arg
= mono_array_get_internal (params
, MonoObject
*, i
);
5394 g_assert (arg
->vtable
->klass
== mono_defaults
.int_class
);
5395 result
= ((MonoIntPtr
*)arg
)->m_value
;
5400 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig
->type
);
5405 * mono_runtime_invoke_array:
5406 * \param method method to invoke
5407 * \param obj object instance
5408 * \param params arguments to the method
5409 * \param exc exception information.
5410 * Invokes the method represented by \p method on the object \p obj.
5412 * \p obj is the \c this pointer, it should be NULL for static
5413 * methods, a \c MonoObject* for object instances and a pointer to
5414 * the value type for value types.
5416 * The \p params array contains the arguments to the method with the
5417 * same convention: \c MonoObject* pointers for object instances and
5418 * pointers to the value type otherwise. The \c _invoke_array
5419 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5420 * in this case the value types are boxed inside the
5421 * respective reference representation.
5423 * From unmanaged code you'll usually use the
5424 * mono_runtime_invoke_checked() variant.
5426 * Note that this function doesn't handle virtual methods for
5427 * you, it will exec the exact method you pass: we still need to
5428 * expose a function to lookup the derived class implementation
5429 * of a virtual method (there are examples of this in the code,
5432 * You can pass NULL as the \p exc argument if you don't want to
5433 * catch exceptions, otherwise, \c *exc will be set to the exception
5434 * thrown, if any. if an exception is thrown, you can't use the
5435 * \c MonoObject* result from the function.
5437 * If the method returns a value type, it is boxed in an object
5441 mono_runtime_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
5446 MonoObject
*result
= mono_runtime_try_invoke_array (method
, obj
, params
, exc
, error
);
5448 mono_error_cleanup (error
);
5452 *exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
5456 MonoObject
*result
= mono_runtime_try_invoke_array (method
, obj
, params
, NULL
, error
);
5457 mono_error_raise_exception_deprecated (error
); /* OK to throw, external only without a good alternative */
5463 * mono_runtime_invoke_array_checked:
5464 * \param method method to invoke
5465 * \param obj object instance
5466 * \param params arguments to the method
5467 * \param error set on failure.
5468 * Invokes the method represented by \p method on the object \p obj.
5470 * \p obj is the \c this pointer, it should be NULL for static
5471 * methods, a \c MonoObject* for object instances and a pointer to
5472 * the value type for value types.
5474 * The \p params array contains the arguments to the method with the
5475 * same convention: \c MonoObject* pointers for object instances and
5476 * pointers to the value type otherwise. The \c _invoke_array
5477 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5478 * in this case the value types are boxed inside the
5479 * respective reference representation.
5481 * From unmanaged code you'll usually use the
5482 * mono_runtime_invoke_checked() variant.
5484 * Note that this function doesn't handle virtual methods for
5485 * you, it will exec the exact method you pass: we still need to
5486 * expose a function to lookup the derived class implementation
5487 * of a virtual method (there are examples of this in the code,
5490 * On failure or exception, \p error will be set. In that case, you
5491 * can't use the \c MonoObject* result from the function.
5493 * If the method returns a value type, it is boxed in an object
5497 mono_runtime_invoke_array_checked (MonoMethod
*method
, void *obj
, MonoArray
*params
,
5501 return mono_runtime_try_invoke_array (method
, obj
, params
, NULL
, error
);
5505 * mono_runtime_try_invoke_array:
5506 * \param method method to invoke
5507 * \param obj object instance
5508 * \param params arguments to the method
5509 * \param exc exception information.
5510 * \param error set on failure.
5511 * Invokes the method represented by \p method on the object \p obj.
5513 * \p obj is the \c this pointer, it should be NULL for static
5514 * methods, a \c MonoObject* for object instances and a pointer to
5515 * the value type for value types.
5517 * The \p params array contains the arguments to the method with the
5518 * same convention: \c MonoObject* pointers for object instances and
5519 * pointers to the value type otherwise. The \c _invoke_array
5520 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5521 * in this case the value types are boxed inside the
5522 * respective reference representation.
5524 * From unmanaged code you'll usually use the
5525 * mono_runtime_invoke_checked() variant.
5527 * Note that this function doesn't handle virtual methods for
5528 * you, it will exec the exact method you pass: we still need to
5529 * expose a function to lookup the derived class implementation
5530 * of a virtual method (there are examples of this in the code,
5533 * You can pass NULL as the \p exc argument if you don't want to catch
5534 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5535 * any. On other failures, \p error will be set. If an exception is
5536 * thrown or there's an error, you can't use the \c MonoObject* result
5537 * from the function.
5539 * If the method returns a value type, it is boxed in an object
5543 mono_runtime_try_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
5544 MonoObject
**exc
, MonoError
*error
)
5546 MONO_REQ_GC_UNSAFE_MODE
;
5550 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
5551 gpointer
*pa
= NULL
;
5554 gboolean has_byref_nullables
= FALSE
;
5556 if (NULL
!= params
) {
5557 pa
= g_newa (gpointer
, mono_array_length_internal (params
));
5558 for (i
= 0; i
< mono_array_length_internal (params
); i
++) {
5559 MonoType
*t
= sig
->params
[i
];
5560 pa
[i
] = invoke_array_extract_argument (params
, i
, t
, &has_byref_nullables
, error
);
5561 return_val_if_nok (error
, NULL
);
5565 if (!strcmp (method
->name
, ".ctor") && method
->klass
!= mono_defaults
.string_class
) {
5568 if (mono_class_is_nullable (method
->klass
)) {
5569 /* Need to create a boxed vtype instead */
5575 return mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method
->klass
), pa
[0], error
);
5580 obj
= mono_object_new_checked (mono_domain_get (), method
->klass
, error
);
5581 return_val_if_nok (error
, NULL
);
5582 g_assert (obj
); /*maybe we should raise a TLE instead?*/
5583 #ifndef DISABLE_REMOTING
5584 if (mono_object_is_transparent_proxy (obj
)) {
5585 method
= mono_marshal_get_remoting_invoke (method
->slot
== -1 ? method
: m_class_get_vtable (method
->klass
) [method
->slot
], error
);
5586 return_val_if_nok (error
, NULL
);
5589 if (m_class_is_valuetype (method
->klass
))
5590 o
= (MonoObject
*)mono_object_unbox_internal ((MonoObject
*)obj
);
5593 } else if (m_class_is_valuetype (method
->klass
)) {
5594 obj
= mono_value_box_checked (mono_domain_get (), method
->klass
, obj
, error
);
5595 return_val_if_nok (error
, NULL
);
5599 mono_runtime_try_invoke (method
, o
, pa
, exc
, error
);
5601 mono_runtime_invoke_checked (method
, o
, pa
, error
);
5604 return (MonoObject
*)obj
;
5606 if (mono_class_is_nullable (method
->klass
)) {
5607 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
5610 MonoObject
*nullable
;
5611 /* Convert the unboxed vtype into a Nullable structure */
5612 nullable
= mono_object_new_checked (mono_domain_get (), method
->klass
, error
);
5613 return_val_if_nok (error
, NULL
);
5615 MonoObject
*boxed
= mono_value_box_checked (mono_domain_get (), m_class_get_cast_class (method
->klass
), obj
, error
);
5616 return_val_if_nok (error
, NULL
);
5617 mono_nullable_init ((guint8
*)mono_object_unbox_internal (nullable
), boxed
, method
->klass
);
5618 obj
= mono_object_unbox_internal (nullable
);
5622 /* obj must be already unboxed if needed */
5624 res
= mono_runtime_try_invoke (method
, obj
, pa
, exc
, error
);
5626 res
= mono_runtime_invoke_checked (method
, obj
, pa
, error
);
5628 return_val_if_nok (error
, NULL
);
5630 if (sig
->ret
->type
== MONO_TYPE_PTR
) {
5631 MonoClass
*pointer_class
;
5633 MonoObject
*box_exc
;
5636 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5637 * convert it to a Pointer object.
5639 pointer_class
= mono_class_get_pointer_class ();
5641 MONO_STATIC_POINTER_INIT (MonoMethod
, box_method
)
5642 box_method
= mono_class_get_method_from_name_checked (pointer_class
, "Box", -1, 0, error
);
5643 mono_error_assert_ok (error
);
5644 MONO_STATIC_POINTER_INIT_END (MonoMethod
, box_method
)
5646 g_assert (res
->vtable
->klass
== mono_defaults
.int_class
);
5647 box_args
[0] = ((MonoIntPtr
*)res
)->m_value
;
5648 if (sig
->ret
->byref
) {
5649 // byref is already unboxed by the invoke code
5650 MonoType
*tmpret
= mono_metadata_type_dup (NULL
, sig
->ret
);
5651 tmpret
->byref
= FALSE
;
5652 box_args
[1] = mono_type_get_object_checked (mono_domain_get (), tmpret
, error
);
5653 mono_metadata_free_type (tmpret
);
5655 box_args
[1] = mono_type_get_object_checked (mono_domain_get (), sig
->ret
, error
);
5657 return_val_if_nok (error
, NULL
);
5659 res
= mono_runtime_try_invoke (box_method
, NULL
, box_args
, &box_exc
, error
);
5660 g_assert (box_exc
== NULL
);
5661 mono_error_assert_ok (error
);
5664 if (has_byref_nullables
) {
5666 * The runtime invoke wrapper already converted byref nullables back,
5667 * and stored them in pa, we just need to copy them back to the
5670 for (i
= 0; i
< mono_array_length_internal (params
); i
++) {
5671 MonoType
*t
= sig
->params
[i
];
5673 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
5674 mono_array_setref_internal (params
, i
, pa
[i
]);
5682 // FIXME these will move to header soon
5683 static MonoObjectHandle
5684 mono_object_new_by_vtable (MonoVTable
*vtable
, MonoError
*error
);
5687 * object_new_common_tail:
5689 * This function centralizes post-processing of objects upon creation.
5690 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields,
5691 * and setting error.
5694 object_new_common_tail (MonoObject
*o
, MonoClass
*klass
, MonoError
*error
)
5698 if (G_UNLIKELY (!o
)) {
5699 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (klass
));
5703 if (G_UNLIKELY (m_class_has_finalize (klass
)))
5704 mono_object_register_finalizer (o
);
5706 if (G_UNLIKELY (m_class_has_weak_fields (klass
)))
5707 mono_gc_register_obj_with_weak_fields (o
);
5713 * object_new_handle_tail:
5715 * This function centralizes post-processing of objects upon creation.
5716 * i.e. calling mono_object_register_finalizer and mono_gc_register_obj_with_weak_fields.
5718 static MonoObjectHandle
5719 object_new_handle_common_tail (MonoObjectHandle o
, MonoClass
*klass
, MonoError
*error
)
5723 if (G_UNLIKELY (MONO_HANDLE_IS_NULL (o
))) {
5724 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (klass
));
5728 if (G_UNLIKELY (m_class_has_finalize (klass
)))
5729 mono_object_register_finalizer_handle (o
);
5731 if (G_UNLIKELY (m_class_has_weak_fields (klass
)))
5732 mono_gc_register_object_with_weak_fields (o
);
5739 * \param klass the class of the object that we want to create
5740 * \returns a newly created object whose definition is
5741 * looked up using \p klass. This will not invoke any constructors,
5742 * so the consumer of this routine has to invoke any constructors on
5743 * its own to initialize the object.
5745 * It returns NULL on failure.
5748 mono_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5750 MonoObject
* result
;
5751 MONO_ENTER_GC_UNSAFE
;
5753 result
= mono_object_new_checked (domain
, klass
, error
);
5754 mono_error_cleanup (error
);
5755 MONO_EXIT_GC_UNSAFE
;
5760 ves_icall_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5762 MONO_REQ_GC_UNSAFE_MODE
;
5766 MonoObject
* result
= mono_object_new_checked (domain
, klass
, error
);
5768 mono_error_set_pending_exception (error
);
5773 * mono_object_new_checked:
5774 * \param klass the class of the object that we want to create
5775 * \param error set on error
5776 * \returns a newly created object whose definition is
5777 * looked up using \p klass. This will not invoke any constructors,
5778 * so the consumer of this routine has to invoke any constructors on
5779 * its own to initialize the object.
5781 * It returns NULL on failure and sets \p error.
5784 mono_object_new_checked (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5786 MONO_REQ_GC_UNSAFE_MODE
;
5790 vtable
= mono_class_vtable_checked (domain
, klass
, error
);
5794 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
5799 * mono_object_new_handle:
5800 * \param klass the class of the object that we want to create
5801 * \param error set on error
5802 * \returns a newly created object whose definition is
5803 * looked up using \p klass. This will not invoke any constructors,
5804 * so the consumer of this routine has to invoke any constructors on
5805 * its own to initialize the object.
5807 * It returns NULL on failure and sets \p error.
5810 mono_object_new_handle (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5812 MONO_REQ_GC_UNSAFE_MODE
;
5814 MonoVTable
* const vtable
= mono_class_vtable_checked (domain
, klass
, error
);
5816 return_val_if_nok (error
, MONO_HANDLE_NEW (MonoObject
, NULL
));
5818 return mono_object_new_by_vtable (vtable
, error
);
5822 * mono_object_new_pinned:
5824 * Same as mono_object_new, but the returned object will be pinned.
5825 * For SGEN, these objects will only be freed at appdomain unload.
5828 mono_object_new_pinned_handle (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5830 MONO_REQ_GC_UNSAFE_MODE
;
5832 MonoVTable
* const vtable
= mono_class_vtable_checked (domain
, klass
, error
);
5833 return_val_if_nok (error
, MONO_HANDLE_NEW (MonoObject
, NULL
));
5835 g_assert (vtable
->klass
== klass
);
5837 int const size
= mono_class_instance_size (klass
);
5839 MonoObjectHandle o
= mono_gc_alloc_handle_pinned_obj (vtable
, size
);
5841 return object_new_handle_common_tail (o
, klass
, error
);
5845 mono_object_new_pinned (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5847 MONO_REQ_GC_UNSAFE_MODE
;
5851 vtable
= mono_class_vtable_checked (domain
, klass
, error
);
5852 return_val_if_nok (error
, NULL
);
5854 MonoObject
*o
= mono_gc_alloc_pinned_obj (vtable
, mono_class_instance_size (klass
));
5856 return object_new_common_tail (o
, klass
, error
);
5860 * mono_object_new_specific:
5861 * \param vtable the vtable of the object that we want to create
5862 * \returns A newly created object with class and domain specified
5866 mono_object_new_specific (MonoVTable
*vtable
)
5869 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
5870 mono_error_cleanup (error
);
5876 mono_object_new_specific_checked (MonoVTable
*vtable
, MonoError
*error
)
5878 MONO_REQ_GC_UNSAFE_MODE
;
5884 /* check for is_com_object for COM Interop */
5885 if (mono_vtable_is_remote (vtable
) || mono_class_is_com_object (vtable
->klass
))
5888 MonoMethod
*im
= vtable
->domain
->create_proxy_for_type_method
;
5891 MonoClass
*klass
= mono_class_get_activation_services_class ();
5893 if (!m_class_is_inited (klass
))
5894 mono_class_init_internal (klass
);
5896 im
= mono_class_get_method_from_name_checked (klass
, "CreateProxyForType", 1, 0, error
);
5897 return_val_if_nok (error
, NULL
);
5899 mono_error_set_not_supported (error
, "Linked away.");
5902 vtable
->domain
->create_proxy_for_type_method
= im
;
5905 pa
[0] = mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable
->klass
), error
);
5909 o
= mono_runtime_invoke_checked (im
, NULL
, pa
, error
);
5917 return mono_object_new_alloc_specific_checked (vtable
, error
);
5920 static MonoObjectHandle
5921 mono_object_new_by_vtable (MonoVTable
*vtable
, MonoError
*error
)
5923 // This function handles remoting and COM.
5924 // mono_object_new_alloc_by_vtable does not.
5926 MONO_REQ_GC_UNSAFE_MODE
;
5928 MonoObjectHandle o
= MONO_HANDLE_NEW (MonoObject
, NULL
);
5932 /* check for is_com_object for COM Interop */
5933 if (mono_vtable_is_remote (vtable
) || mono_class_is_com_object (vtable
->klass
))
5935 MonoMethod
*im
= vtable
->domain
->create_proxy_for_type_method
;
5938 MonoClass
*klass
= mono_class_get_activation_services_class ();
5940 if (!m_class_is_inited (klass
))
5941 mono_class_init_internal (klass
);
5943 im
= mono_class_get_method_from_name_checked (klass
, "CreateProxyForType", 1, 0, error
);
5944 return_val_if_nok (error
, mono_new_null ());
5946 mono_error_set_not_supported (error
, "Linked away.");
5947 return MONO_HANDLE_NEW (MonoObject
, NULL
);
5949 vtable
->domain
->create_proxy_for_type_method
= im
;
5953 gpointer pa
[ ] = { mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (vtable
->klass
), error
) };
5954 return_val_if_nok (error
, MONO_HANDLE_NEW (MonoObject
, NULL
));
5957 o
= MONO_HANDLE_NEW (MonoObject
, mono_runtime_invoke_checked (im
, NULL
, pa
, error
));
5958 return_val_if_nok (error
, MONO_HANDLE_NEW (MonoObject
, NULL
));
5960 if (!MONO_HANDLE_IS_NULL (o
))
5964 return mono_object_new_alloc_by_vtable (vtable
, error
);
5968 ves_icall_object_new_specific (MonoVTable
*vtable
)
5971 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
5972 mono_error_set_pending_exception (error
);
5978 * mono_object_new_alloc_specific:
5979 * \param vtable virtual table for the object.
5980 * This function allocates a new \c MonoObject with the type derived
5981 * from the \p vtable information. If the class of this object has a
5982 * finalizer, then the object will be tracked for finalization.
5984 * This method might raise an exception on errors. Use the
5985 * \c mono_object_new_fast_checked method if you want to manually raise
5988 * \returns the allocated object.
5991 mono_object_new_alloc_specific (MonoVTable
*vtable
)
5994 MonoObject
*o
= mono_object_new_alloc_specific_checked (vtable
, error
);
5995 mono_error_cleanup (error
);
6001 * mono_object_new_alloc_specific_checked:
6002 * \param vtable virtual table for the object.
6003 * \param error holds the error return value.
6005 * This function allocates a new \c MonoObject with the type derived
6006 * from the \p vtable information. If the class of this object has a
6007 * finalizer, then the object will be tracked for finalization.
6009 * If there is not enough memory, the \p error parameter will be set
6010 * and will contain a user-visible message with the amount of bytes
6011 * that were requested.
6013 * \returns the allocated object, or NULL if there is not enough memory
6016 mono_object_new_alloc_specific_checked (MonoVTable
*vtable
, MonoError
*error
)
6018 MONO_REQ_GC_UNSAFE_MODE
;
6020 MonoObject
*o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
6022 return object_new_common_tail (o
, vtable
->klass
, error
);
6026 mono_object_new_alloc_by_vtable (MonoVTable
*vtable
, MonoError
*error
)
6028 MONO_REQ_GC_UNSAFE_MODE
;
6030 MonoClass
* const klass
= vtable
->klass
;
6031 int const size
= m_class_get_instance_size (klass
);
6033 MonoObjectHandle o
= mono_gc_alloc_handle_obj (vtable
, size
);
6035 return object_new_handle_common_tail (o
, klass
, error
);
6039 * mono_object_new_fast:
6040 * \param vtable virtual table for the object.
6042 * This function allocates a new \c MonoObject with the type derived
6043 * from the \p vtable information. The returned object is not tracked
6044 * for finalization. If your object implements a finalizer, you should
6045 * use \c mono_object_new_alloc_specific instead.
6047 * This method might raise an exception on errors. Use the
6048 * \c mono_object_new_fast_checked method if you want to manually raise
6051 * \returns the allocated object.
6054 mono_object_new_fast (MonoVTable
*vtable
)
6058 MonoObject
*o
= mono_gc_alloc_obj (vtable
, m_class_get_instance_size (vtable
->klass
));
6060 // This deliberately skips object_new_common_tail.
6062 if (G_UNLIKELY (!o
))
6063 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", m_class_get_instance_size (vtable
->klass
));
6065 mono_error_cleanup (error
);
6071 mono_object_new_mature (MonoVTable
*vtable
, MonoError
*error
)
6073 MONO_REQ_GC_UNSAFE_MODE
;
6077 size
= m_class_get_instance_size (vtable
->klass
);
6079 #if MONO_CROSS_COMPILE
6080 /* In cross compile mode, we should only allocate thread objects */
6081 /* The instance size refers to the target arch, this should be safe enough */
6085 MonoObject
*o
= mono_gc_alloc_mature (vtable
, size
);
6087 return object_new_common_tail (o
, vtable
->klass
, error
);
6091 mono_object_new_handle_mature (MonoVTable
*vtable
, MonoError
*error
)
6093 MONO_REQ_GC_UNSAFE_MODE
;
6095 MonoClass
* const klass
= vtable
->klass
;
6096 int const size
= m_class_get_instance_size (klass
);
6098 MonoObjectHandle o
= mono_gc_alloc_handle_mature (vtable
, size
);
6100 return object_new_handle_common_tail (o
, klass
, error
);
6104 * mono_object_new_from_token:
6105 * \param image Context where the type_token is hosted
6106 * \param token a token of the type that we want to create
6107 * \returns A newly created object whose definition is
6108 * looked up using \p token in the \p image image
6111 mono_object_new_from_token (MonoDomain
*domain
, MonoImage
*image
, guint32 token
)
6113 MONO_REQ_GC_UNSAFE_MODE
;
6115 HANDLE_FUNCTION_ENTER ();
6120 klass
= mono_class_get_checked (image
, token
, error
);
6121 mono_error_assert_ok (error
);
6123 MonoObjectHandle result
= mono_object_new_handle (domain
, klass
, error
);
6125 mono_error_cleanup (error
);
6127 HANDLE_FUNCTION_RETURN_OBJ (result
);
6131 * mono_object_clone:
6132 * \param obj the object to clone
6133 * \returns A newly created object who is a shallow copy of \p obj
6136 mono_object_clone (MonoObject
*obj
)
6139 MonoObject
*o
= mono_object_clone_checked (obj
, error
);
6140 mono_error_cleanup (error
);
6146 mono_object_clone_checked (MonoObject
*obj_raw
, MonoError
*error
)
6148 MONO_REQ_GC_UNSAFE_MODE
;
6149 HANDLE_FUNCTION_ENTER ();
6150 MONO_HANDLE_DCL (MonoObject
, obj
);
6151 HANDLE_FUNCTION_RETURN_OBJ (mono_object_clone_handle (obj
, error
));
6155 mono_object_clone_handle (MonoObjectHandle obj
, MonoError
*error
)
6157 MONO_REQ_GC_UNSAFE_MODE
;
6159 MonoVTable
* const vtable
= MONO_HANDLE_GETVAL (obj
, vtable
);
6160 MonoClass
* const klass
= vtable
->klass
;
6162 if (m_class_get_rank (klass
))
6163 return MONO_HANDLE_CAST (MonoObject
, mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (obj
),
6164 MONO_HANDLE_CAST (MonoArray
, obj
), error
));
6166 int const size
= m_class_get_instance_size (klass
);
6168 MonoObjectHandle o
= mono_gc_alloc_handle_obj (vtable
, size
);
6170 if (G_LIKELY (!MONO_HANDLE_IS_NULL (o
))) {
6171 /* If the object doesn't contain references this will do a simple memmove. */
6172 mono_gc_wbarrier_object_copy_handle (o
, obj
);
6175 return object_new_handle_common_tail (o
, klass
, error
);
6179 * mono_array_full_copy:
6180 * \param src source array to copy
6181 * \param dest destination array
6182 * Copies the content of one array to another with exactly the same type and size.
6185 mono_array_full_copy (MonoArray
*src
, MonoArray
*dest
)
6187 MONO_REQ_GC_UNSAFE_MODE
;
6190 MonoClass
*klass
= mono_object_class (&src
->obj
);
6192 g_assert (klass
== mono_object_class (&dest
->obj
));
6194 size
= mono_array_length_internal (src
);
6195 g_assert (size
== mono_array_length_internal (dest
));
6196 size
*= mono_array_element_size (klass
);
6198 array_full_copy_unchecked_size (src
, dest
, klass
, size
);
6202 array_full_copy_unchecked_size (MonoArray
*src
, MonoArray
*dest
, MonoClass
*klass
, uintptr_t size
)
6204 if (mono_gc_is_moving ()) {
6205 MonoClass
*element_class
= m_class_get_element_class (klass
);
6206 if (m_class_is_valuetype (element_class
)) {
6207 if (m_class_has_references (element_class
))
6208 mono_value_copy_array_internal (dest
, 0, mono_array_addr_with_size_fast (src
, 0, 0), mono_array_length_internal (src
));
6210 mono_gc_memmove_atomic (&dest
->vector
, &src
->vector
, size
);
6212 mono_array_memcpy_refs_internal
6213 (dest
, 0, src
, 0, mono_array_length_internal (src
));
6216 mono_gc_memmove_atomic (&dest
->vector
, &src
->vector
, size
);
6221 * mono_array_clone_in_domain:
6222 * \param domain the domain in which the array will be cloned into
6223 * \param array the array to clone
6224 * \param error set on error
6225 * This routine returns a copy of the array that is hosted on the
6226 * specified \c MonoDomain. On failure returns NULL and sets \p error.
6229 mono_array_clone_in_domain (MonoDomain
*domain
, MonoArrayHandle array_handle
, MonoError
*error
)
6231 MONO_REQ_GC_UNSAFE_MODE
;
6233 MonoArrayHandle result
= MONO_HANDLE_NEW (MonoArray
, NULL
);
6235 MonoClass
*klass
= mono_handle_class (array_handle
);
6239 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
6240 uint32_t src_handle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, array_handle
), TRUE
);
6242 MonoArrayBounds
*array_bounds
= MONO_HANDLE_GETVAL (array_handle
, bounds
);
6244 if (array_bounds
== NULL
) {
6245 size
= mono_array_handle_length (array_handle
);
6246 o
= mono_array_new_full_handle (domain
, klass
, &size
, NULL
, error
);
6247 goto_if_nok (error
, leave
);
6248 size
*= mono_array_element_size (klass
);
6250 guint8 klass_rank
= m_class_get_rank (klass
);
6251 uintptr_t *sizes
= g_newa (uintptr_t, klass_rank
);
6252 intptr_t *lower_bounds
= g_newa (intptr_t, klass_rank
);
6253 size
= mono_array_element_size (klass
);
6254 for (int i
= 0; i
< klass_rank
; ++i
) {
6255 sizes
[i
] = array_bounds
[i
].length
;
6256 size
*= array_bounds
[i
].length
;
6257 lower_bounds
[i
] = array_bounds
[i
].lower_bound
;
6259 o
= mono_array_new_full_handle (domain
, klass
, sizes
, lower_bounds
, error
);
6260 goto_if_nok (error
, leave
);
6263 uint32_t dst_handle
;
6264 dst_handle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, o
), TRUE
);
6265 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle
), MONO_HANDLE_RAW (o
), klass
, size
);
6266 mono_gchandle_free_internal (dst_handle
);
6268 MONO_HANDLE_ASSIGN (result
, o
);
6271 mono_gchandle_free_internal (src_handle
);
6277 * \param array the array to clone
6278 * \returns A newly created array who is a shallow copy of \p array
6281 mono_array_clone (MonoArray
*array
)
6283 MONO_REQ_GC_UNSAFE_MODE
;
6286 MonoArray
*result
= mono_array_clone_checked (array
, error
);
6287 mono_error_cleanup (error
);
6292 * mono_array_clone_checked:
6293 * \param array the array to clone
6294 * \param error set on error
6295 * \returns A newly created array who is a shallow copy of \p array. On
6296 * failure returns NULL and sets \p error.
6299 mono_array_clone_checked (MonoArray
*array_raw
, MonoError
*error
)
6301 MONO_REQ_GC_UNSAFE_MODE
;
6302 HANDLE_FUNCTION_ENTER ();
6303 /* FIXME: callers of mono_array_clone_checked should use handles */
6305 MONO_HANDLE_DCL (MonoArray
, array
);
6306 MonoArrayHandle result
= mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array
), array
, error
);
6307 HANDLE_FUNCTION_RETURN_OBJ (result
);
6310 /* helper macros to check for overflow when calculating the size of arrays */
6311 #ifdef MONO_BIG_ARRAYS
6312 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
6313 #define MYGUINT_MAX MYGUINT64_MAX
6314 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6315 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
6316 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6317 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
6318 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
6320 #define MYGUINT32_MAX 4294967295U
6321 #define MYGUINT_MAX MYGUINT32_MAX
6322 #define CHECK_ADD_OVERFLOW_UN(a,b) \
6323 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
6324 #define CHECK_MUL_OVERFLOW_UN(a,b) \
6325 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
6326 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
6330 mono_array_calc_byte_len (MonoClass
*klass
, uintptr_t len
, uintptr_t *res
)
6332 MONO_REQ_GC_NEUTRAL_MODE
;
6336 byte_len
= mono_array_element_size (klass
);
6337 if (CHECK_MUL_OVERFLOW_UN (byte_len
, len
))
6340 if (CHECK_ADD_OVERFLOW_UN (byte_len
, MONO_SIZEOF_MONO_ARRAY
))
6342 byte_len
+= MONO_SIZEOF_MONO_ARRAY
;
6350 * mono_array_new_full:
6351 * \param domain domain where the object is created
6352 * \param array_class array class
6353 * \param lengths lengths for each dimension in the array
6354 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
6355 * This routine creates a new array object with the given dimensions,
6356 * lower bounds and type.
6359 mono_array_new_full (MonoDomain
*domain
, MonoClass
*array_class
, uintptr_t *lengths
, intptr_t *lower_bounds
)
6362 MonoArray
*array
= mono_array_new_full_checked (domain
, array_class
, lengths
, lower_bounds
, error
);
6363 mono_error_cleanup (error
);
6369 mono_array_new_full_checked (MonoDomain
*domain
, MonoClass
*array_class
, uintptr_t *lengths
, intptr_t *lower_bounds
, MonoError
*error
)
6371 MONO_REQ_GC_UNSAFE_MODE
;
6373 uintptr_t byte_len
= 0, len
, bounds_size
;
6376 MonoArrayBounds
*bounds
;
6382 if (!m_class_is_inited (array_class
))
6383 mono_class_init_internal (array_class
);
6387 guint8 array_class_rank
= m_class_get_rank (array_class
);
6388 /* A single dimensional array with a 0 lower bound is the same as an szarray */
6389 if (array_class_rank
== 1 && ((m_class_get_byval_arg (array_class
)->type
== MONO_TYPE_SZARRAY
) || (lower_bounds
&& lower_bounds
[0] == 0))) {
6391 if (len
> MONO_ARRAY_MAX_INDEX
) {
6392 mono_error_set_generic_error (error
, "System", "OverflowException", "");
6397 bounds_size
= sizeof (MonoArrayBounds
) * array_class_rank
;
6399 for (i
= 0; i
< array_class_rank
; ++i
) {
6400 if (lengths
[i
] > MONO_ARRAY_MAX_INDEX
) {
6401 mono_error_set_generic_error (error
, "System", "OverflowException", "");
6404 if (CHECK_MUL_OVERFLOW_UN (len
, lengths
[i
])) {
6405 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
6412 if (!mono_array_calc_byte_len (array_class
, len
, &byte_len
)) {
6413 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
6419 if (CHECK_ADD_OVERFLOW_UN (byte_len
, 3)) {
6420 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
6423 byte_len
= (byte_len
+ 3) & ~3;
6424 if (CHECK_ADD_OVERFLOW_UN (byte_len
, bounds_size
)) {
6425 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
6428 byte_len
+= bounds_size
;
6431 * Following three lines almost taken from mono_object_new ():
6432 * they need to be kept in sync.
6434 vtable
= mono_class_vtable_checked (domain
, array_class
, error
);
6435 return_val_if_nok (error
, NULL
);
6438 o
= (MonoObject
*)mono_gc_alloc_array (vtable
, byte_len
, len
, bounds_size
);
6440 o
= (MonoObject
*)mono_gc_alloc_vector (vtable
, byte_len
, len
);
6442 if (G_UNLIKELY (!o
)) {
6443 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
"d bytes", (gsize
) byte_len
);
6447 array
= (MonoArray
*)o
;
6449 bounds
= array
->bounds
;
6452 for (i
= 0; i
< array_class_rank
; ++i
) {
6453 bounds
[i
].length
= lengths
[i
];
6455 bounds
[i
].lower_bound
= lower_bounds
[i
];
6464 * \param domain domain where the object is created
6465 * \param eclass element class
6466 * \param n number of array elements
6467 * This routine creates a new szarray with \p n elements of type \p eclass.
6470 mono_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
6473 MONO_ENTER_GC_UNSAFE
;
6476 result
= mono_array_new_checked (domain
, eclass
, n
, error
);
6477 mono_error_cleanup (error
);
6478 MONO_EXIT_GC_UNSAFE
;
6483 * mono_array_new_checked:
6484 * \param domain domain where the object is created
6485 * \param eclass element class
6486 * \param n number of array elements
6487 * \param error set on error
6488 * This routine creates a new szarray with \p n elements of type \p eclass.
6489 * On failure returns NULL and sets \p error.
6492 mono_array_new_checked (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
, MonoError
*error
)
6498 ac
= mono_class_create_array (eclass
, 1);
6501 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, ac
, error
);
6502 return_val_if_nok (error
, NULL
);
6504 return mono_array_new_specific_checked (vtable
, n
, error
);
6508 ves_icall_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
6511 MonoArray
*arr
= mono_array_new_checked (domain
, eclass
, n
, error
);
6512 mono_error_set_pending_exception (error
);
6518 * mono_array_new_specific:
6519 * \param vtable a vtable in the appropriate domain for an initialized class
6520 * \param n number of array elements
6521 * This routine is a fast alternative to \c mono_array_new for code which
6522 * can be sure about the domain it operates in.
6525 mono_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
6528 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, error
);
6529 mono_error_cleanup (error
);
6535 mono_array_new_specific_checked (MonoVTable
*vtable
, uintptr_t n
, MonoError
*error
)
6537 MONO_REQ_GC_UNSAFE_MODE
;
6544 if (G_UNLIKELY (n
> MONO_ARRAY_MAX_INDEX
)) {
6545 mono_error_set_generic_error (error
, "System", "OverflowException", "");
6549 if (!mono_array_calc_byte_len (vtable
->klass
, n
, &byte_len
)) {
6550 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
6553 o
= (MonoObject
*)mono_gc_alloc_vector (vtable
, byte_len
, n
);
6555 if (G_UNLIKELY (!o
)) {
6556 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
"d bytes", (gsize
) byte_len
);
6560 return (MonoArray
*)o
;
6565 mono_array_new_specific_handle (MonoVTable
*vtable
, uintptr_t n
, MonoError
*error
)
6567 // FIXMEcoop invert relationship with mono_array_new_specific_checked
6568 return MONO_HANDLE_NEW (MonoArray
, mono_array_new_specific_checked (vtable
, n
, error
));
6572 ves_icall_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
6575 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, error
);
6576 mono_error_set_pending_exception (error
);
6582 * mono_string_empty_wrapper:
6584 * Returns: The same empty string instance as the managed string.Empty
6587 mono_string_empty_wrapper (void)
6589 MonoDomain
*domain
= mono_domain_get ();
6590 return mono_string_empty_internal (domain
);
6594 mono_string_empty_internal (MonoDomain
*domain
)
6597 g_assert (domain
->empty_string
);
6598 return domain
->empty_string
;
6602 * mono_string_empty:
6604 * Returns: The same empty string instance as the managed string.Empty
6607 mono_string_empty (MonoDomain
*domain
)
6609 MONO_EXTERNAL_ONLY (MonoString
*, mono_string_empty_internal (domain
));
6613 mono_string_empty_handle (MonoDomain
*domain
)
6615 return MONO_HANDLE_NEW (MonoString
, mono_string_empty_internal (domain
));
6619 * mono_string_new_utf16:
6620 * \param text a pointer to an utf16 string
6621 * \param len the length of the string
6622 * \returns A newly created string object which contains \p text.
6625 mono_string_new_utf16 (MonoDomain
*domain
, const mono_unichar2
*text
, gint32 len
)
6627 MonoString
*res
= NULL
;
6628 MONO_ENTER_GC_UNSAFE
;
6630 res
= mono_string_new_utf16_checked (domain
, text
, len
, error
);
6631 mono_error_cleanup (error
);
6632 MONO_EXIT_GC_UNSAFE
;
6637 * mono_string_new_utf16_checked:
6638 * \param text a pointer to an utf16 string
6639 * \param len the length of the string
6640 * \param error written on error.
6641 * \returns A newly created string object which contains \p text.
6642 * On error, returns NULL and sets \p error.
6645 mono_string_new_utf16_checked (MonoDomain
*domain
, const gunichar2
*text
, gint32 len
, MonoError
*error
)
6647 MONO_REQ_GC_UNSAFE_MODE
;
6653 s
= mono_string_new_size_checked (domain
, len
, error
);
6655 memcpy (mono_string_chars_internal (s
), text
, len
* 2);
6661 * mono_string_new_utf16_handle:
6662 * \param text a pointer to an utf16 string
6663 * \param len the length of the string
6664 * \param error written on error.
6665 * \returns A newly created string object which contains \p text.
6666 * On error, returns NULL and sets \p error.
6669 mono_string_new_utf16_handle (MonoDomain
*domain
, const gunichar2
*text
, gint32 len
, MonoError
*error
)
6671 return MONO_HANDLE_NEW (MonoString
, mono_string_new_utf16_checked (domain
, text
, len
, error
));
6675 * mono_string_new_utf32_checked:
6676 * \param text a pointer to an utf32 string
6677 * \param len the length of the string
6678 * \param error set on failure.
6679 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6682 mono_string_new_utf32_checked (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
, MonoError
*error
)
6684 MONO_REQ_GC_UNSAFE_MODE
;
6687 mono_unichar2
*utf16_output
= NULL
;
6690 utf16_output
= g_ucs4_to_utf16 (text
, len
, NULL
, NULL
, NULL
);
6692 gint32 utf16_len
= g_utf16_len (utf16_output
);
6694 s
= mono_string_new_size_checked (domain
, utf16_len
, error
);
6695 goto_if_nok (error
, exit
);
6697 memcpy (mono_string_chars_internal (s
), utf16_output
, utf16_len
* 2);
6700 g_free (utf16_output
);
6706 * mono_string_new_utf32:
6707 * \param text a pointer to a UTF-32 string
6708 * \param len the length of the string
6709 * \returns A newly created string object which contains \p text.
6712 mono_string_new_utf32 (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
)
6715 MonoString
*result
= mono_string_new_utf32_checked (domain
, text
, len
, error
);
6716 mono_error_cleanup (error
);
6721 * mono_string_new_size:
6722 * \param text a pointer to a UTF-16 string
6723 * \param len the length of the string
6724 * \returns A newly created string object of \p len
6727 mono_string_new_size (MonoDomain
*domain
, gint32 len
)
6730 MONO_ENTER_GC_UNSAFE
;
6732 str
= mono_string_new_size_checked (domain
, len
, error
);
6733 mono_error_cleanup (error
);
6734 MONO_EXIT_GC_UNSAFE
;
6739 mono_string_new_size_handle (MonoDomain
*domain
, gint32 len
, MonoError
*error
)
6741 MONO_REQ_GC_UNSAFE_MODE
;
6749 /* check for overflow */
6750 if (len
< 0 || len
> ((SIZE_MAX
- G_STRUCT_OFFSET (MonoString
, chars
) - 8) / 2)) {
6751 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", -1);
6752 return NULL_HANDLE_STRING
;
6755 size
= (G_STRUCT_OFFSET (MonoString
, chars
) + (((size_t)len
+ 1) * 2));
6756 g_assert (size
> 0);
6758 vtable
= mono_class_vtable_checked (domain
, mono_defaults
.string_class
, error
);
6759 return_val_if_nok (error
, NULL_HANDLE_STRING
);
6761 s
= mono_gc_alloc_handle_string (vtable
, size
, len
);
6763 if (G_UNLIKELY (MONO_HANDLE_IS_NULL (s
)))
6764 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
" bytes", size
);
6770 mono_string_new_size_checked (MonoDomain
*domain
, gint32 length
, MonoError
*error
)
6772 HANDLE_FUNCTION_ENTER ();
6773 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_size_handle (domain
, length
, error
));
6777 * mono_string_new_len:
6778 * \param text a pointer to an utf8 string
6779 * \param length number of bytes in \p text to consider
6780 * \returns A newly created string object which contains \p text.
6783 mono_string_new_len (MonoDomain
*domain
, const char *text
, guint length
)
6785 HANDLE_FUNCTION_ENTER ();
6787 MonoStringHandle result
;
6789 MONO_ENTER_GC_UNSAFE
;
6790 result
= mono_string_new_utf8_len (domain
, text
, length
, error
);
6791 MONO_EXIT_GC_UNSAFE
;
6793 mono_error_cleanup (error
);
6794 HANDLE_FUNCTION_RETURN_OBJ (result
);
6798 * mono_string_new_utf8_len:
6799 * \param text a pointer to an utf8 string
6800 * \param length number of bytes in \p text to consider
6801 * \param error set on error
6802 * \returns A newly created string object which contains \p text. On
6803 * failure returns NULL and sets \p error.
6806 mono_string_new_utf8_len (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6808 MONO_REQ_GC_UNSAFE_MODE
;
6812 GError
*eg_error
= NULL
;
6813 MonoStringHandle o
= NULL_HANDLE_STRING
;
6814 gunichar2
*ut
= NULL
;
6815 glong items_written
;
6817 ut
= eg_utf8_to_utf16_with_nuls (text
, length
, NULL
, &items_written
, &eg_error
);
6820 o
= NULL_HANDLE_STRING
;
6821 // Like mono_ldstr_utf8:
6822 mono_error_set_argument (error
, "string", eg_error
->message
);
6823 // FIXME? See mono_string_new_checked.
6824 //mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6825 g_error_free (eg_error
);
6827 o
= mono_string_new_utf16_handle (domain
, ut
, items_written
, error
);
6836 mono_string_new_len_checked (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6838 HANDLE_FUNCTION_ENTER ();
6840 HANDLE_FUNCTION_RETURN_OBJ (mono_string_new_utf8_len (domain
, text
, length
, error
));
6845 mono_string_new_internal (MonoDomain
*domain
, const char *text
)
6848 MonoString
*res
= NULL
;
6849 res
= mono_string_new_checked (domain
, text
, error
);
6850 if (!is_ok (error
)) {
6851 /* Mono API compatability: assert on Out of Memory errors,
6852 * return NULL otherwise (most likely an invalid UTF-8 byte
6854 if (mono_error_get_error_code (error
) == MONO_ERROR_OUT_OF_MEMORY
)
6855 mono_error_assert_ok (error
);
6857 mono_error_cleanup (error
);
6864 * \param text a pointer to a UTF-8 string
6865 * \deprecated Use \c mono_string_new_checked in new code.
6866 * This function asserts if it cannot allocate a new string.
6867 * \returns A newly created string object which contains \p text.
6870 mono_string_new (MonoDomain
*domain
, const char *text
)
6872 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoString
*, mono_string_new_internal (domain
, text
));
6876 * mono_string_new_checked:
6877 * \param text a pointer to an utf8 string
6878 * \param merror set on error
6879 * \returns A newly created string object which contains \p text.
6880 * On error returns NULL and sets \p merror.
6883 mono_string_new_checked (MonoDomain
*domain
, const char *text
, MonoError
*error
)
6885 MONO_REQ_GC_UNSAFE_MODE
;
6887 GError
*eg_error
= NULL
;
6888 MonoString
*o
= NULL
;
6890 glong items_written
;
6895 len
= strlen (text
);
6897 ut
= g_utf8_to_utf16 (text
, len
, NULL
, &items_written
, &eg_error
);
6900 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6902 mono_error_set_execution_engine (error
, "String conversion error: %s", eg_error
->message
);
6903 g_error_free (eg_error
);
6908 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6913 MonoString
*o
= NULL
;
6915 if (!g_utf8_validate (text
, -1, &end
)) {
6916 mono_error_set_argument (error
, "text", "Not a valid utf8 string");
6920 len
= g_utf8_strlen (text
, -1);
6921 o
= mono_string_new_size_checked (domain
, len
, error
);
6924 str
= mono_string_chars_internal (o
);
6926 while (text
< end
) {
6927 *str
++ = g_utf8_get_char (text
);
6928 text
= g_utf8_next_char (text
);
6937 * mono_string_new_wtf8_len_checked:
6938 * \param text a pointer to an wtf8 string (see https://simonsapin.github.io/wtf-8/)
6939 * \param length number of bytes in \p text to consider
6940 * \param merror set on error
6941 * \returns A newly created string object which contains \p text.
6942 * On error returns NULL and sets \p merror.
6945 mono_string_new_wtf8_len_checked (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6947 MONO_REQ_GC_UNSAFE_MODE
;
6951 GError
*eg_error
= NULL
;
6952 MonoString
*o
= NULL
;
6953 gunichar2
*ut
= NULL
;
6954 glong items_written
;
6956 ut
= eg_wtf8_to_utf16 (text
, length
, NULL
, &items_written
, &eg_error
);
6959 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6961 g_error_free (eg_error
);
6969 mono_string_new_wrapper_internal_impl (const char *text
, MonoError
*error
)
6971 return MONO_HANDLE_NEW (MonoString
, mono_string_new_internal (mono_domain_get (), text
));
6975 * mono_string_new_wrapper:
6976 * \param text pointer to UTF-8 characters.
6977 * Helper function to create a string object from \p text in the current domain.
6980 mono_string_new_wrapper (const char *text
)
6982 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoString
*, mono_string_new_wrapper_internal (text
));
6987 * \param class the class of the value
6988 * \param value a pointer to the unboxed data
6989 * \returns A newly created object which contains \p value.
6992 mono_value_box (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
)
6995 MONO_ENTER_GC_UNSAFE
;
6997 result
= mono_value_box_checked (domain
, klass
, value
, error
);
6998 mono_error_cleanup (error
);
6999 MONO_EXIT_GC_UNSAFE
;
7004 * mono_value_box_handle:
7005 * \param domain the domain of the new object
7006 * \param class the class of the value
7007 * \param value a pointer to the unboxed data
7008 * \param error set on error
7009 * \returns A newly created object which contains \p value. On failure
7010 * returns NULL and sets \p error.
7013 mono_value_box_handle (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
, MonoError
*error
)
7015 // FIXMEcoop gpointer value needs more attention
7016 MONO_REQ_GC_UNSAFE_MODE
;
7021 g_assert (m_class_is_valuetype (klass
));
7022 g_assert (value
!= NULL
);
7023 if (G_UNLIKELY (m_class_is_byreflike (klass
))) {
7024 char *full_name
= mono_type_get_full_name (klass
);
7025 mono_error_set_execution_engine (error
, "Cannot box IsByRefLike type %s", full_name
);
7029 if (mono_class_is_nullable (klass
))
7030 return mono_nullable_box_handle (value
, klass
, error
);
7032 vtable
= mono_class_vtable_checked (domain
, klass
, error
);
7033 return_val_if_nok (error
, NULL_HANDLE
);
7035 int size
= mono_class_instance_size (klass
);
7037 MonoObjectHandle res_handle
= mono_object_new_alloc_by_vtable (vtable
, error
);
7038 return_val_if_nok (error
, NULL_HANDLE
);
7040 size
-= MONO_ABI_SIZEOF (MonoObject
);
7041 if (mono_gc_is_moving ()) {
7042 g_assert (size
== mono_class_value_size (klass
, NULL
));
7043 MONO_ENTER_NO_SAFEPOINTS
;
7044 gpointer data
= mono_handle_get_data_unsafe (res_handle
);
7045 mono_gc_wbarrier_value_copy_internal (data
, value
, 1, klass
);
7046 MONO_EXIT_NO_SAFEPOINTS
;
7048 MONO_ENTER_NO_SAFEPOINTS
;
7049 gpointer data
= mono_handle_get_data_unsafe (res_handle
);
7050 #if NO_UNALIGNED_ACCESS
7051 mono_gc_memmove_atomic (data
, value
, size
);
7055 *(guint8
*)data
= *(guint8
*) value
;
7058 *(guint16
*)(data
) = *(guint16
*) value
;
7061 *(guint32
*)(data
) = *(guint32
*) value
;
7064 *(guint64
*)(data
) = *(guint64
*) value
;
7067 mono_gc_memmove_atomic (data
, value
, size
);
7070 MONO_EXIT_NO_SAFEPOINTS
;
7072 if (m_class_has_finalize (klass
))
7073 mono_object_register_finalizer_handle (res_handle
);
7079 * mono_value_box_checked:
7080 * \param domain the domain of the new object
7081 * \param class the class of the value
7082 * \param value a pointer to the unboxed data
7083 * \param error set on error
7084 * \returns A newly created object which contains \p value. On failure
7085 * returns NULL and sets \p error.
7088 mono_value_box_checked (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
, MonoError
*error
)
7090 HANDLE_FUNCTION_ENTER ();
7091 HANDLE_FUNCTION_RETURN_OBJ (mono_value_box_handle (domain
, klass
, value
, error
));
7095 mono_value_copy_internal (gpointer dest
, gconstpointer src
, MonoClass
*klass
)
7097 MONO_REQ_GC_UNSAFE_MODE
;
7099 mono_gc_wbarrier_value_copy_internal (dest
, src
, 1, klass
);
7104 * \param dest destination pointer
7105 * \param src source pointer
7106 * \param klass a valuetype class
7107 * Copy a valuetype from \p src to \p dest. This function must be used
7108 * when \p klass contains reference fields.
7111 mono_value_copy (gpointer dest
, gpointer src
, MonoClass
*klass
)
7113 mono_value_copy_internal (dest
, src
, klass
);
7117 mono_value_copy_array_internal (MonoArray
*dest
, int dest_idx
, gconstpointer src
, int count
)
7119 MONO_REQ_GC_UNSAFE_MODE
;
7121 int size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
7122 char *d
= mono_array_addr_with_size_fast (dest
, size
, dest_idx
);
7123 g_assert (size
== mono_class_value_size (m_class_get_element_class (mono_object_class (dest
)), NULL
));
7124 // FIXME remove (gpointer) cast.
7125 mono_gc_wbarrier_value_copy_internal (d
, (gpointer
)src
, count
, m_class_get_element_class (mono_object_class (dest
)));
7129 mono_value_copy_array_handle (MonoArrayHandle dest
, int dest_idx
, gconstpointer src
, int count
)
7131 mono_value_copy_array_internal (MONO_HANDLE_RAW (dest
), dest_idx
, src
, count
);
7135 * mono_value_copy_array:
7136 * \param dest destination array
7137 * \param dest_idx index in the \p dest array
7138 * \param src source pointer
7139 * \param count number of items
7140 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
7141 * This function must be used when \p klass contains references fields.
7142 * Overlap is handled.
7145 mono_value_copy_array (MonoArray
*dest
, int dest_idx
, void* src
, int count
)
7147 MONO_EXTERNAL_ONLY_VOID (mono_value_copy_array_internal (dest
, dest_idx
, src
, count
));
7151 mono_object_get_vtable_internal (MonoObject
*obj
)
7153 // This could be called during STW, so untag the vtable if needed.
7154 return mono_gc_get_vtable (obj
);
7158 mono_object_get_vtable (MonoObject
*obj
)
7160 MONO_EXTERNAL_ONLY (MonoVTable
*, mono_object_get_vtable_internal (obj
));
7164 mono_object_get_domain_internal (MonoObject
*obj
)
7166 MONO_REQ_GC_UNSAFE_MODE
;
7168 return mono_object_domain (obj
);
7172 * mono_object_get_domain:
7173 * \param obj object to query
7174 * \returns the \c MonoDomain where the object is hosted
7177 mono_object_get_domain (MonoObject
*obj
)
7179 MonoDomain
* ret
= NULL
;
7180 MONO_ENTER_GC_UNSAFE
;
7181 ret
= mono_object_get_domain_internal (obj
);
7182 MONO_EXIT_GC_UNSAFE
;
7187 * mono_object_get_class:
7188 * \param obj object to query
7189 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
7190 * \returns the \c MonoClass of the object.
7193 mono_object_get_class (MonoObject
*obj
)
7195 MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoClass
*, mono_object_class (obj
));
7199 mono_object_get_size_internal (MonoObject
* o
)
7201 MONO_REQ_GC_UNSAFE_MODE
;
7203 MonoClass
* klass
= mono_object_class (o
);
7204 if (klass
== mono_defaults
.string_class
) {
7205 return MONO_SIZEOF_MONO_STRING
+ 2 * mono_string_length_internal ((MonoString
*) o
) + 2;
7206 } else if (o
->vtable
->rank
) {
7207 MonoArray
*array
= (MonoArray
*)o
;
7208 size_t size
= MONO_SIZEOF_MONO_ARRAY
+ mono_array_element_size (klass
) * mono_array_length_internal (array
);
7209 if (array
->bounds
) {
7212 size
+= sizeof (MonoArrayBounds
) * o
->vtable
->rank
;
7216 return mono_class_instance_size (klass
);
7221 * mono_object_get_size:
7222 * \param o object to query
7223 * \returns the size, in bytes, of \p o
7226 mono_object_get_size (MonoObject
*o
)
7228 MONO_EXTERNAL_ONLY (unsigned, mono_object_get_size_internal (o
));
7232 * mono_object_unbox:
7233 * \param obj object to unbox
7234 * \returns a pointer to the start of the valuetype boxed in this
7237 * This method will assert if the object passed is not a valuetype.
7240 mono_object_unbox (MonoObject
*obj
)
7242 MONO_EXTERNAL_ONLY_GC_UNSAFE (void*, mono_object_unbox_internal (obj
));
7246 * mono_object_isinst:
7247 * \param obj an object
7248 * \param klass a pointer to a class
7249 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
7252 mono_object_isinst (MonoObject
*obj_raw
, MonoClass
*klass
)
7254 HANDLE_FUNCTION_ENTER ();
7255 MonoObjectHandle result
;
7256 MONO_ENTER_GC_UNSAFE
;
7258 MONO_HANDLE_DCL (MonoObject
, obj
);
7260 result
= mono_object_handle_isinst (obj
, klass
, error
);
7261 mono_error_cleanup (error
);
7262 MONO_EXIT_GC_UNSAFE
;
7263 HANDLE_FUNCTION_RETURN_OBJ (result
);
7267 * mono_object_isinst_checked:
7268 * \param obj an object
7269 * \param klass a pointer to a class
7270 * \param error set on error
7271 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7272 * On failure returns NULL and sets \p error.
7275 mono_object_isinst_checked (MonoObject
*obj_raw
, MonoClass
*klass
, MonoError
*error
)
7277 MONO_REQ_GC_UNSAFE_MODE
;
7279 HANDLE_FUNCTION_ENTER ();
7281 MONO_HANDLE_DCL (MonoObject
, obj
);
7282 MonoObjectHandle result
= mono_object_handle_isinst (obj
, klass
, error
);
7283 HANDLE_FUNCTION_RETURN_OBJ (result
);
7287 * mono_object_handle_isinst:
7288 * \param obj an object
7289 * \param klass a pointer to a class
7290 * \param error set on error
7291 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
7292 * On failure returns NULL and sets \p error.
7295 mono_object_handle_isinst (MonoObjectHandle obj
, MonoClass
*klass
, MonoError
*error
)
7299 if (!m_class_is_inited (klass
))
7300 mono_class_init_internal (klass
);
7302 if (mono_class_is_marshalbyref (klass
) || mono_class_is_interface (klass
)) {
7303 return mono_object_handle_isinst_mbyref (obj
, klass
, error
);
7306 MonoObjectHandle result
= MONO_HANDLE_NEW (MonoObject
, NULL
);
7308 if (!MONO_HANDLE_IS_NULL (obj
) && mono_class_is_assignable_from_internal (klass
, mono_handle_class (obj
)))
7309 MONO_HANDLE_ASSIGN (result
, obj
);
7314 * mono_object_isinst_mbyref:
7317 mono_object_isinst_mbyref (MonoObject
*obj_raw
, MonoClass
*klass
)
7319 MONO_REQ_GC_UNSAFE_MODE
;
7321 HANDLE_FUNCTION_ENTER ();
7323 MONO_HANDLE_DCL (MonoObject
, obj
);
7324 MonoObjectHandle result
= mono_object_handle_isinst_mbyref (obj
, klass
, error
);
7325 mono_error_cleanup (error
); /* FIXME better API that doesn't swallow the error */
7326 HANDLE_FUNCTION_RETURN_OBJ (result
);
7330 mono_object_handle_isinst_mbyref (MonoObjectHandle obj
, MonoClass
*klass
, MonoError
*error
)
7332 gboolean success
= FALSE
;
7335 MonoObjectHandle result
= MONO_HANDLE_NEW (MonoObject
, NULL
);
7337 if (MONO_HANDLE_IS_NULL (obj
))
7340 success
= mono_object_handle_isinst_mbyref_raw (obj
, klass
, error
);
7341 if (success
&& is_ok (error
))
7342 MONO_HANDLE_ASSIGN (result
, obj
);
7349 mono_object_handle_isinst_mbyref_raw (MonoObjectHandle obj
, MonoClass
*klass
, MonoError
*error
)
7353 gboolean result
= FALSE
;
7355 if (MONO_HANDLE_IS_NULL (obj
))
7359 vt
= MONO_HANDLE_GETVAL (obj
, vtable
);
7361 if (mono_class_is_interface (klass
)) {
7362 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt
, m_class_get_interface_id (klass
))) {
7367 /* casting an array one of the invariant interfaces that must act as such */
7368 if (m_class_is_array_special_interface (klass
)) {
7369 if (mono_class_is_assignable_from_internal (klass
, vt
->klass
)) {
7375 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
7376 else if (mono_class_has_variant_generic_params (klass
) && mono_class_is_assignable_from_internal (klass
, mono_handle_class (obj
))) {
7381 MonoClass
*oklass
= vt
->klass
;
7382 if (mono_class_is_transparent_proxy (oklass
)){
7383 MonoRemoteClass
*remote_class
= MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy
, obj
), remote_class
);
7384 oklass
= remote_class
->proxy_class
;
7387 mono_class_setup_supertypes (klass
);
7388 if (mono_class_has_parent_fast (oklass
, klass
)) {
7393 #ifndef DISABLE_REMOTING
7394 if (mono_class_is_transparent_proxy (vt
->klass
))
7396 MonoBoolean custom_type_info
= MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy
, obj
), custom_type_info
);
7397 if (!custom_type_info
)
7399 MonoDomain
*domain
= mono_domain_get ();
7400 MonoObjectHandle rp
= MONO_HANDLE_NEW (MonoObject
, NULL
);
7401 MONO_HANDLE_GET (rp
, MONO_HANDLE_CAST (MonoTransparentProxy
, obj
), rp
);
7402 MonoClass
*rpklass
= mono_defaults
.iremotingtypeinfo_class
;
7403 MonoMethod
*im
= NULL
;
7406 im
= mono_class_get_method_from_name_checked (rpklass
, "CanCastTo", -1, 0, error
);
7407 goto_if_nok (error
, leave
);
7409 mono_error_set_not_supported (error
, "Linked away.");
7412 im
= mono_object_handle_get_virtual_method (rp
, im
, error
);
7413 goto_if_nok (error
, leave
);
7416 MonoReflectionTypeHandle reftype
= mono_type_get_object_handle (domain
, m_class_get_byval_arg (klass
), error
);
7417 goto_if_nok (error
, leave
);
7419 pa
[0] = MONO_HANDLE_RAW (reftype
);
7420 pa
[1] = MONO_HANDLE_RAW (obj
);
7421 MonoObject
*res
= mono_runtime_invoke_checked (im
, MONO_HANDLE_RAW (rp
), pa
, error
);
7422 goto_if_nok (error
, leave
);
7424 if (*(MonoBoolean
*) mono_object_unbox_internal (res
)) {
7425 /* Update the vtable of the remote type, so it can safely cast to this new type */
7426 mono_upgrade_remote_class (domain
, obj
, klass
, error
);
7427 goto_if_nok (error
, leave
);
7432 #endif /* DISABLE_REMOTING */
7438 * mono_object_castclass_mbyref:
7439 * \param obj an object
7440 * \param klass a pointer to a class
7441 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
7444 mono_object_castclass_mbyref (MonoObject
*obj_raw
, MonoClass
*klass
)
7446 MONO_REQ_GC_UNSAFE_MODE
;
7447 HANDLE_FUNCTION_ENTER ();
7449 MONO_HANDLE_DCL (MonoObject
, obj
);
7450 MonoObjectHandle result
= MONO_HANDLE_NEW (MonoObject
, NULL
);
7451 if (MONO_HANDLE_IS_NULL (obj
))
7453 MONO_HANDLE_ASSIGN (result
, mono_object_handle_isinst_mbyref (obj
, klass
, error
));
7454 mono_error_cleanup (error
);
7456 HANDLE_FUNCTION_RETURN_OBJ (result
);
7459 static MonoStringHandle
7460 mono_string_get_pinned (MonoStringHandle str
, MonoError
*error
)
7462 MONO_REQ_GC_UNSAFE_MODE
;
7466 /* We only need to make a pinned version of a string if this is a moving GC */
7467 if (!mono_gc_is_moving ())
7470 const gsize length
= mono_string_handle_length (str
);
7471 const gsize size
= MONO_SIZEOF_MONO_STRING
+ (length
+ 1) * sizeof (gunichar2
);
7472 MonoStringHandle news
= MONO_HANDLE_CAST (MonoString
, mono_gc_alloc_handle_pinned_obj (MONO_HANDLE_GETVAL (str
, object
.vtable
), size
));
7473 if (!MONO_HANDLE_BOOL (news
)) {
7474 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
" bytes", size
);
7478 MONO_ENTER_NO_SAFEPOINTS
;
7480 memcpy (mono_string_chars_internal (MONO_HANDLE_RAW (news
)),
7481 mono_string_chars_internal (MONO_HANDLE_RAW (str
)),
7482 length
* sizeof (gunichar2
));
7484 MONO_EXIT_NO_SAFEPOINTS
;
7486 MONO_HANDLE_SETVAL (news
, length
, int, length
);
7491 mono_string_is_interned_lookup (MonoStringHandle str
, gboolean insert
, MonoError
*error
)
7493 MONO_REQ_GC_UNSAFE_MODE
;
7495 MonoGHashTable
*ldstr_table
= MONO_HANDLE_DOMAIN (str
)->ldstr_table
;
7497 MonoString
*res
= (MonoString
*)mono_g_hash_table_lookup (ldstr_table
, MONO_HANDLE_RAW (str
));
7500 return MONO_HANDLE_NEW (MonoString
, res
);
7502 return NULL_HANDLE_STRING
;
7504 // Allocate outside the lock.
7505 MonoStringHandle s
= mono_string_get_pinned (str
, error
);
7506 if (!is_ok (error
) || !MONO_HANDLE_BOOL (s
))
7507 return NULL_HANDLE_STRING
;
7509 // Try again inside lock.
7511 res
= (MonoString
*)mono_g_hash_table_lookup (ldstr_table
, MONO_HANDLE_RAW (str
));
7513 MONO_HANDLE_ASSIGN_RAW (s
, res
);
7515 mono_g_hash_table_insert_internal (ldstr_table
, MONO_HANDLE_RAW (s
), MONO_HANDLE_RAW (s
));
7521 * mono_string_is_interned:
7522 * \param o String to probe
7523 * \returns Whether the string has been interned.
7526 mono_string_is_interned (MonoString
*str_raw
)
7529 HANDLE_FUNCTION_ENTER ();
7530 MONO_HANDLE_DCL (MonoString
, str
);
7531 MONO_ENTER_GC_UNSAFE
;
7532 str
= mono_string_is_interned_internal (str
, error
);
7533 MONO_EXIT_GC_UNSAFE
;
7534 mono_error_assert_ok (error
);
7535 HANDLE_FUNCTION_RETURN_OBJ (str
);
7539 * mono_string_intern:
7540 * \param o String to intern
7541 * Interns the string passed.
7542 * \returns The interned string.
7545 mono_string_intern (MonoString
*str_raw
)
7548 HANDLE_FUNCTION_ENTER ();
7549 MONO_HANDLE_DCL (MonoString
, str
);
7550 MONO_ENTER_GC_UNSAFE
;
7551 str
= mono_string_intern_checked (str
, error
);
7552 MONO_EXIT_GC_UNSAFE
;
7553 HANDLE_FUNCTION_RETURN_OBJ (str
);
7558 * \param domain the domain where the string will be used.
7559 * \param image a metadata context
7560 * \param idx index into the user string table.
7561 * Implementation for the \c ldstr opcode.
7562 * \returns a loaded string from the \p image / \p idx combination.
7565 mono_ldstr (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
)
7568 MONO_ENTER_GC_UNSAFE
;
7570 result
= mono_ldstr_checked (domain
, image
, idx
, error
);
7571 mono_error_cleanup (error
);
7572 MONO_EXIT_GC_UNSAFE
;
7577 * mono_ldstr_checked:
7578 * \param domain the domain where the string will be used.
7579 * \param image a metadata context
7580 * \param idx index into the user string table.
7581 * \param error set on error.
7582 * Implementation for the \c ldstr opcode.
7583 * \returns A loaded string from the \p image / \p idx combination.
7584 * On failure returns NULL and sets \p error.
7587 mono_ldstr_checked (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
, MonoError
*error
)
7589 MONO_REQ_GC_UNSAFE_MODE
;
7592 HANDLE_FUNCTION_ENTER ();
7594 MonoStringHandle str
= MONO_HANDLE_NEW (MonoString
, NULL
);
7596 if (image
->dynamic
) {
7597 MONO_HANDLE_ASSIGN_RAW (str
, (MonoString
*)mono_lookup_dynamic_token (image
, MONO_TOKEN_STRING
| idx
, NULL
, error
));
7600 if (!mono_verifier_verify_string_signature (image
, idx
, error
))
7602 mono_ldstr_metadata_sig (domain
, mono_metadata_user_string (image
, idx
), str
, error
);
7604 HANDLE_FUNCTION_RETURN_OBJ (str
);
7608 mono_ldstr_handle (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
, MonoError
*error
)
7610 // FIXME invert mono_ldstr_handle and mono_ldstr_checked.
7611 return MONO_HANDLE_NEW (MonoString
, mono_ldstr_checked (domain
, image
, idx
, error
));
7615 mono_string_from_blob (const char *str
, MonoError
*error
)
7617 gsize len
= mono_metadata_decode_blob_size (str
, &str
) >> 1;
7619 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7620 gunichar2
*src
= (gunichar2
*)str
;
7621 gunichar2
*copy
= g_new (gunichar2
, len
);
7623 for (i
= 0; i
< len
; ++i
)
7624 copy
[i
] = GUINT16_FROM_LE (src
[i
]);
7626 char *res
= mono_utf16_to_utf8 (copy
, len
, error
);
7630 return mono_utf16_to_utf8 ((const gunichar2
*)str
, len
, error
);
7634 * mono_ldstr_metadata_sig
7635 * \param domain the domain for the string
7636 * \param sig the signature of a metadata string
7637 * \param error set on error
7638 * \returns a \c MonoString for a string stored in the metadata. On
7639 * failure returns NULL and sets \p error.
7642 mono_ldstr_metadata_sig (MonoDomain
*domain
, const char* sig
, MonoStringHandleOut string_handle
, MonoError
*error
)
7644 MONO_REQ_GC_UNSAFE_MODE
;
7648 MONO_HANDLE_ASSIGN_RAW (string_handle
, NULL
);
7650 const gsize len
= mono_metadata_decode_blob_size (sig
, &sig
) / sizeof (gunichar2
);
7652 // FIXMEcoop excess handle, use mono_string_new_utf16_checked and string_handle parameter
7654 MonoStringHandle o
= mono_string_new_utf16_handle (domain
, (gunichar2
*)sig
, len
, error
);
7655 return_if_nok (error
);
7657 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
7658 gunichar2
*p
= mono_string_chars_internal (MONO_HANDLE_RAW (o
));
7659 for (gsize i
= 0; i
< len
; ++i
)
7660 p
[i
] = GUINT16_FROM_LE (p
[i
]);
7662 // FIXMEcoop excess handle in mono_string_intern_checked
7664 MONO_HANDLE_ASSIGN_RAW (string_handle
, MONO_HANDLE_RAW (mono_string_intern_checked (o
, error
)));
7670 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
7674 mono_ldstr_utf8 (MonoImage
*image
, guint32 idx
, MonoError
*error
)
7680 GError
*gerror
= NULL
;
7684 if (!mono_verifier_verify_string_signature (image
, idx
, error
))
7686 str
= mono_metadata_user_string (image
, idx
);
7688 len2
= mono_metadata_decode_blob_size (str
, &str
);
7691 as
= g_utf16_to_utf8 ((gunichar2
*)str
, len2
, NULL
, &written
, &gerror
);
7693 mono_error_set_argument (error
, "string", gerror
->message
);
7694 g_error_free (gerror
);
7697 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7698 if (len2
> written
) {
7699 /* allocate the total length and copy the part of the string that has been converted */
7700 char *as2
= (char *)g_malloc0 (len2
);
7701 memcpy (as2
, as
, written
);
7710 * mono_string_to_utf8:
7711 * \param s a \c System.String
7712 * \deprecated Use \c mono_string_to_utf8_checked_internal to avoid having an exception arbitrarily raised.
7713 * \returns the UTF-8 representation for \p s.
7714 * The resulting buffer needs to be freed with \c mono_free().
7717 mono_string_to_utf8 (MonoString
*s
)
7720 MONO_ENTER_GC_UNSAFE
;
7722 result
= mono_string_to_utf8_checked_internal (s
, error
);
7724 if (!is_ok (error
)) {
7725 mono_error_cleanup (error
);
7728 MONO_EXIT_GC_UNSAFE
;
7733 * mono_utf16_to_utf8len:
7736 mono_utf16_to_utf8len (const gunichar2
*s
, gsize slength
, gsize
*utf8_length
, MonoError
*error
)
7738 MONO_REQ_GC_UNSAFE_MODE
;
7743 GError
*gerror
= NULL
;
7751 return g_strdup ("");
7753 as
= g_utf16_to_utf8 (s
, slength
, NULL
, &written
, &gerror
);
7754 *utf8_length
= written
;
7756 mono_error_set_argument (error
, "string", gerror
->message
);
7757 g_error_free (gerror
);
7760 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7761 if (slength
> written
) {
7762 /* allocate the total length and copy the part of the string that has been converted */
7763 char *as2
= (char *)g_malloc0 (slength
);
7764 memcpy (as2
, as
, written
);
7768 // FIXME utf8_length is ambiguous here.
7769 // For now it is what strlen would report.
7770 // A lot of code does not deal correctly with embedded nuls.
7777 * mono_utf16_to_utf8:
7780 mono_utf16_to_utf8 (const gunichar2
*s
, gsize slength
, MonoError
*error
)
7782 gsize utf8_length
= 0;
7783 return mono_utf16_to_utf8len (s
, slength
, &utf8_length
, error
);
7787 mono_string_to_utf8_checked_internal (MonoString
*s
, MonoError
*error
)
7789 MONO_REQ_GC_UNSAFE_MODE
;
7797 return g_strdup ("");
7799 return mono_utf16_to_utf8 (mono_string_chars_internal (s
), s
->length
, error
);
7803 mono_string_to_utf8len (MonoStringHandle s
, gsize
*utf8len
, MonoError
*error
)
7806 if (MONO_HANDLE_IS_NULL (s
))
7811 MONO_ENTER_NO_SAFEPOINTS
;
7813 utf8
= mono_utf16_to_utf8len (mono_string_chars_internal (MONO_HANDLE_RAW (s
)), mono_string_handle_length (s
), utf8len
, error
);
7815 MONO_EXIT_NO_SAFEPOINTS
;
7821 * mono_string_to_utf8_checked:
7822 * \param s a \c System.String
7823 * \param error a \c MonoError.
7824 * Converts a \c MonoString to its UTF-8 representation. May fail; check
7825 * \p error to determine whether the conversion was successful.
7826 * The resulting buffer should be freed with \c mono_free().
7829 mono_string_to_utf8_checked (MonoString
*string_obj
, MonoError
*error
)
7831 MONO_EXTERNAL_ONLY_GC_UNSAFE (char*, mono_string_to_utf8_checked_internal (string_obj
, error
));
7835 mono_string_handle_to_utf8 (MonoStringHandle s
, MonoError
*error
)
7837 return mono_string_to_utf8_checked_internal (MONO_HANDLE_RAW (s
), error
);
7841 * mono_string_to_utf8_ignore:
7842 * \param s a MonoString
7843 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7844 * invalid surrogate pairs.
7845 * The resulting buffer should be freed with \c mono_free().
7848 mono_string_to_utf8_ignore (MonoString
*s
)
7850 MONO_REQ_GC_UNSAFE_MODE
;
7859 return g_strdup ("");
7861 as
= g_utf16_to_utf8 (mono_string_chars_internal (s
), s
->length
, NULL
, &written
, NULL
);
7863 /* g_utf16_to_utf8 may not be able to complete the conversion (e.g. NULL values were found, #335488) */
7864 if (s
->length
> written
) {
7865 /* allocate the total length and copy the part of the string that has been converted */
7866 char *as2
= (char *)g_malloc0 (s
->length
);
7867 memcpy (as2
, as
, written
);
7876 mono_string_to_utf16_internal_impl (MonoStringHandle s
, MonoError
*error
)
7878 MONO_REQ_GC_UNSAFE_MODE
;
7880 // FIXME This optimization ok to miss before wrapper? Or null is rare?
7881 if (MONO_HANDLE_RAW (s
) == NULL
)
7884 int const length
= mono_string_handle_length (s
);
7885 mono_unichar2
* const as
= (mono_unichar2
*)g_malloc ((length
+ 1) * sizeof (*as
));
7889 memcpy (as
, mono_string_chars_internal (MONO_HANDLE_RAW (s
)), length
* sizeof (*as
));
7895 * mono_string_to_utf16:
7896 * \param s a \c MonoString
7897 * \returns a null-terminated array of the UTF-16 chars
7898 * contained in \p s. The result must be freed with \c g_free().
7899 * This is a temporary helper until our string implementation
7900 * is reworked to always include the null-terminating char.
7903 mono_string_to_utf16 (MonoString
*string_obj
)
7907 MONO_EXTERNAL_ONLY (mono_unichar2
*, mono_string_to_utf16_internal (string_obj
));
7911 mono_string_to_utf32_internal_impl (MonoStringHandle s
, MonoError
*error
)
7913 MONO_REQ_GC_UNSAFE_MODE
;
7915 // FIXME This optimization ok to miss before wrapper? Or null is rare?
7916 if (MONO_HANDLE_RAW (s
) == NULL
)
7919 return g_utf16_to_ucs4 (MONO_HANDLE_RAW (s
)->chars
, mono_string_handle_length (s
), NULL
, NULL
, NULL
);
7923 * mono_string_to_utf32:
7924 * \param s a \c MonoString
7925 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7926 * contained in \p s. The result must be freed with \c g_free().
7929 mono_string_to_utf32 (MonoString
*string_obj
)
7931 MONO_EXTERNAL_ONLY (mono_unichar4
*, mono_string_to_utf32_internal (string_obj
));
7935 * mono_string_from_utf16:
7936 * \param data the UTF-16 string (LPWSTR) to convert
7937 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7938 * \returns a \c MonoString.
7941 mono_string_from_utf16 (gunichar2
*data
)
7944 MonoString
*result
= mono_string_from_utf16_checked (data
, error
);
7945 mono_error_cleanup (error
);
7950 * mono_string_from_utf16_checked:
7951 * \param data the UTF-16 string (LPWSTR) to convert
7952 * \param error set on error
7953 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7954 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7957 mono_string_from_utf16_checked (const gunichar2
*data
, MonoError
*error
)
7959 MONO_REQ_GC_UNSAFE_MODE
;
7963 return mono_string_new_utf16_checked (mono_domain_get (), data
, g_utf16_len (data
), error
);
7967 * mono_string_from_utf32:
7968 * \param data the UTF-32 string (LPWSTR) to convert
7969 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7970 * \returns a \c MonoString.
7973 mono_string_from_utf32 (/*const*/ mono_unichar4
*data
)
7976 MonoString
*result
= mono_string_from_utf32_checked (data
, error
);
7977 mono_error_cleanup (error
);
7982 * mono_string_from_utf32_checked:
7983 * \param data the UTF-32 string (LPWSTR) to convert
7984 * \param error set on error
7985 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7986 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7989 mono_string_from_utf32_checked (const mono_unichar4
*data
, MonoError
*error
)
7991 MONO_REQ_GC_UNSAFE_MODE
;
7994 MonoString
* result
= NULL
;
7995 mono_unichar2
*utf16_output
= NULL
;
7996 GError
*gerror
= NULL
;
7997 glong items_written
;
8003 while (data
[len
]) len
++;
8005 utf16_output
= g_ucs4_to_utf16 (data
, len
, NULL
, &items_written
, &gerror
);
8008 g_error_free (gerror
);
8010 result
= mono_string_from_utf16_checked (utf16_output
, error
);
8011 g_free (utf16_output
);
8016 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, MonoError
*error
)
8018 MONO_REQ_GC_UNSAFE_MODE
;
8024 r
= mono_string_to_utf8_checked_internal (s
, error
);
8031 len
= strlen (r
) + 1;
8033 mp_s
= (char *)mono_mempool_alloc (mp
, len
);
8035 mp_s
= (char *)mono_image_alloc (image
, len
);
8037 memcpy (mp_s
, r
, len
);
8045 * mono_string_to_utf8_image:
8046 * \param s a \c System.String
8047 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
8050 mono_string_to_utf8_image (MonoImage
*image
, MonoStringHandle s
, MonoError
*error
)
8052 MONO_REQ_GC_UNSAFE_MODE
;
8054 return mono_string_to_utf8_internal (NULL
, image
, MONO_HANDLE_RAW (s
), error
); /* FIXME pin the string */
8058 * mono_string_to_utf8_mp:
8059 * \param s a \c System.String
8060 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
8063 mono_string_to_utf8_mp (MonoMemPool
*mp
, MonoString
*s
, MonoError
*error
)
8065 MONO_REQ_GC_UNSAFE_MODE
;
8067 return mono_string_to_utf8_internal (mp
, NULL
, s
, error
);
8071 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks
;
8074 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks
*cbs
)
8076 eh_callbacks
= *cbs
;
8079 MonoRuntimeExceptionHandlingCallbacks
*
8080 mono_get_eh_callbacks (void)
8082 return &eh_callbacks
;
8086 mono_raise_exception_internal (MonoException
*ex
)
8088 /* raise_exception doesn't return, so the transition to GC Unsafe is unbalanced */
8089 MONO_STACKDATA (stackdata
);
8090 mono_threads_enter_gc_unsafe_region_unbalanced_with_info (mono_thread_info_current (), &stackdata
);
8091 mono_raise_exception_deprecated (ex
);
8095 * mono_raise_exception:
8096 * \param ex exception object
8097 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
8098 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8101 mono_raise_exception (MonoException
*ex
)
8103 MONO_EXTERNAL_ONLY_VOID (mono_raise_exception_internal (ex
));
8107 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8110 mono_raise_exception_deprecated (MonoException
*ex
)
8112 MONO_REQ_GC_UNSAFE_MODE
;
8114 eh_callbacks
.mono_raise_exception (ex
);
8118 * mono_reraise_exception:
8119 * \param ex exception object
8120 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
8121 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8124 mono_reraise_exception (MonoException
*ex
)
8126 mono_reraise_exception_deprecated (ex
);
8130 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
8133 mono_reraise_exception_deprecated (MonoException
*ex
)
8135 MONO_REQ_GC_UNSAFE_MODE
;
8137 eh_callbacks
.mono_reraise_exception (ex
);
8141 * CTX must point to managed code.
8144 mono_raise_exception_with_context (MonoException
*ex
, MonoContext
*ctx
)
8146 MONO_REQ_GC_UNSAFE_MODE
;
8148 eh_callbacks
.mono_raise_exception_with_ctx (ex
, ctx
);
8151 #ifndef ENABLE_NETCORE
8154 * mono_wait_handle_new:
8155 * \param domain Domain where the object will be created
8156 * \param handle Handle for the wait handle
8157 * \param error set on error.
8158 * \returns A new \c MonoWaitHandle created in the given domain for the
8159 * given handle. On failure returns NULL and sets \p error.
8162 mono_wait_handle_new (MonoDomain
*domain
, HANDLE handle
, MonoError
*error
)
8164 MONO_REQ_GC_UNSAFE_MODE
;
8166 MonoWaitHandle
*res
;
8167 gpointer params
[1];
8168 static MonoMethod
*handle_set
;
8171 res
= (MonoWaitHandle
*)mono_object_new_checked (domain
, mono_defaults
.manualresetevent_class
, error
);
8172 return_val_if_nok (error
, NULL
);
8174 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
8176 handle_set
= mono_class_get_property_from_name_internal (mono_defaults
.manualresetevent_class
, "Handle")->set
;
8178 params
[0] = &handle
;
8180 mono_runtime_invoke_checked (handle_set
, res
, params
, error
);
8185 mono_wait_handle_get_handle (MonoWaitHandle
*handle
)
8187 MONO_REQ_GC_UNSAFE_MODE
;
8191 MONO_STATIC_POINTER_INIT (MonoClassField
, f_safe_handle
)
8193 f_safe_handle
= mono_class_get_field_from_name_full (mono_defaults
.manualresetevent_class
, "safeWaitHandle", NULL
);
8194 g_assert (f_safe_handle
);
8196 MONO_STATIC_POINTER_INIT_END (MonoClassField
, f_safe_handle
)
8198 mono_field_get_value_internal ((MonoObject
*)handle
, f_safe_handle
, &sh
);
8202 #endif /* ENABLE_NETCORE */
8205 * Returns the MonoMethod to call to Capture the ExecutionContext.
8208 mono_get_context_capture_method (void)
8210 /* older corlib revisions won't have the class (nor the method) */
8211 MonoClass
*execution_context
= mono_class_try_get_execution_context_class ();
8212 if (!execution_context
)
8215 MONO_STATIC_POINTER_INIT (MonoMethod
, method
)
8218 mono_class_init_internal (execution_context
);
8219 method
= mono_class_get_method_from_name_checked (execution_context
, "Capture", 0, 0, error
);
8220 mono_error_assert_ok (error
);
8222 MONO_STATIC_POINTER_INIT_END (MonoMethod
, method
)
8228 mono_runtime_capture_context (MonoDomain
*domain
, MonoError
*error
)
8231 return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL
, NULL
, error
);
8233 MONO_REQ_GC_UNSAFE_MODE
;
8235 RuntimeInvokeFunction runtime_invoke
;
8239 if (!domain
->capture_context_runtime_invoke
|| !domain
->capture_context_method
) {
8240 MonoMethod
*method
= mono_get_context_capture_method ();
8241 MonoMethod
*wrapper
;
8244 wrapper
= mono_marshal_get_runtime_invoke (method
, FALSE
);
8245 domain
->capture_context_runtime_invoke
= mono_compile_method_checked (wrapper
, error
);
8246 return_val_if_nok (error
, NULL
);
8247 domain
->capture_context_method
= mono_compile_method_checked (method
, error
);
8248 return_val_if_nok (error
, NULL
);
8251 runtime_invoke
= (RuntimeInvokeFunction
)domain
->capture_context_runtime_invoke
;
8253 return runtime_invoke (NULL
, NULL
, NULL
, domain
->capture_context_method
);
8257 #ifndef ENABLE_NETCORE
8260 * mono_async_result_new:
8261 * \param domain domain where the object will be created.
8262 * \param handle wait handle.
8263 * \param state state to pass to AsyncResult
8264 * \param data C closure data.
8265 * \param error set on error.
8266 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
8267 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
8268 * On failure returns NULL and sets \p error.
8271 mono_async_result_new (MonoDomain
*domain
, HANDLE handle
, MonoObject
*state
, gpointer data
, MonoObject
*object_data
, MonoError
*error
)
8273 MONO_REQ_GC_UNSAFE_MODE
;
8276 MonoAsyncResult
*res
= (MonoAsyncResult
*)mono_object_new_checked (domain
, mono_class_get_asyncresult_class (), error
);
8277 return_val_if_nok (error
, NULL
);
8278 MonoObject
*context
= mono_runtime_capture_context (domain
, error
);
8279 return_val_if_nok (error
, NULL
);
8280 /* we must capture the execution context from the original thread */
8282 MONO_OBJECT_SETREF_INTERNAL (res
, execution_context
, context
);
8283 /* note: result may be null if the flow is suppressed */
8286 res
->data
= (void **)data
;
8287 MONO_OBJECT_SETREF_INTERNAL (res
, object_data
, object_data
);
8288 MONO_OBJECT_SETREF_INTERNAL (res
, async_state
, state
);
8289 MonoWaitHandle
*wait_handle
= mono_wait_handle_new (domain
, handle
, error
);
8290 return_val_if_nok (error
, NULL
);
8292 MONO_OBJECT_SETREF_INTERNAL (res
, handle
, (MonoObject
*) wait_handle
);
8294 res
->sync_completed
= FALSE
;
8295 res
->completed
= FALSE
;
8301 mono_message_invoke (MonoThreadInfo
* mono_thread_info_current_var
,
8302 MonoObject
* target
, MonoMethodMessage
* msg
,
8303 MonoObject
** exc
, MonoArray
** out_args
, MonoError
* error
);
8306 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResultHandle aresh
, MonoError
* error
)
8308 MONO_REQ_GC_UNSAFE_MODE
;
8310 SETUP_ICALL_FUNCTION
;
8313 MonoObjectHandle res
= MONO_HANDLE_NEW (MonoObject
, NULL
);
8314 MonoAsyncResult
* ares
= MONO_HANDLE_RAW (aresh
);
8317 g_assert (ares
->async_delegate
);
8318 MONO_HANDLE_NEW (MonoObject
, ares
->async_delegate
);
8320 ac
= (MonoAsyncCall
*) ares
->object_data
;
8321 MONO_HANDLE_NEW (MonoAsyncCall
, ac
);
8324 MONO_HANDLE_ASSIGN_RAW (res
, mono_runtime_delegate_invoke_checked (ares
->async_delegate
, (void**) &ares
->async_state
, error
));
8325 return_val_if_nok (error
, NULL_HANDLE
);
8327 gpointer wait_event
= NULL
;
8329 MONO_HANDLE_NEW (MonoMethodMessage
, ac
->msg
);
8331 ac
->msg
->exc
= NULL
;
8333 MONO_HANDLE_ASSIGN_RAW (res
, mono_message_invoke (mono_thread_info_current_var
,
8334 ares
->async_delegate
,
8340 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
8341 mono_threads_begin_abort_protected_block ();
8343 if (!ac
->msg
->exc
) {
8344 MonoException
*ex
= mono_error_convert_to_exception (error
);
8345 MONO_OBJECT_SETREF_INTERNAL (ac
->msg
, exc
, (MonoObject
*)ex
);
8347 mono_error_cleanup (error
);
8350 MONO_OBJECT_SETREF_INTERNAL (ac
, res
, MONO_HANDLE_RAW (res
));
8352 MonoObjectHandle handle
= MONO_HANDLE_NEW (MonoObject
, NULL
); // Create handle outside of lock.
8354 mono_monitor_enter_internal ((MonoObject
*) ares
);
8355 ares
->completed
= 1;
8357 MONO_HANDLE_ASSIGN_RAW (handle
, ares
->handle
);
8358 wait_event
= mono_wait_handle_get_handle ((MonoWaitHandle
*) ares
->handle
);
8360 mono_monitor_exit_internal ((MonoObject
*) ares
);
8362 if (wait_event
!= NULL
)
8363 mono_w32event_set (wait_event
);
8365 error_init (error
); //the else branch would leave it in an undefined state
8366 if (ac
->cb_method
) {
8367 MONO_HANDLE_NEW (MonoDelegate
, ac
->cb_target
);
8368 mono_runtime_invoke_checked (ac
->cb_method
, ac
->cb_target
, (gpointer
*) &ares
, error
);
8371 mono_threads_end_abort_protected_block ();
8373 return_val_if_nok (error
, NULL_HANDLE
);
8377 #endif /* ENABLE_NETCORE */
8380 mono_message_init (MonoDomain
*domain
,
8381 MonoMethodMessage
*this_obj
,
8382 MonoReflectionMethod
*method
,
8383 MonoArray
*out_args
,
8386 MONO_REQ_GC_UNSAFE_MODE
;
8388 MONO_STATIC_POINTER_INIT (MonoMethod
, init_message_method
)
8390 init_message_method
= mono_class_get_method_from_name_checked (mono_defaults
.mono_method_message_class
, "InitMessage", 2, 0, error
);
8391 mono_error_assert_ok (error
);
8392 g_assert (init_message_method
!= NULL
);
8394 MONO_STATIC_POINTER_INIT_END (MonoMethod
, init_message_method
)
8397 /* FIXME set domain instead? */
8398 g_assert (domain
== mono_domain_get ());
8405 mono_runtime_invoke_checked (init_message_method
, this_obj
, args
, error
);
8406 return is_ok (error
);
8409 #ifndef DISABLE_REMOTING
8411 * mono_remoting_invoke:
8412 * \param real_proxy pointer to a \c RealProxy object
8413 * \param msg The \c MonoMethodMessage to execute
8414 * \param exc used to store exceptions
8415 * \param out_args used to store output arguments
8416 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
8417 * \c IMessage interface and it is not trivial to extract results from there. So
8418 * we call an helper method \c PrivateInvoke instead of calling
8419 * \c RealProxy::Invoke() directly.
8420 * \returns the result object.
8423 mono_remoting_invoke (MonoObject
*real_proxy
, MonoMethodMessage
*msg
, MonoObject
**exc
, MonoArray
**out_args
, MonoError
*error
)
8425 MONO_REQ_GC_UNSAFE_MODE
;
8428 MonoMethod
*im
= real_proxy
->vtable
->domain
->private_invoke_method
;
8435 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
8438 im
= mono_class_get_method_from_name_checked (mono_defaults
.real_proxy_class
, "PrivateInvoke", 4, 0, error
);
8439 return_val_if_nok (error
, NULL
);
8441 mono_error_set_not_supported (error
, "Linked away.");
8444 real_proxy
->vtable
->domain
->private_invoke_method
= im
;
8447 pa
[0] = real_proxy
;
8452 o
= mono_runtime_try_invoke (im
, NULL
, pa
, exc
, error
);
8453 return_val_if_nok (error
, NULL
);
8459 // FIXME inline in the only caller
8461 mono_message_invoke (MonoThreadInfo
*mono_thread_info_current_var
,
8462 MonoObject
*target
, MonoMethodMessage
*msg
,
8463 MonoObject
**exc
, MonoArray
**out_args
, MonoError
*error
)
8465 MONO_REQ_GC_UNSAFE_MODE
;
8467 static MonoClass
*object_array_klass
;
8472 MonoMethodSignature
*sig
;
8474 int i
, j
, outarg_count
= 0;
8476 #ifndef DISABLE_REMOTING
8477 if (target
&& mono_object_is_transparent_proxy (target
)) {
8478 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)target
;
8480 gboolean
const is_contextbound
= mono_class_is_contextbound (tp
->remote_class
->proxy_class
);
8482 MonoObject
* const context
= is_contextbound
? MONO_HANDLE_RAW (MONO_HANDLE_NEW (MonoObject
, (MonoObject
*)mono_context_get ())) : NULL
;
8484 if (is_contextbound
&& tp
->rp
->context
== context
) {
8485 target
= tp
->rp
->unwrapped_server
;
8486 MONO_HANDLE_NEW (MonoObject
, target
);
8488 MONO_HANDLE_NEW (MonoRealProxy
, tp
->rp
);
8489 return mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, exc
, out_args
, error
);
8494 domain
= mono_domain_get ();
8495 method
= msg
->method
->method
;
8496 sig
= mono_method_signature_internal (method
);
8498 for (i
= 0; i
< sig
->param_count
; i
++) {
8499 if (sig
->params
[i
]->byref
)
8503 if (!object_array_klass
) {
8506 klass
= mono_class_create_array (mono_defaults
.object_class
, 1);
8509 mono_memory_barrier ();
8510 object_array_klass
= klass
;
8513 MonoVTable
*vt
= mono_class_vtable_checked (domain
, object_array_klass
, error
);
8514 return_val_if_nok (error
, NULL
);
8515 arr
= mono_array_new_specific_checked (vt
, outarg_count
, error
);
8516 return_val_if_nok (error
, NULL
);
8517 MONO_HANDLE_NEW (MonoArray
, arr
);
8519 mono_gc_wbarrier_generic_store_internal (out_args
, (MonoObject
*) arr
);
8522 MONO_HANDLE_NEW (MonoArray
, msg
->args
);
8523 MonoObject
*ret
= mono_runtime_try_invoke_array (method
, m_class_is_valuetype (method
->klass
)? mono_object_unbox_internal (target
): target
, msg
->args
, exc
, error
);
8524 return_val_if_nok (error
, NULL
);
8525 MONO_HANDLE_NEW (MonoObject
, ret
);
8527 MonoObjectHandle argh
= MONO_HANDLE_NEW (MonoObject
, NULL
);
8529 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
8530 if (sig
->params
[i
]->byref
) {
8532 arg
= (MonoObject
*)mono_array_get_internal (msg
->args
, gpointer
, i
);
8533 MONO_HANDLE_ASSIGN_RAW (argh
, arg
);
8534 mono_array_setref_internal (*out_args
, j
, arg
);
8543 * prepare_to_string_method:
8545 * @target: Set to @obj or unboxed value if a valuetype
8547 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
8550 prepare_to_string_method (MonoObject
*obj
, void **target
)
8552 MONO_REQ_GC_UNSAFE_MODE
;
8560 MONO_STATIC_POINTER_INIT (MonoMethod
, to_string
)
8563 to_string
= mono_class_get_method_from_name_checked (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL
| METHOD_ATTRIBUTE_PUBLIC
, error
);
8564 mono_error_assert_ok (error
);
8566 MONO_STATIC_POINTER_INIT_END (MonoMethod
, to_string
)
8568 method
= mono_object_get_virtual_method_internal (obj
, to_string
);
8570 // Unbox value type if needed
8571 if (m_class_is_valuetype (mono_method_get_class (method
))) {
8572 *target
= mono_object_unbox_internal (obj
);
8578 * mono_object_to_string:
8579 * \param obj The object
8580 * \param exc Any exception thrown by \c ToString. May be NULL.
8581 * \returns the result of calling \c ToString on an object.
8584 mono_object_to_string (MonoObject
*obj
, MonoObject
**exc
)
8587 MonoString
*s
= NULL
;
8589 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
8591 s
= (MonoString
*) mono_runtime_try_invoke (method
, target
, NULL
, exc
, error
);
8592 if (*exc
== NULL
&& !is_ok (error
))
8593 *exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
8595 mono_error_cleanup (error
);
8597 s
= (MonoString
*) mono_runtime_invoke_checked (method
, target
, NULL
, error
);
8598 mono_error_raise_exception_deprecated (error
); /* OK to throw, external only without a good alternative */
8605 * mono_object_try_to_string:
8606 * \param obj The object
8607 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
8608 * \param error Set if method cannot be invoked.
8609 * \returns the result of calling \c ToString() on an object. If the
8610 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
8614 mono_object_try_to_string (MonoObject
*obj
, MonoObject
**exc
, MonoError
*error
)
8619 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
8620 return (MonoString
*) mono_runtime_try_invoke (method
, target
, NULL
, exc
, error
);
8626 get_native_backtrace (MonoException
*exc_raw
)
8628 HANDLE_FUNCTION_ENTER ();
8629 MONO_HANDLE_DCL(MonoException
, exc
);
8630 char * const trace
= mono_exception_handle_get_native_backtrace (exc
);
8631 HANDLE_FUNCTION_RETURN_VAL (trace
);
8635 * mono_print_unhandled_exception:
8636 * \param exc The exception
8637 * Prints the unhandled exception.
8640 mono_print_unhandled_exception_internal (MonoObject
*exc
)
8642 MONO_REQ_GC_UNSAFE_MODE
;
8645 char *message
= (char*)"";
8646 gboolean free_message
= FALSE
;
8649 if (exc
== (MonoObject
*)mono_object_domain (exc
)->out_of_memory_ex
) {
8650 message
= g_strdup ("OutOfMemoryException");
8651 free_message
= TRUE
;
8652 } else if (exc
== (MonoObject
*)mono_object_domain (exc
)->stack_overflow_ex
) {
8653 message
= g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
8654 free_message
= TRUE
;
8657 if (((MonoException
*)exc
)->native_trace_ips
) {
8658 message
= get_native_backtrace ((MonoException
*)exc
);
8659 free_message
= TRUE
;
8661 MonoObject
*other_exc
= NULL
;
8662 str
= mono_object_try_to_string (exc
, &other_exc
, error
);
8663 if (other_exc
== NULL
&& !is_ok (error
))
8664 other_exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
8666 mono_error_cleanup (error
);
8668 char *original_backtrace
= mono_exception_get_managed_backtrace ((MonoException
*)exc
);
8669 char *nested_backtrace
= mono_exception_get_managed_backtrace ((MonoException
*)other_exc
);
8671 message
= g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
8672 original_backtrace
, nested_backtrace
);
8674 g_free (original_backtrace
);
8675 g_free (nested_backtrace
);
8676 free_message
= TRUE
;
8678 message
= mono_string_to_utf8_checked_internal (str
, error
);
8679 if (!is_ok (error
)) {
8680 mono_error_cleanup (error
);
8681 message
= (char *) "";
8683 free_message
= TRUE
;
8690 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
8691 * exc->vtable->klass->name, message);
8693 g_printerr ("\nUnhandled Exception:\n%s\n", message
);
8700 mono_print_unhandled_exception (MonoObject
*exc
)
8702 MONO_EXTERNAL_ONLY_VOID (mono_print_unhandled_exception_internal (exc
));
8706 * mono_delegate_ctor_with_method:
8707 * \param this pointer to an uninitialized delegate object
8708 * \param target target object
8709 * \param addr pointer to native code
8710 * \param method method
8711 * \param error set on error.
8712 * Initialize a delegate and sets a specific method, not the one
8713 * associated with \p addr. This is useful when sharing generic code.
8714 * In that case \p addr will most probably not be associated with the
8715 * correct instantiation of the method.
8716 * On failure returns FALSE and sets \p error.
8719 mono_delegate_ctor_with_method (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoMethod
*method
, MonoError
*error
)
8721 MONO_REQ_GC_UNSAFE_MODE
;
8724 MonoDelegateHandle delegate
= MONO_HANDLE_CAST (MonoDelegate
, this_obj
);
8726 g_assert (!MONO_HANDLE_IS_NULL (this_obj
));
8728 MonoClass
*klass
= mono_handle_class (this_obj
);
8729 g_assert (mono_class_has_parent (klass
, mono_defaults
.multicastdelegate_class
));
8732 MONO_HANDLE_SETVAL (delegate
, method
, MonoMethod
*, method
);
8734 UnlockedIncrement (&mono_stats
.delegate_creations
);
8737 MONO_HANDLE_SETVAL (delegate
, method_ptr
, gpointer
, addr
);
8739 #ifndef DISABLE_REMOTING
8740 if (!MONO_HANDLE_IS_NULL (target
) && mono_class_is_transparent_proxy (mono_handle_class (target
))) {
8741 if (callbacks
.interp_get_remoting_invoke
) {
8742 MONO_HANDLE_SETVAL (delegate
, interp_method
, gpointer
, callbacks
.interp_get_remoting_invoke (method
, addr
, error
));
8745 method
= mono_marshal_get_remoting_invoke (method
, error
);
8746 return_val_if_nok (error
, FALSE
);
8747 MONO_HANDLE_SETVAL (delegate
, method_ptr
, gpointer
, mono_compile_method_checked (method
, error
));
8749 return_val_if_nok (error
, FALSE
);
8753 MONO_HANDLE_SET (delegate
, target
, target
);
8754 MONO_HANDLE_SETVAL (delegate
, invoke_impl
, gpointer
, callbacks
.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate
), mono_handle_class (delegate
)));
8755 g_assert (callbacks
.init_delegate
);
8756 callbacks
.init_delegate (delegate
, error
);
8757 return_val_if_nok (error
, FALSE
);
8762 * mono_delegate_ctor:
8763 * \param this pointer to an uninitialized delegate object
8764 * \param target target object
8765 * \param addr pointer to native code
8766 * \param error set on error.
8767 * This is used to initialize a delegate.
8768 * On failure returns FALSE and sets \p error.
8771 mono_delegate_ctor (MonoObjectHandle this_obj
, MonoObjectHandle target
, gpointer addr
, MonoError
*error
)
8773 MONO_REQ_GC_UNSAFE_MODE
;
8776 MonoDomain
*domain
= mono_domain_get ();
8778 MonoMethod
*method
= NULL
;
8782 ji
= mono_jit_info_table_find (domain
, mono_get_addr_from_ftnptr (addr
));
8784 if (!ji
&& domain
!= mono_get_root_domain ())
8785 ji
= mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr
));
8787 method
= mono_jit_info_get_method (ji
);
8788 g_assert (!mono_class_is_gtd (method
->klass
));
8791 return mono_delegate_ctor_with_method (this_obj
, target
, addr
, method
, error
);
8795 * mono_method_call_message_new:
8796 * \param method method to encapsulate
8797 * \param params parameters to the method
8798 * \param invoke optional, delegate invoke.
8799 * \param cb async callback delegate.
8800 * \param state state passed to the async callback.
8801 * \param error set on error.
8802 * Translates arguments pointers into a \c MonoMethodMessage.
8803 * On failure returns NULL and sets \p error.
8806 mono_method_call_message_new (MonoMethod
*method
, gpointer
*params
, MonoMethod
*invoke
,
8807 MonoDelegate
**cb
, MonoObject
**state
, MonoError
*error
)
8809 MONO_REQ_GC_UNSAFE_MODE
;
8813 MonoDomain
*domain
= mono_domain_get ();
8814 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
8815 MonoMethodMessage
*msg
;
8818 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
8819 return_val_if_nok (error
, NULL
);
8822 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, invoke
, NULL
, error
);
8823 return_val_if_nok (error
, NULL
);
8824 mono_message_init (domain
, msg
, rm
, NULL
, error
);
8825 return_val_if_nok (error
, NULL
);
8826 count
= sig
->param_count
- 2;
8828 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
8829 return_val_if_nok (error
, NULL
);
8830 mono_message_init (domain
, msg
, rm
, NULL
, error
);
8831 return_val_if_nok (error
, NULL
);
8832 count
= sig
->param_count
;
8835 for (i
= 0; i
< count
; i
++) {
8840 if (sig
->params
[i
]->byref
)
8841 vpos
= *((gpointer
*)params
[i
]);
8845 klass
= mono_class_from_mono_type_internal (sig
->params
[i
]);
8847 if (m_class_is_valuetype (klass
)) {
8848 arg
= mono_value_box_checked (domain
, klass
, vpos
, error
);
8849 return_val_if_nok (error
, NULL
);
8851 arg
= *((MonoObject
**)vpos
);
8853 mono_array_setref_internal (msg
->args
, i
, arg
);
8856 if (cb
!= NULL
&& state
!= NULL
) {
8857 *cb
= *((MonoDelegate
**)params
[i
]);
8859 *state
= *((MonoObject
**)params
[i
]);
8866 * mono_method_return_message_restore:
8868 * Restore results from message based processing back to arguments pointers
8871 mono_method_return_message_restore (MonoMethod
*method
, gpointer
*params
, MonoArray
*out_args
, MonoError
*error
)
8873 MONO_REQ_GC_UNSAFE_MODE
;
8877 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
8878 int i
, j
, type
, size
, out_len
;
8880 if (out_args
== NULL
)
8882 out_len
= mono_array_length_internal (out_args
);
8886 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
8887 MonoType
*pt
= sig
->params
[i
];
8892 mono_error_set_execution_engine (error
, "The proxy call returned an incorrect number of output arguments");
8896 arg
= (char *)mono_array_get_internal (out_args
, gpointer
, j
);
8899 g_assert (type
!= MONO_TYPE_VOID
);
8901 if (MONO_TYPE_IS_REFERENCE (pt
)) {
8902 mono_gc_wbarrier_generic_store_internal (*((MonoObject
***)params
[i
]), (MonoObject
*)arg
);
8905 MonoClass
*klass
= ((MonoObject
*)arg
)->vtable
->klass
;
8906 size
= mono_class_value_size (klass
, NULL
);
8907 if (m_class_has_references (klass
))
8908 mono_gc_wbarrier_value_copy_internal (*((gpointer
*)params
[i
]), mono_object_get_data ((MonoObject
*)arg
), 1, klass
);
8910 mono_gc_memmove_atomic (*((gpointer
*)params
[i
]), mono_object_get_data ((MonoObject
*)arg
), size
);
8912 size
= mono_class_value_size (mono_class_from_mono_type_internal (pt
), NULL
);
8913 mono_gc_bzero_atomic (*((gpointer
*)params
[i
]), size
);
8922 #ifndef DISABLE_REMOTING
8925 * mono_load_remote_field:
8926 * \param this pointer to an object
8927 * \param klass klass of the object containing \p field
8928 * \param field the field to load
8929 * \param res a storage to store the result
8930 * This method is called by the runtime on attempts to load fields of
8931 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8932 * the object containing \p field. \p res is a storage location which can be
8933 * used to store the result.
8934 * \returns an address pointing to the value of field.
8937 mono_load_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
)
8941 MONO_ENTER_GC_UNSAFE
;
8944 result
= mono_load_remote_field_checked (this_obj
, klass
, field
, res
, error
);
8945 mono_error_cleanup (error
);
8947 MONO_EXIT_GC_UNSAFE
;
8953 * mono_load_remote_field_checked:
8954 * \param this pointer to an object
8955 * \param klass klass of the object containing \p field
8956 * \param field the field to load
8957 * \param res a storage to store the result
8958 * \param error set on error
8959 * This method is called by the runtime on attempts to load fields of
8960 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8961 * the object containing \p field. \p res is a storage location which can be
8962 * used to store the result.
8963 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8966 mono_load_remote_field_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
, MonoError
*error
)
8968 MONO_REQ_GC_UNSAFE_MODE
;
8972 MonoDomain
*domain
= mono_domain_get ();
8973 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this_obj
;
8975 MonoObject
*exc
= NULL
;
8976 MonoClass
*field_class
= NULL
;
8977 MonoString
*field_name
= NULL
;
8978 char* full_name
= NULL
;
8979 MonoString
*full_name_str
= NULL
;
8980 MonoMethodMessage
*msg
= NULL
;
8981 MonoArray
*out_args
= NULL
;
8982 MonoReflectionMethod
*rm
= NULL
;
8984 g_assert (mono_object_is_transparent_proxy (this_obj
));
8985 g_assert (res
!= NULL
);
8987 if (mono_class_is_contextbound (tp
->remote_class
->proxy_class
) && tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
8988 mono_field_get_value_internal (tp
->rp
->unwrapped_server
, field
, res
);
8992 MONO_STATIC_POINTER_INIT (MonoMethod
, getter
)
8994 getter
= mono_class_get_method_from_name_checked (mono_defaults
.object_class
, "FieldGetter", -1, 0, error
);
8995 goto_if_nok (error
, return_null
);
8997 mono_error_set_not_supported (error
, "Linked away.");
9001 MONO_STATIC_POINTER_INIT_END (MonoMethod
, getter
)
9003 field_class
= mono_class_from_mono_type_internal (field
->type
);
9005 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
9006 goto_if_nok (error
, return_null
);
9008 out_args
= mono_array_new_checked (domain
, mono_defaults
.object_class
, 1, error
);
9009 goto_if_nok (error
, return_null
);
9011 rm
= mono_method_get_object_checked (domain
, getter
, NULL
, error
);
9012 goto_if_nok (error
, return_null
);
9014 mono_message_init (domain
, msg
, rm
, out_args
, error
);
9015 goto_if_nok (error
, return_null
);
9017 full_name
= mono_type_get_full_name (klass
);
9018 full_name_str
= mono_string_new_checked (domain
, full_name
, error
);
9019 goto_if_nok (error
, return_null
);
9021 mono_array_setref_internal (msg
->args
, 0, full_name_str
);
9022 field_name
= mono_string_new_checked (domain
, mono_field_get_name (field
), error
);
9023 goto_if_nok (error
, return_null
);
9025 mono_array_setref_internal (msg
->args
, 1, field_name
);
9027 mono_remoting_invoke ((MonoObject
*)(tp
->rp
), msg
, &exc
, &out_args
, error
);
9028 goto_if_nok (error
, return_null
);
9031 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
9035 if (mono_array_length_internal (out_args
) == 0)
9038 mono_gc_wbarrier_generic_store_internal (res
, mono_array_get_internal (out_args
, MonoObject
*, 0));
9040 if (m_class_is_valuetype (field_class
)) {
9041 res
= (gpointer
*)mono_object_get_data ((MonoObject
*)*res
);
9053 * mono_load_remote_field_new:
9057 * Missing documentation.
9060 mono_load_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
)
9066 MONO_ENTER_GC_UNSAFE
;
9068 result
= mono_load_remote_field_new_checked (this_obj
, klass
, field
, error
);
9069 mono_error_cleanup (error
);
9071 MONO_EXIT_GC_UNSAFE
;
9077 * mono_load_remote_field_new_checked:
9078 * \param this pointer to an object
9079 * \param klass klass of the object containing \p field
9080 * \param field the field to load
9081 * \param error set on error.
9082 * This method is called by the runtime on attempts to load fields of
9083 * transparent proxy objects. \p this points to such TP, \p klass is the class of
9084 * the object containing \p field.
9085 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
9088 mono_load_remote_field_new_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoError
*error
)
9090 MONO_REQ_GC_UNSAFE_MODE
;
9094 g_assert (mono_object_is_transparent_proxy (this_obj
));
9096 MONO_STATIC_POINTER_INIT (MonoMethod
, tp_load
)
9098 tp_load
= mono_class_get_method_from_name_checked (mono_defaults
.transparent_proxy_class
, "LoadRemoteFieldNew", -1, 0, error
);
9099 return_val_if_nok (error
, NULL
);
9101 mono_error_set_not_supported (error
, "Linked away.");
9105 MONO_STATIC_POINTER_INIT_END (MonoMethod
, tp_load
)
9107 /* MonoType *type = m_class_get_byval_arg (klass); */
9109 gpointer args
[ ] = { &klass
, &field
};
9111 return mono_runtime_invoke_checked (tp_load
, this_obj
, args
, error
);
9115 * mono_store_remote_field:
9116 * \param this_obj pointer to an object
9117 * \param klass klass of the object containing \p field
9118 * \param field the field to load
9119 * \param val the value/object to store
9120 * This method is called by the runtime on attempts to store fields of
9121 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
9122 * the object containing \p field. \p val is the new value to store in \p field.
9125 mono_store_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
)
9127 MONO_ENTER_GC_UNSAFE
;
9130 (void) mono_store_remote_field_checked (this_obj
, klass
, field
, val
, error
);
9131 mono_error_cleanup (error
);
9133 MONO_EXIT_GC_UNSAFE
;
9137 * mono_store_remote_field_checked:
9138 * \param this_obj pointer to an object
9139 * \param klass klass of the object containing \p field
9140 * \param field the field to load
9141 * \param val the value/object to store
9142 * \param error set on error
9143 * This method is called by the runtime on attempts to store fields of
9144 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
9145 * the object containing \p field. \p val is the new value to store in \p field.
9146 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
9149 mono_store_remote_field_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
, MonoError
*error
)
9151 MONO_REQ_GC_UNSAFE_MODE
;
9155 MonoDomain
*domain
= mono_domain_get ();
9156 MonoClass
*field_class
;
9159 g_assert (mono_object_is_transparent_proxy (this_obj
));
9161 field_class
= mono_class_from_mono_type_internal (field
->type
);
9163 if (m_class_is_valuetype (field_class
)) {
9164 arg
= mono_value_box_checked (domain
, field_class
, val
, error
);
9165 return_val_if_nok (error
, FALSE
);
9167 arg
= *((MonoObject
**)val
);
9170 return mono_store_remote_field_new_checked (this_obj
, klass
, field
, arg
, error
);
9174 * mono_store_remote_field_new:
9179 * Missing documentation
9182 mono_store_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
)
9184 MONO_ENTER_GC_UNSAFE
;
9187 (void) mono_store_remote_field_new_checked (this_obj
, klass
, field
, arg
, error
);
9188 mono_error_cleanup (error
);
9190 MONO_EXIT_GC_UNSAFE
;
9194 * mono_store_remote_field_new_checked:
9200 * Missing documentation
9203 mono_store_remote_field_new_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
, MonoError
*error
)
9205 MONO_REQ_GC_UNSAFE_MODE
;
9209 g_assert (mono_object_is_transparent_proxy (this_obj
));
9211 MONO_STATIC_POINTER_INIT (MonoMethod
, tp_store
)
9213 tp_store
= mono_class_get_method_from_name_checked (mono_defaults
.transparent_proxy_class
, "StoreRemoteField", -1, 0, error
);
9214 return_val_if_nok (error
, FALSE
);
9216 mono_error_set_not_supported (error
, "Linked away.");
9220 MONO_STATIC_POINTER_INIT_END (MonoMethod
, tp_store
)
9222 gpointer args
[ ] = { &klass
, &field
, arg
};
9224 mono_runtime_invoke_checked (tp_store
, this_obj
, args
, error
);
9225 return is_ok (error
);
9230 * mono_create_ftnptr:
9232 * Given a function address, create a function descriptor for it.
9233 * This is only needed on some platforms.
9236 mono_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
9238 return callbacks
.create_ftnptr (domain
, addr
);
9242 * mono_get_addr_from_ftnptr:
9244 * Given a pointer to a function descriptor, return the function address.
9245 * This is only needed on some platforms.
9248 mono_get_addr_from_ftnptr (gpointer descr
)
9250 return callbacks
.get_addr_from_ftnptr (descr
);
9254 * mono_string_chars:
9255 * \param s a \c MonoString
9256 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
9259 mono_string_chars (MonoString
*s
)
9261 MONO_EXTERNAL_ONLY (mono_unichar2
*, mono_string_chars_internal (s
));
9265 * mono_string_length:
9266 * \param s MonoString
9267 * \returns the length in characters of the string
9270 mono_string_length (MonoString
*s
)
9272 MONO_EXTERNAL_ONLY (int, mono_string_length_internal (s
));
9276 * mono_array_length:
9277 * \param array a \c MonoArray*
9278 * \returns the total number of elements in the array. This works for
9279 * both vectors and multidimensional arrays.
9282 mono_array_length (MonoArray
*array
)
9284 MONO_EXTERNAL_ONLY (uintptr_t, mono_array_length_internal (array
));
9287 #ifdef ENABLE_CHECKED_BUILD_GC
9290 * mono_string_handle_length:
9291 * \param s \c MonoString
9292 * \returns the length in characters of the string
9295 mono_string_handle_length (MonoStringHandle s
)
9297 MONO_REQ_GC_UNSAFE_MODE
;
9299 return MONO_HANDLE_GETVAL (s
, length
);
9305 * mono_array_addr_with_size:
9306 * \param array a \c MonoArray*
9307 * \param size size of the array elements
9308 * \param idx index into the array
9309 * Use this function to obtain the address for the \p idx item on the
9310 * \p array containing elements of size \p size.
9312 * This method performs no bounds checking or type checking.
9313 * \returns the address of the \p idx element in the array.
9316 mono_array_addr_with_size (MonoArray
*array
, int size
, uintptr_t idx
)
9318 MONO_EXTERNAL_ONLY (char*, mono_array_addr_with_size_internal (array
, size
, idx
));
9322 mono_glist_to_array (GList
*list
, MonoClass
*eclass
, MonoError
*error
)
9324 MonoDomain
*domain
= mono_domain_get ();
9332 len
= g_list_length (list
);
9333 res
= mono_array_new_checked (domain
, eclass
, len
, error
);
9334 return_val_if_nok (error
, NULL
);
9336 for (i
= 0; list
; list
= list
->next
, i
++)
9337 mono_array_set_internal (res
, gpointer
, i
, list
->data
);
9343 * mono_class_value_size:
9344 * \param klass a class
9346 * This function is used for value types, and return the
9347 * space and the alignment to store that kind of value object.
9349 * \returns the size of a value of kind \p klass
9352 mono_class_value_size (MonoClass
*klass
, guint32
*align
)
9356 /* fixme: check disable, because we still have external revereces to
9357 * mscorlib and Dummy Objects
9359 /*g_assert (klass->valuetype);*/
9361 size
= mono_class_instance_size (klass
) - MONO_ABI_SIZEOF (MonoObject
);
9364 *align
= m_class_get_min_align (klass
);
9370 * mono_vtype_get_field_addr:
9372 * Return the address of the FIELD in the valuetype VTYPE.
9375 mono_vtype_get_field_addr (gpointer vtype
, MonoClassField
*field
)
9377 return ((char*)vtype
) + field
->offset
- MONO_ABI_SIZEOF (MonoObject
);
9383 * The following section is purely to declare prototypes and
9384 * document the API, as these C files are processed by our
9390 * \param array array to alter
9391 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
9392 * \param index index into the array
9393 * \param value value to set
9394 * Value Type version: This sets the \p index's element of the \p array
9395 * with elements of size sizeof(type) to the provided \p value.
9397 * This macro does not attempt to perform type checking or bounds checking
9398 * and it doesn't execute any write barriers.
9400 * Use this to set value types in a \c MonoArray. This shouldn't be used if
9401 * the copied value types contain references. Use \c mono_gc_wbarrier_value_copy
9402 * instead when also copying references.
9404 void mono_array_set(MonoArray
*array
, Type element_type
, uintptr_t index
, Value value
)
9409 * mono_array_setref:
9410 * \param array array to alter
9411 * \param index index into the array
9412 * \param value value to set
9413 * Reference Type version. This sets the \p index's element of the
9414 * \p array with elements of size sizeof(type) to the provided \p value.
9416 * This macro does not attempt to perform type checking or bounds checking.
9418 * Use this to reference types in a \c MonoArray.
9420 void mono_array_setref(MonoArray
*array
, uintptr_t index
, MonoObject
*object
)
9426 * \param array array on which to operate on
9427 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
9428 * \param index index into the array
9430 * Use this macro to retrieve the \p index element of an \p array and
9431 * extract the value assuming that the elements of the array match
9432 * the provided type value.
9434 * This method can be used with both arrays holding value types and
9435 * reference types. For reference types, the \p type parameter should
9436 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
9438 * This macro does not attempt to perform type checking or bounds checking.
9440 * \returns The element at the \p index position in the \p array.
9442 Type
mono_array_get_internal (MonoArray
*array
, Type element_type
, uintptr_t index
)