2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/metadata/w32event.h>
45 #include <mono/utils/strenc.h>
46 #include <mono/utils/mono-counters.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-memory-model.h>
49 #include <mono/utils/checked-build.h>
50 #include <mono/utils/mono-threads.h>
51 #include <mono/utils/mono-threads-coop.h>
52 #include "cominterop.h"
55 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
, MonoError
*error
);
58 mono_ldstr_metadata_sig (MonoDomain
*domain
, const char* sig
, MonoError
*error
);
61 free_main_args (void);
64 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, gboolean ignore_error
, MonoError
*error
);
66 /* Class lazy loading functions */
67 static GENERATE_GET_CLASS_WITH_CACHE (pointer
, System
.Reflection
, Pointer
)
68 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services
, System
.Runtime
.Remoting
, RemotingServices
)
69 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args
, System
, UnhandledExceptionEventArgs
)
70 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute
, System
, STAThreadAttribute
)
71 static GENERATE_GET_CLASS_WITH_CACHE (activation_services
, System
.Runtime
.Remoting
.Activation
, ActivationServices
)
74 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
75 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
76 static mono_mutex_t ldstr_section
;
79 * mono_runtime_object_init:
80 * @this_obj: the object to initialize
82 * This function calls the zero-argument constructor (which must
83 * exist) for the given object.
86 mono_runtime_object_init (MonoObject
*this_obj
)
89 mono_runtime_object_init_checked (this_obj
, &error
);
90 mono_error_assert_ok (&error
);
94 * mono_runtime_object_init_checked:
95 * @this_obj: the object to initialize
96 * @error: set on error.
98 * This function calls the zero-argument constructor (which must
99 * exist) for the given object and returns TRUE on success, or FALSE
100 * on error and sets @error.
103 mono_runtime_object_init_checked (MonoObject
*this_obj
, MonoError
*error
)
105 MONO_REQ_GC_UNSAFE_MODE
;
107 MonoMethod
*method
= NULL
;
108 MonoClass
*klass
= this_obj
->vtable
->klass
;
110 mono_error_init (error
);
111 method
= mono_class_get_method_from_name (klass
, ".ctor", 0);
113 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass
));
115 if (method
->klass
->valuetype
)
116 this_obj
= (MonoObject
*)mono_object_unbox (this_obj
);
118 mono_runtime_invoke_checked (method
, this_obj
, NULL
, error
);
119 return is_ok (error
);
122 /* The pseudo algorithm for type initialization from the spec
123 Note it doesn't say anything about domains - only threads.
125 2. If the type is initialized you are done.
126 2.1. If the type is not yet initialized, try to take an
128 2.2. If successful, record this thread as responsible for
129 initializing the type and proceed to step 2.3.
130 2.2.1. If not, see whether this thread or any thread
131 waiting for this thread to complete already holds the lock.
132 2.2.2. If so, return since blocking would create a deadlock. This thread
133 will now see an incompletely initialized state for the type,
134 but no deadlock will arise.
135 2.2.3 If not, block until the type is initialized then return.
136 2.3 Initialize the parent type and then all interfaces implemented
138 2.4 Execute the type initialization code for this type.
139 2.5 Mark the type as initialized, release the initialization lock,
140 awaken any threads waiting for this type to be initialized,
147 MonoNativeThreadId initializing_tid
;
148 guint32 waiting_count
;
150 MonoCoopMutex initialization_section
;
151 } TypeInitializationLock
;
153 /* for locking access to type_initialization_hash and blocked_thread_hash */
154 static MonoCoopMutex type_initialization_section
;
157 mono_type_initialization_lock (void)
159 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
160 mono_coop_mutex_lock (&type_initialization_section
);
164 mono_type_initialization_unlock (void)
166 mono_coop_mutex_unlock (&type_initialization_section
);
170 mono_type_init_lock (TypeInitializationLock
*lock
)
172 MONO_REQ_GC_NEUTRAL_MODE
;
174 mono_coop_mutex_lock (&lock
->initialization_section
);
178 mono_type_init_unlock (TypeInitializationLock
*lock
)
180 mono_coop_mutex_unlock (&lock
->initialization_section
);
183 /* from vtable to lock */
184 static GHashTable
*type_initialization_hash
;
186 /* from thread id to thread id being waited on */
187 static GHashTable
*blocked_thread_hash
;
190 static MonoThread
*main_thread
;
192 /* Functions supplied by the runtime */
193 static MonoRuntimeCallbacks callbacks
;
196 * mono_thread_set_main:
197 * @thread: thread to set as the main thread
199 * This function can be used to instruct the runtime to treat @thread
200 * as the main thread, ie, the thread that would normally execute the Main()
201 * method. This basically means that at the end of @thread, the runtime will
202 * wait for the existing foreground threads to quit and other such details.
205 mono_thread_set_main (MonoThread
*thread
)
207 MONO_REQ_GC_UNSAFE_MODE
;
209 static gboolean registered
= FALSE
;
212 MONO_GC_REGISTER_ROOT_SINGLE (main_thread
, MONO_ROOT_SOURCE_THREADING
, "main thread object");
216 main_thread
= thread
;
220 mono_thread_get_main (void)
222 MONO_REQ_GC_UNSAFE_MODE
;
228 mono_type_initialization_init (void)
230 mono_coop_mutex_init_recursive (&type_initialization_section
);
231 type_initialization_hash
= g_hash_table_new (NULL
, NULL
);
232 blocked_thread_hash
= g_hash_table_new (NULL
, NULL
);
233 mono_os_mutex_init_recursive (&ldstr_section
);
237 mono_type_initialization_cleanup (void)
240 /* This is causing race conditions with
241 * mono_release_type_locks
243 mono_coop_mutex_destroy (&type_initialization_section
);
244 g_hash_table_destroy (type_initialization_hash
);
245 type_initialization_hash
= NULL
;
247 mono_os_mutex_destroy (&ldstr_section
);
248 g_hash_table_destroy (blocked_thread_hash
);
249 blocked_thread_hash
= NULL
;
255 * get_type_init_exception_for_vtable:
257 * Return the stored type initialization exception for VTABLE.
259 static MonoException
*
260 get_type_init_exception_for_vtable (MonoVTable
*vtable
)
262 MONO_REQ_GC_UNSAFE_MODE
;
265 MonoDomain
*domain
= vtable
->domain
;
266 MonoClass
*klass
= vtable
->klass
;
270 if (!vtable
->init_failed
)
271 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass
));
274 * If the initializing thread was rudely aborted, the exception is not stored
278 mono_domain_lock (domain
);
279 if (domain
->type_init_exception_hash
)
280 ex
= (MonoException
*)mono_g_hash_table_lookup (domain
->type_init_exception_hash
, klass
);
281 mono_domain_unlock (domain
);
284 if (klass
->name_space
&& *klass
->name_space
)
285 full_name
= g_strdup_printf ("%s.%s", klass
->name_space
, klass
->name
);
287 full_name
= g_strdup (klass
->name
);
288 ex
= mono_get_exception_type_initialization_checked (full_name
, NULL
, &error
);
290 return_val_if_nok (&error
, NULL
);
297 * mono_runtime_class_init:
298 * @vtable: vtable that needs to be initialized
300 * This routine calls the class constructor for @vtable.
303 mono_runtime_class_init (MonoVTable
*vtable
)
305 MONO_REQ_GC_UNSAFE_MODE
;
308 mono_runtime_class_init_full (vtable
, &error
);
309 mono_error_assert_ok (&error
);
313 * mono_runtime_class_init_full:
314 * @vtable that neeeds to be initialized
315 * @error set on error
317 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
321 mono_runtime_class_init_full (MonoVTable
*vtable
, MonoError
*error
)
323 MONO_REQ_GC_UNSAFE_MODE
;
325 MonoMethod
*method
= NULL
;
328 MonoDomain
*domain
= vtable
->domain
;
329 TypeInitializationLock
*lock
;
330 MonoNativeThreadId tid
;
331 int do_initialization
= 0;
332 MonoDomain
*last_domain
= NULL
;
333 MonoException
* pending_tae
= NULL
;
335 mono_error_init (error
);
337 if (vtable
->initialized
)
340 klass
= vtable
->klass
;
342 if (!klass
->image
->checked_module_cctor
) {
343 mono_image_check_for_module_cctor (klass
->image
);
344 if (klass
->image
->has_module_cctor
) {
345 MonoClass
*module_klass
;
346 MonoVTable
*module_vtable
;
348 module_klass
= mono_class_get_checked (klass
->image
, MONO_TOKEN_TYPE_DEF
| 1, error
);
353 module_vtable
= mono_class_vtable_full (vtable
->domain
, module_klass
, error
);
356 if (!mono_runtime_class_init_full (module_vtable
, error
))
360 method
= mono_class_get_cctor (klass
);
362 vtable
->initialized
= 1;
366 tid
= mono_native_thread_id_get ();
368 mono_type_initialization_lock ();
369 /* double check... */
370 if (vtable
->initialized
) {
371 mono_type_initialization_unlock ();
374 if (vtable
->init_failed
) {
375 mono_type_initialization_unlock ();
377 /* The type initialization already failed once, rethrow the same exception */
378 mono_error_set_exception_instance (error
, get_type_init_exception_for_vtable (vtable
));
381 lock
= (TypeInitializationLock
*)g_hash_table_lookup (type_initialization_hash
, vtable
);
383 /* This thread will get to do the initialization */
384 if (mono_domain_get () != domain
) {
385 /* Transfer into the target domain */
386 last_domain
= mono_domain_get ();
387 if (!mono_domain_set (domain
, FALSE
)) {
388 vtable
->initialized
= 1;
389 mono_type_initialization_unlock ();
390 mono_error_set_exception_instance (error
, mono_get_exception_appdomain_unloaded ());
394 lock
= (TypeInitializationLock
*)g_malloc (sizeof (TypeInitializationLock
));
395 mono_coop_mutex_init_recursive (&lock
->initialization_section
);
396 lock
->initializing_tid
= tid
;
397 lock
->waiting_count
= 1;
399 /* grab the vtable lock while this thread still owns type_initialization_section */
400 /* This is why type_initialization_lock needs to enter blocking mode */
401 mono_type_init_lock (lock
);
402 g_hash_table_insert (type_initialization_hash
, vtable
, lock
);
403 do_initialization
= 1;
406 TypeInitializationLock
*pending_lock
;
408 if (mono_native_thread_id_equals (lock
->initializing_tid
, tid
) || lock
->done
) {
409 mono_type_initialization_unlock ();
412 /* see if the thread doing the initialization is already blocked on this thread */
413 blocked
= GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock
->initializing_tid
));
414 while ((pending_lock
= (TypeInitializationLock
*) g_hash_table_lookup (blocked_thread_hash
, blocked
))) {
415 if (mono_native_thread_id_equals (pending_lock
->initializing_tid
, tid
)) {
416 if (!pending_lock
->done
) {
417 mono_type_initialization_unlock ();
420 /* the thread doing the initialization is blocked on this thread,
421 but on a lock that has already been freed. It just hasn't got
426 blocked
= GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock
->initializing_tid
));
428 ++lock
->waiting_count
;
429 /* record the fact that we are waiting on the initializing thread */
430 g_hash_table_insert (blocked_thread_hash
, GUINT_TO_POINTER (tid
), lock
);
432 mono_type_initialization_unlock ();
434 if (do_initialization
) {
435 MonoException
*exc
= NULL
;
437 mono_threads_begin_abort_protected_block ();
438 mono_runtime_try_invoke (method
, NULL
, NULL
, (MonoObject
**) &exc
, error
);
439 mono_threads_end_abort_protected_block ();
441 //exception extracted, error will be set to the right value later
442 if (exc
== NULL
&& !mono_error_ok (error
))//invoking failed but exc was not set
443 exc
= mono_error_convert_to_exception (error
);
445 mono_error_cleanup (error
);
447 mono_error_init (error
);
449 /* If the initialization failed, mark the class as unusable. */
450 /* Avoid infinite loops */
452 (klass
->image
== mono_defaults
.corlib
&&
453 !strcmp (klass
->name_space
, "System") &&
454 !strcmp (klass
->name
, "TypeInitializationException")))) {
455 vtable
->init_failed
= 1;
457 if (klass
->name_space
&& *klass
->name_space
)
458 full_name
= g_strdup_printf ("%s.%s", klass
->name_space
, klass
->name
);
460 full_name
= g_strdup (klass
->name
);
462 MonoException
*exc_to_throw
= mono_get_exception_type_initialization_checked (full_name
, exc
, error
);
465 mono_error_assert_ok (error
); //We can't recover from this, no way to fail a type we can't alloc a failure.
468 * Store the exception object so it could be thrown on subsequent
471 mono_domain_lock (domain
);
472 if (!domain
->type_init_exception_hash
)
473 domain
->type_init_exception_hash
= mono_g_hash_table_new_type (mono_aligned_addr_hash
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_DOMAIN
, "type initialization exceptions table");
474 mono_g_hash_table_insert (domain
->type_init_exception_hash
, klass
, exc_to_throw
);
475 mono_domain_unlock (domain
);
479 mono_domain_set (last_domain
, TRUE
);
481 mono_type_init_unlock (lock
);
482 if (exc
&& mono_object_class (exc
) == mono_defaults
.threadabortexception_class
)
484 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
486 pending_tae
= mono_thread_try_resume_interruption ();
488 /* this just blocks until the initializing thread is done */
489 mono_type_init_lock (lock
);
490 mono_type_init_unlock (lock
);
493 mono_type_initialization_lock ();
494 if (!mono_native_thread_id_equals (lock
->initializing_tid
, tid
))
495 g_hash_table_remove (blocked_thread_hash
, GUINT_TO_POINTER (tid
));
496 --lock
->waiting_count
;
497 if (lock
->waiting_count
== 0) {
498 mono_coop_mutex_destroy (&lock
->initialization_section
);
499 g_hash_table_remove (type_initialization_hash
, vtable
);
502 mono_memory_barrier ();
503 if (!vtable
->init_failed
)
504 vtable
->initialized
= 1;
505 mono_type_initialization_unlock ();
509 mono_error_set_exception_instance (error
, pending_tae
);
510 else if (vtable
->init_failed
) {
511 /* Either we were the initializing thread or we waited for the initialization */
512 mono_error_set_exception_instance (error
, get_type_init_exception_for_vtable (vtable
));
519 gboolean
release_type_locks (gpointer key
, gpointer value
, gpointer user
)
521 MONO_REQ_GC_NEUTRAL_MODE
;
523 MonoVTable
*vtable
= (MonoVTable
*)key
;
525 TypeInitializationLock
*lock
= (TypeInitializationLock
*) value
;
526 if (mono_native_thread_id_equals (lock
->initializing_tid
, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user
))) && !lock
->done
) {
529 * Have to set this since it cannot be set by the normal code in
530 * mono_runtime_class_init (). In this case, the exception object is not stored,
531 * and get_type_init_exception_for_class () needs to be aware of this.
533 vtable
->init_failed
= 1;
534 mono_type_init_unlock (lock
);
535 --lock
->waiting_count
;
536 if (lock
->waiting_count
== 0) {
537 mono_coop_mutex_destroy (&lock
->initialization_section
);
546 mono_release_type_locks (MonoInternalThread
*thread
)
548 MONO_REQ_GC_UNSAFE_MODE
;
550 mono_type_initialization_lock ();
551 g_hash_table_foreach_remove (type_initialization_hash
, release_type_locks
, GUINT_TO_POINTER (thread
->tid
));
552 mono_type_initialization_unlock ();
555 #ifndef DISABLE_REMOTING
558 default_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
560 g_error ("remoting not installed");
564 static MonoRemotingTrampoline arch_create_remoting_trampoline
= default_remoting_trampoline
;
568 default_delegate_trampoline (MonoDomain
*domain
, MonoClass
*klass
)
570 g_assert_not_reached ();
574 static MonoDelegateTrampoline arch_create_delegate_trampoline
= default_delegate_trampoline
;
575 static MonoImtTrampolineBuilder imt_trampoline_builder
;
576 static gboolean always_build_imt_trampolines
;
578 #if (MONO_IMT_SIZE > 32)
579 #error "MONO_IMT_SIZE cannot be larger than 32"
583 mono_install_callbacks (MonoRuntimeCallbacks
*cbs
)
585 memcpy (&callbacks
, cbs
, sizeof (*cbs
));
588 MonoRuntimeCallbacks
*
589 mono_get_runtime_callbacks (void)
594 #ifndef DISABLE_REMOTING
596 mono_install_remoting_trampoline (MonoRemotingTrampoline func
)
598 arch_create_remoting_trampoline
= func
? func
: default_remoting_trampoline
;
603 mono_install_delegate_trampoline (MonoDelegateTrampoline func
)
605 arch_create_delegate_trampoline
= func
? func
: default_delegate_trampoline
;
609 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func
)
611 imt_trampoline_builder
= func
;
615 mono_set_always_build_imt_trampolines (gboolean value
)
617 always_build_imt_trampolines
= value
;
621 * mono_compile_method:
622 * @method: The method to compile.
624 * This JIT-compiles the method, and returns the pointer to the native code
628 mono_compile_method (MonoMethod
*method
)
631 gpointer result
= mono_compile_method_checked (method
, &error
);
632 mono_error_cleanup (&error
);
637 * mono_compile_method:
638 * @method: The method to compile.
639 * @error: set on error.
641 * This JIT-compiles the method, and returns the pointer to the native code
642 * produced. On failure returns NULL and sets @error.
645 mono_compile_method_checked (MonoMethod
*method
, MonoError
*error
)
649 MONO_REQ_GC_NEUTRAL_MODE
651 mono_error_init (error
);
653 if (!callbacks
.compile_method
) {
654 g_error ("compile method called on uninitialized runtime");
657 res
= callbacks
.compile_method (method
, error
);
662 mono_runtime_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
, MonoError
*error
)
666 MONO_REQ_GC_NEUTRAL_MODE
;
668 mono_error_init (error
);
669 res
= callbacks
.create_jump_trampoline (domain
, method
, add_sync_wrapper
, error
);
674 mono_runtime_create_delegate_trampoline (MonoClass
*klass
)
676 MONO_REQ_GC_NEUTRAL_MODE
678 return arch_create_delegate_trampoline (mono_domain_get (), klass
);
681 static MonoFreeMethodFunc default_mono_free_method
= NULL
;
684 * mono_install_free_method:
685 * @func: pointer to the MonoFreeMethodFunc used to release a method
687 * This is an internal VM routine, it is used for the engines to
688 * register a handler to release the resources associated with a method.
690 * Methods are freed when no more references to the delegate that holds
694 mono_install_free_method (MonoFreeMethodFunc func
)
696 default_mono_free_method
= func
;
700 * mono_runtime_free_method:
701 * @domain; domain where the method is hosted
702 * @method: method to release
704 * This routine is invoked to free the resources associated with
705 * a method that has been JIT compiled. This is used to discard
706 * methods that were used only temporarily (for example, used in marshalling)
710 mono_runtime_free_method (MonoDomain
*domain
, MonoMethod
*method
)
712 MONO_REQ_GC_NEUTRAL_MODE
714 if (default_mono_free_method
!= NULL
)
715 default_mono_free_method (domain
, method
);
717 mono_method_clear_object (domain
, method
);
719 mono_free_method (method
);
723 * The vtables in the root appdomain are assumed to be reachable by other
724 * roots, and we don't use typed allocation in the other domains.
727 /* The sync block is no longer a GC pointer */
728 #define GC_HEADER_BITMAP (0)
730 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
733 compute_class_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
, int *max_set
, gboolean static_fields
)
735 MONO_REQ_GC_NEUTRAL_MODE
;
737 MonoClassField
*field
;
743 max_size
= mono_class_data_size (klass
) / sizeof (gpointer
);
745 max_size
= klass
->instance_size
/ sizeof (gpointer
);
746 if (max_size
> size
) {
747 g_assert (offset
<= 0);
748 bitmap
= (gsize
*)g_malloc0 ((max_size
+ BITMAP_EL_SIZE
- 1) / BITMAP_EL_SIZE
* sizeof (gsize
));
753 /*An Ephemeron cannot be marked by sgen*/
754 if (!static_fields
&& klass
->image
== mono_defaults
.corlib
&& !strcmp ("Ephemeron", klass
->name
)) {
756 memset (bitmap
, 0, size
/ 8);
761 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
762 gpointer iter
= NULL
;
763 while ((field
= mono_class_get_fields (p
, &iter
))) {
767 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
769 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
772 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
775 /* FIXME: should not happen, flag as type load error */
776 if (field
->type
->byref
)
779 if (static_fields
&& field
->offset
== -1)
783 pos
= field
->offset
/ sizeof (gpointer
);
786 type
= mono_type_get_underlying_type (field
->type
);
787 switch (type
->type
) {
790 case MONO_TYPE_FNPTR
:
792 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
797 if (klass
->image
!= mono_defaults
.corlib
)
800 case MONO_TYPE_STRING
:
801 case MONO_TYPE_SZARRAY
:
802 case MONO_TYPE_CLASS
:
803 case MONO_TYPE_OBJECT
:
804 case MONO_TYPE_ARRAY
:
805 g_assert ((field
->offset
% sizeof(gpointer
)) == 0);
807 g_assert (pos
< size
|| pos
<= max_size
);
808 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
809 *max_set
= MAX (*max_set
, pos
);
811 case MONO_TYPE_GENERICINST
:
812 if (!mono_type_generic_inst_is_valuetype (type
)) {
813 g_assert ((field
->offset
% sizeof(gpointer
)) == 0);
815 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
816 *max_set
= MAX (*max_set
, pos
);
821 case MONO_TYPE_VALUETYPE
: {
822 MonoClass
*fclass
= mono_class_from_mono_type (field
->type
);
823 if (fclass
->has_references
) {
824 /* remove the object header */
825 compute_class_bitmap (fclass
, bitmap
, size
, pos
- (sizeof (MonoObject
) / sizeof (gpointer
)), max_set
, FALSE
);
839 case MONO_TYPE_BOOLEAN
:
843 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type
->type
, mono_type_get_full_name (field
->parent
), field
->name
);
854 * mono_class_compute_bitmap:
856 * Mono internal function to compute a bitmap of reference fields in a class.
859 mono_class_compute_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
, int *max_set
, gboolean static_fields
)
861 MONO_REQ_GC_NEUTRAL_MODE
;
863 return compute_class_bitmap (klass
, bitmap
, size
, offset
, max_set
, static_fields
);
868 * similar to the above, but sets the bits in the bitmap for any non-ref field
869 * and ignores static fields
872 compute_class_non_ref_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
)
874 MonoClassField
*field
;
879 max_size
= class->instance_size
/ sizeof (gpointer
);
880 if (max_size
>= size
) {
881 bitmap
= g_malloc0 (sizeof (gsize
) * ((max_size
) + 1));
884 for (p
= class; p
!= NULL
; p
= p
->parent
) {
885 gpointer iter
= NULL
;
886 while ((field
= mono_class_get_fields (p
, &iter
))) {
889 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
891 /* FIXME: should not happen, flag as type load error */
892 if (field
->type
->byref
)
895 pos
= field
->offset
/ sizeof (gpointer
);
898 type
= mono_type_get_underlying_type (field
->type
);
899 switch (type
->type
) {
900 #if SIZEOF_VOID_P == 8
904 case MONO_TYPE_FNPTR
:
909 if ((((field
->offset
+ 7) / sizeof (gpointer
)) + offset
) != pos
) {
910 pos2
= ((field
->offset
+ 7) / sizeof (gpointer
)) + offset
;
911 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
914 #if SIZEOF_VOID_P == 4
918 case MONO_TYPE_FNPTR
:
923 if ((((field
->offset
+ 3) / sizeof (gpointer
)) + offset
) != pos
) {
924 pos2
= ((field
->offset
+ 3) / sizeof (gpointer
)) + offset
;
925 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
931 if ((((field
->offset
+ 1) / sizeof (gpointer
)) + offset
) != pos
) {
932 pos2
= ((field
->offset
+ 1) / sizeof (gpointer
)) + offset
;
933 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
936 case MONO_TYPE_BOOLEAN
:
939 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
941 case MONO_TYPE_STRING
:
942 case MONO_TYPE_SZARRAY
:
943 case MONO_TYPE_CLASS
:
944 case MONO_TYPE_OBJECT
:
945 case MONO_TYPE_ARRAY
:
947 case MONO_TYPE_GENERICINST
:
948 if (!mono_type_generic_inst_is_valuetype (type
)) {
953 case MONO_TYPE_VALUETYPE
: {
954 MonoClass
*fclass
= mono_class_from_mono_type (field
->type
);
955 /* remove the object header */
956 compute_class_non_ref_bitmap (fclass
, bitmap
, size
, pos
- (sizeof (MonoObject
) / sizeof (gpointer
)));
960 g_assert_not_reached ();
969 * mono_class_insecure_overlapping:
970 * check if a class with explicit layout has references and non-references
971 * fields overlapping.
973 * Returns: TRUE if it is insecure to load the type.
976 mono_class_insecure_overlapping (MonoClass
*klass
)
980 gsize default_bitmap
[4] = {0};
982 gsize default_nrbitmap
[4] = {0};
983 int i
, insecure
= FALSE
;
986 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
987 nrbitmap
= compute_class_non_ref_bitmap (klass
, default_nrbitmap
, sizeof (default_nrbitmap
) * 8, 0);
989 for (i
= 0; i
<= max_set
; i
+= sizeof (bitmap
[0]) * 8) {
990 int idx
= i
% (sizeof (bitmap
[0]) * 8);
991 if (bitmap
[idx
] & nrbitmap
[idx
]) {
996 if (bitmap
!= default_bitmap
)
998 if (nrbitmap
!= default_nrbitmap
)
1001 g_print ("class %s.%s in assembly %s has overlapping references\n", klass
->name_space
, klass
->name
, klass
->image
->name
);
1009 ves_icall_string_alloc (int length
)
1012 MonoString
*str
= mono_string_new_size_checked (mono_domain_get (), length
, &error
);
1013 mono_error_set_pending_exception (&error
);
1019 mono_class_compute_gc_descriptor (MonoClass
*klass
)
1021 MONO_REQ_GC_NEUTRAL_MODE
;
1025 gsize default_bitmap
[4] = {0};
1026 static gboolean gcj_inited
= FALSE
;
1029 mono_loader_lock ();
1031 mono_register_jit_icall (ves_icall_object_new_fast
, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE
);
1032 mono_register_jit_icall (ves_icall_string_alloc
, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE
);
1035 mono_loader_unlock ();
1039 mono_class_init (klass
);
1041 if (klass
->gc_descr_inited
)
1044 klass
->gc_descr_inited
= TRUE
;
1045 klass
->gc_descr
= MONO_GC_DESCRIPTOR_NULL
;
1047 bitmap
= default_bitmap
;
1048 if (klass
== mono_defaults
.string_class
) {
1049 klass
->gc_descr
= mono_gc_make_descr_for_string (bitmap
, 2);
1050 } else if (klass
->rank
) {
1051 mono_class_compute_gc_descriptor (klass
->element_class
);
1052 if (MONO_TYPE_IS_REFERENCE (&klass
->element_class
->byval_arg
)) {
1054 klass
->gc_descr
= mono_gc_make_descr_for_array (klass
->byval_arg
.type
== MONO_TYPE_SZARRAY
, &abm
, 1, sizeof (gpointer
));
1055 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1056 class->name_space, class->name);*/
1058 /* remove the object header */
1059 bitmap
= compute_class_bitmap (klass
->element_class
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(sizeof (MonoObject
) / sizeof (gpointer
)), &max_set
, FALSE
);
1060 klass
->gc_descr
= mono_gc_make_descr_for_array (klass
->byval_arg
.type
== MONO_TYPE_SZARRAY
, bitmap
, mono_array_element_size (klass
) / sizeof (gpointer
), mono_array_element_size (klass
));
1061 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1062 class->name_space, class->name);*/
1063 if (bitmap
!= default_bitmap
)
1067 /*static int count = 0;
1070 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
1071 klass
->gc_descr
= mono_gc_make_descr_for_object (bitmap
, max_set
+ 1, klass
->instance_size
);
1073 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1074 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1076 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1077 if (bitmap
!= default_bitmap
)
1083 * field_is_special_static:
1084 * @fklass: The MonoClass to look up.
1085 * @field: The MonoClassField describing the field.
1087 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1088 * SPECIAL_STATIC_NONE otherwise.
1091 field_is_special_static (MonoClass
*fklass
, MonoClassField
*field
)
1093 MONO_REQ_GC_NEUTRAL_MODE
;
1096 MonoCustomAttrInfo
*ainfo
;
1098 ainfo
= mono_custom_attrs_from_field_checked (fklass
, field
, &error
);
1099 mono_error_cleanup (&error
); /* FIXME don't swallow the error? */
1102 for (i
= 0; i
< ainfo
->num_attrs
; ++i
) {
1103 MonoClass
*klass
= ainfo
->attrs
[i
].ctor
->klass
;
1104 if (klass
->image
== mono_defaults
.corlib
) {
1105 if (strcmp (klass
->name
, "ThreadStaticAttribute") == 0) {
1106 mono_custom_attrs_free (ainfo
);
1107 return SPECIAL_STATIC_THREAD
;
1109 else if (strcmp (klass
->name
, "ContextStaticAttribute") == 0) {
1110 mono_custom_attrs_free (ainfo
);
1111 return SPECIAL_STATIC_CONTEXT
;
1115 mono_custom_attrs_free (ainfo
);
1116 return SPECIAL_STATIC_NONE
;
1119 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1120 #define mix(a,b,c) { \
1121 a -= c; a ^= rot(c, 4); c += b; \
1122 b -= a; b ^= rot(a, 6); a += c; \
1123 c -= b; c ^= rot(b, 8); b += a; \
1124 a -= c; a ^= rot(c,16); c += b; \
1125 b -= a; b ^= rot(a,19); a += c; \
1126 c -= b; c ^= rot(b, 4); b += a; \
1128 #define final(a,b,c) { \
1129 c ^= b; c -= rot(b,14); \
1130 a ^= c; a -= rot(c,11); \
1131 b ^= a; b -= rot(a,25); \
1132 c ^= b; c -= rot(b,16); \
1133 a ^= c; a -= rot(c,4); \
1134 b ^= a; b -= rot(a,14); \
1135 c ^= b; c -= rot(b,24); \
1139 * mono_method_get_imt_slot:
1141 * The IMT slot is embedded into AOTed code, so this must return the same value
1142 * for the same method across all executions. This means:
1143 * - pointers shouldn't be used as hash values.
1144 * - mono_metadata_str_hash () should be used for hashing strings.
1147 mono_method_get_imt_slot (MonoMethod
*method
)
1149 MONO_REQ_GC_NEUTRAL_MODE
;
1151 MonoMethodSignature
*sig
;
1153 guint32
*hashes_start
, *hashes
;
1157 /* This can be used to stress tests the collision code */
1161 * We do this to simplify generic sharing. It will hurt
1162 * performance in cases where a class implements two different
1163 * instantiations of the same generic interface.
1164 * The code in build_imt_slots () depends on this.
1166 if (method
->is_inflated
)
1167 method
= ((MonoMethodInflated
*)method
)->declaring
;
1169 sig
= mono_method_signature (method
);
1170 hashes_count
= sig
->param_count
+ 4;
1171 hashes_start
= (guint32
*)malloc (hashes_count
* sizeof (guint32
));
1172 hashes
= hashes_start
;
1174 if (! MONO_CLASS_IS_INTERFACE (method
->klass
)) {
1175 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1176 method
->klass
->name_space
, method
->klass
->name
, method
->name
);
1179 /* Initialize hashes */
1180 hashes
[0] = mono_metadata_str_hash (method
->klass
->name
);
1181 hashes
[1] = mono_metadata_str_hash (method
->klass
->name_space
);
1182 hashes
[2] = mono_metadata_str_hash (method
->name
);
1183 hashes
[3] = mono_metadata_type_hash (sig
->ret
);
1184 for (i
= 0; i
< sig
->param_count
; i
++) {
1185 hashes
[4 + i
] = mono_metadata_type_hash (sig
->params
[i
]);
1188 /* Setup internal state */
1189 a
= b
= c
= 0xdeadbeef + (((guint32
)hashes_count
)<<2);
1191 /* Handle most of the hashes */
1192 while (hashes_count
> 3) {
1201 /* Handle the last 3 hashes (all the case statements fall through) */
1202 switch (hashes_count
) {
1203 case 3 : c
+= hashes
[2];
1204 case 2 : b
+= hashes
[1];
1205 case 1 : a
+= hashes
[0];
1207 case 0: /* nothing left to add */
1211 g_free (hashes_start
);
1212 /* Report the result */
1213 return c
% MONO_IMT_SIZE
;
1222 add_imt_builder_entry (MonoImtBuilderEntry
**imt_builder
, MonoMethod
*method
, guint32
*imt_collisions_bitmap
, int vtable_slot
, int slot_num
) {
1223 MONO_REQ_GC_NEUTRAL_MODE
;
1225 guint32 imt_slot
= mono_method_get_imt_slot (method
);
1226 MonoImtBuilderEntry
*entry
;
1228 if (slot_num
>= 0 && imt_slot
!= slot_num
) {
1229 /* we build just a single imt slot and this is not it */
1233 entry
= (MonoImtBuilderEntry
*)g_malloc0 (sizeof (MonoImtBuilderEntry
));
1234 entry
->key
= method
;
1235 entry
->value
.vtable_slot
= vtable_slot
;
1236 entry
->next
= imt_builder
[imt_slot
];
1237 if (imt_builder
[imt_slot
] != NULL
) {
1238 entry
->children
= imt_builder
[imt_slot
]->children
+ 1;
1239 if (entry
->children
== 1) {
1240 mono_stats
.imt_slots_with_collisions
++;
1241 *imt_collisions_bitmap
|= (1 << imt_slot
);
1244 entry
->children
= 0;
1245 mono_stats
.imt_used_slots
++;
1247 imt_builder
[imt_slot
] = entry
;
1250 char *method_name
= mono_method_full_name (method
, TRUE
);
1251 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1252 method
, method_name
, imt_slot
, vtable_slot
, entry
->children
);
1253 g_free (method_name
);
1260 print_imt_entry (const char* message
, MonoImtBuilderEntry
*e
, int num
) {
1262 MonoMethod
*method
= e
->key
;
1263 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1267 method
->klass
->name_space
,
1268 method
->klass
->name
,
1271 printf (" * %s: NULL\n", message
);
1277 compare_imt_builder_entries (const void *p1
, const void *p2
) {
1278 MonoImtBuilderEntry
*e1
= *(MonoImtBuilderEntry
**) p1
;
1279 MonoImtBuilderEntry
*e2
= *(MonoImtBuilderEntry
**) p2
;
1281 return (e1
->key
< e2
->key
) ? -1 : ((e1
->key
> e2
->key
) ? 1 : 0);
1285 imt_emit_ir (MonoImtBuilderEntry
**sorted_array
, int start
, int end
, GPtrArray
*out_array
)
1287 MONO_REQ_GC_NEUTRAL_MODE
;
1289 int count
= end
- start
;
1290 int chunk_start
= out_array
->len
;
1293 for (i
= start
; i
< end
; ++i
) {
1294 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1295 item
->key
= sorted_array
[i
]->key
;
1296 item
->value
= sorted_array
[i
]->value
;
1297 item
->has_target_code
= sorted_array
[i
]->has_target_code
;
1298 item
->is_equals
= TRUE
;
1300 item
->check_target_idx
= out_array
->len
+ 1;
1302 item
->check_target_idx
= 0;
1303 g_ptr_array_add (out_array
, item
);
1306 int middle
= start
+ count
/ 2;
1307 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1309 item
->key
= sorted_array
[middle
]->key
;
1310 item
->is_equals
= FALSE
;
1311 g_ptr_array_add (out_array
, item
);
1312 imt_emit_ir (sorted_array
, start
, middle
, out_array
);
1313 item
->check_target_idx
= imt_emit_ir (sorted_array
, middle
, end
, out_array
);
1319 imt_sort_slot_entries (MonoImtBuilderEntry
*entries
) {
1320 MONO_REQ_GC_NEUTRAL_MODE
;
1322 int number_of_entries
= entries
->children
+ 1;
1323 MonoImtBuilderEntry
**sorted_array
= (MonoImtBuilderEntry
**)malloc (sizeof (MonoImtBuilderEntry
*) * number_of_entries
);
1324 GPtrArray
*result
= g_ptr_array_new ();
1325 MonoImtBuilderEntry
*current_entry
;
1328 for (current_entry
= entries
, i
= 0; current_entry
!= NULL
; current_entry
= current_entry
->next
, i
++) {
1329 sorted_array
[i
] = current_entry
;
1331 qsort (sorted_array
, number_of_entries
, sizeof (MonoImtBuilderEntry
*), compare_imt_builder_entries
);
1333 /*for (i = 0; i < number_of_entries; i++) {
1334 print_imt_entry (" sorted array:", sorted_array [i], i);
1337 imt_emit_ir (sorted_array
, 0, number_of_entries
, result
);
1339 g_free (sorted_array
);
1344 initialize_imt_slot (MonoVTable
*vtable
, MonoDomain
*domain
, MonoImtBuilderEntry
*imt_builder_entry
, gpointer fail_tramp
)
1346 MONO_REQ_GC_NEUTRAL_MODE
;
1348 if (imt_builder_entry
!= NULL
) {
1349 if (imt_builder_entry
->children
== 0 && !fail_tramp
&& !always_build_imt_trampolines
) {
1350 /* No collision, return the vtable slot contents */
1351 return vtable
->vtable
[imt_builder_entry
->value
.vtable_slot
];
1353 /* Collision, build the trampoline */
1354 GPtrArray
*imt_ir
= imt_sort_slot_entries (imt_builder_entry
);
1357 result
= imt_trampoline_builder (vtable
, domain
,
1358 (MonoIMTCheckItem
**)imt_ir
->pdata
, imt_ir
->len
, fail_tramp
);
1359 for (i
= 0; i
< imt_ir
->len
; ++i
)
1360 g_free (g_ptr_array_index (imt_ir
, i
));
1361 g_ptr_array_free (imt_ir
, TRUE
);
1373 static MonoImtBuilderEntry
*
1374 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
);
1377 * LOCKING: requires the loader and domain locks.
1381 build_imt_slots (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
, int slot_num
)
1383 MONO_REQ_GC_NEUTRAL_MODE
;
1387 guint32 imt_collisions_bitmap
= 0;
1388 MonoImtBuilderEntry
**imt_builder
= (MonoImtBuilderEntry
**)calloc (MONO_IMT_SIZE
, sizeof (MonoImtBuilderEntry
*));
1389 int method_count
= 0;
1390 gboolean record_method_count_for_max_collisions
= FALSE
;
1391 gboolean has_generic_virtual
= FALSE
, has_variant_iface
= FALSE
;
1394 printf ("Building IMT for class %s.%s slot %d\n", klass
->name_space
, klass
->name
, slot_num
);
1396 for (i
= 0; i
< klass
->interface_offsets_count
; ++i
) {
1397 MonoClass
*iface
= klass
->interfaces_packed
[i
];
1398 int interface_offset
= klass
->interface_offsets_packed
[i
];
1399 int method_slot_in_interface
, vt_slot
;
1401 if (mono_class_has_variant_generic_params (iface
))
1402 has_variant_iface
= TRUE
;
1404 mono_class_setup_methods (iface
);
1405 vt_slot
= interface_offset
;
1406 for (method_slot_in_interface
= 0; method_slot_in_interface
< iface
->method
.count
; method_slot_in_interface
++) {
1409 if (slot_num
>= 0 && iface
->is_inflated
) {
1411 * The imt slot of the method is the same as for its declaring method,
1412 * see the comment in mono_method_get_imt_slot (), so we can
1413 * avoid inflating methods which will be discarded by
1414 * add_imt_builder_entry anyway.
1416 method
= mono_class_get_method_by_index (iface
->generic_class
->container_class
, method_slot_in_interface
);
1417 if (mono_method_get_imt_slot (method
) != slot_num
) {
1422 method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1423 if (method
->is_generic
) {
1424 has_generic_virtual
= TRUE
;
1429 if (!(method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1430 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, vt_slot
, slot_num
);
1435 if (extra_interfaces
) {
1436 int interface_offset
= klass
->vtable_size
;
1438 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
1439 MonoClass
* iface
= (MonoClass
*)list_item
->data
;
1440 int method_slot_in_interface
;
1441 for (method_slot_in_interface
= 0; method_slot_in_interface
< iface
->method
.count
; method_slot_in_interface
++) {
1442 MonoMethod
*method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1444 if (method
->is_generic
)
1445 has_generic_virtual
= TRUE
;
1446 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, interface_offset
+ method_slot_in_interface
, slot_num
);
1448 interface_offset
+= iface
->method
.count
;
1451 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
) {
1452 /* overwrite the imt slot only if we're building all the entries or if
1453 * we're building this specific one
1455 if (slot_num
< 0 || i
== slot_num
) {
1456 MonoImtBuilderEntry
*entries
= get_generic_virtual_entries (domain
, &imt
[i
]);
1459 if (imt_builder
[i
]) {
1460 MonoImtBuilderEntry
*entry
;
1462 /* Link entries with imt_builder [i] */
1463 for (entry
= entries
; entry
->next
; entry
= entry
->next
) {
1465 MonoMethod
*method
= (MonoMethod
*)entry
->key
;
1466 char *method_name
= mono_method_full_name (method
, TRUE
);
1467 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method
, method_name
, i
);
1468 g_free (method_name
);
1471 entry
->next
= imt_builder
[i
];
1472 entries
->children
+= imt_builder
[i
]->children
+ 1;
1474 imt_builder
[i
] = entries
;
1477 if (has_generic_virtual
|| has_variant_iface
) {
1479 * There might be collisions later when the the trampoline is expanded.
1481 imt_collisions_bitmap
|= (1 << i
);
1484 * The IMT trampoline might be called with an instance of one of the
1485 * generic virtual methods, so has to fallback to the IMT trampoline.
1487 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], callbacks
.get_imt_trampoline (vt
, i
));
1489 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], NULL
);
1492 printf ("initialize_imt_slot[%d]: %p methods %d\n", i
, imt
[i
], imt_builder
[i
]->children
+ 1);
1496 if (imt_builder
[i
] != NULL
) {
1497 int methods_in_slot
= imt_builder
[i
]->children
+ 1;
1498 if (methods_in_slot
> mono_stats
.imt_max_collisions_in_slot
) {
1499 mono_stats
.imt_max_collisions_in_slot
= methods_in_slot
;
1500 record_method_count_for_max_collisions
= TRUE
;
1502 method_count
+= methods_in_slot
;
1506 mono_stats
.imt_number_of_methods
+= method_count
;
1507 if (record_method_count_for_max_collisions
) {
1508 mono_stats
.imt_method_count_when_max_collisions
= method_count
;
1511 for (i
= 0; i
< MONO_IMT_SIZE
; i
++) {
1512 MonoImtBuilderEntry
* entry
= imt_builder
[i
];
1513 while (entry
!= NULL
) {
1514 MonoImtBuilderEntry
* next
= entry
->next
;
1519 g_free (imt_builder
);
1520 /* we OR the bitmap since we may build just a single imt slot at a time */
1521 vt
->imt_collisions_bitmap
|= imt_collisions_bitmap
;
1525 build_imt (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
) {
1526 MONO_REQ_GC_NEUTRAL_MODE
;
1528 build_imt_slots (klass
, vt
, domain
, imt
, extra_interfaces
, -1);
1532 * mono_vtable_build_imt_slot:
1533 * @vtable: virtual object table struct
1534 * @imt_slot: slot in the IMT table
1536 * Fill the given @imt_slot in the IMT table of @vtable with
1537 * a trampoline or a trampoline for the case of collisions.
1538 * This is part of the internal mono API.
1540 * LOCKING: Take the domain lock.
1543 mono_vtable_build_imt_slot (MonoVTable
* vtable
, int imt_slot
)
1545 MONO_REQ_GC_NEUTRAL_MODE
;
1547 gpointer
*imt
= (gpointer
*)vtable
;
1548 imt
-= MONO_IMT_SIZE
;
1549 g_assert (imt_slot
>= 0 && imt_slot
< MONO_IMT_SIZE
);
1551 /* no support for extra interfaces: the proxy objects will need
1552 * to build the complete IMT
1553 * Update and heck needs to ahppen inside the proper domain lock, as all
1554 * the changes made to a MonoVTable.
1556 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1557 mono_domain_lock (vtable
->domain
);
1558 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1559 if (!callbacks
.imt_entry_inited (vtable
, imt_slot
))
1560 build_imt_slots (vtable
->klass
, vtable
, vtable
->domain
, imt
, NULL
, imt_slot
);
1561 mono_domain_unlock (vtable
->domain
);
1562 mono_loader_unlock ();
1565 #define THUNK_THRESHOLD 10
1568 * mono_method_alloc_generic_virtual_trampoline:
1570 * @size: size in bytes
1572 * Allocs size bytes to be used for the code of a generic virtual
1573 * trampoline. It's either allocated from the domain's code manager or
1574 * reused from a previously invalidated piece.
1576 * LOCKING: The domain lock must be held.
1579 mono_method_alloc_generic_virtual_trampoline (MonoDomain
*domain
, int size
)
1581 MONO_REQ_GC_NEUTRAL_MODE
;
1583 static gboolean inited
= FALSE
;
1584 static int generic_virtual_trampolines_size
= 0;
1587 mono_counters_register ("Generic virtual trampoline bytes",
1588 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &generic_virtual_trampolines_size
);
1591 generic_virtual_trampolines_size
+= size
;
1593 return mono_domain_code_reserve (domain
, size
);
1596 typedef struct _GenericVirtualCase
{
1600 struct _GenericVirtualCase
*next
;
1601 } GenericVirtualCase
;
1604 * get_generic_virtual_entries:
1606 * Return IMT entries for the generic virtual method instances and
1607 * variant interface methods for vtable slot
1610 static MonoImtBuilderEntry
*
1611 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
)
1613 MONO_REQ_GC_NEUTRAL_MODE
;
1615 GenericVirtualCase
*list
;
1616 MonoImtBuilderEntry
*entries
;
1618 mono_domain_lock (domain
);
1619 if (!domain
->generic_virtual_cases
)
1620 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1622 list
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1625 for (; list
; list
= list
->next
) {
1626 MonoImtBuilderEntry
*entry
;
1628 if (list
->count
< THUNK_THRESHOLD
)
1631 entry
= g_new0 (MonoImtBuilderEntry
, 1);
1632 entry
->key
= list
->method
;
1633 entry
->value
.target_code
= mono_get_addr_from_ftnptr (list
->code
);
1634 entry
->has_target_code
= 1;
1636 entry
->children
= entries
->children
+ 1;
1637 entry
->next
= entries
;
1641 mono_domain_unlock (domain
);
1643 /* FIXME: Leaking memory ? */
1648 * mono_method_add_generic_virtual_invocation:
1650 * @vtable_slot: pointer to the vtable slot
1651 * @method: the inflated generic virtual method
1652 * @code: the method's code
1654 * Registers a call via unmanaged code to a generic virtual method
1655 * instantiation or variant interface method. If the number of calls reaches a threshold
1656 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1657 * virtual method trampoline.
1660 mono_method_add_generic_virtual_invocation (MonoDomain
*domain
, MonoVTable
*vtable
,
1661 gpointer
*vtable_slot
,
1662 MonoMethod
*method
, gpointer code
)
1664 MONO_REQ_GC_NEUTRAL_MODE
;
1666 static gboolean inited
= FALSE
;
1667 static int num_added
= 0;
1668 static int num_freed
= 0;
1670 GenericVirtualCase
*gvc
, *list
;
1671 MonoImtBuilderEntry
*entries
;
1675 mono_domain_lock (domain
);
1676 if (!domain
->generic_virtual_cases
)
1677 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1680 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_added
);
1681 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_freed
);
1685 /* Check whether the case was already added */
1686 list
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1689 if (gvc
->method
== method
)
1694 /* If not found, make a new one */
1696 gvc
= (GenericVirtualCase
*)mono_domain_alloc (domain
, sizeof (GenericVirtualCase
));
1697 gvc
->method
= method
;
1700 gvc
->next
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1702 g_hash_table_insert (domain
->generic_virtual_cases
, vtable_slot
, gvc
);
1707 if (++gvc
->count
== THUNK_THRESHOLD
) {
1708 gpointer
*old_thunk
= (void **)*vtable_slot
;
1709 gpointer vtable_trampoline
= NULL
;
1710 gpointer imt_trampoline
= NULL
;
1712 if ((gpointer
)vtable_slot
< (gpointer
)vtable
) {
1713 int displacement
= (gpointer
*)vtable_slot
- (gpointer
*)vtable
;
1714 int imt_slot
= MONO_IMT_SIZE
+ displacement
;
1716 /* Force the rebuild of the trampoline at the next call */
1717 imt_trampoline
= callbacks
.get_imt_trampoline (vtable
, imt_slot
);
1718 *vtable_slot
= imt_trampoline
;
1720 vtable_trampoline
= callbacks
.get_vtable_trampoline
? callbacks
.get_vtable_trampoline (vtable
, (gpointer
*)vtable_slot
- (gpointer
*)vtable
->vtable
) : NULL
;
1722 entries
= get_generic_virtual_entries (domain
, vtable_slot
);
1724 sorted
= imt_sort_slot_entries (entries
);
1726 *vtable_slot
= imt_trampoline_builder (NULL
, domain
, (MonoIMTCheckItem
**)sorted
->pdata
, sorted
->len
,
1730 MonoImtBuilderEntry
*next
= entries
->next
;
1735 for (i
= 0; i
< sorted
->len
; ++i
)
1736 g_free (g_ptr_array_index (sorted
, i
));
1737 g_ptr_array_free (sorted
, TRUE
);
1739 if (old_thunk
!= vtable_trampoline
&& old_thunk
!= imt_trampoline
)
1744 mono_domain_unlock (domain
);
1747 static MonoVTable
*mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
);
1750 * mono_class_vtable:
1751 * @domain: the application domain
1752 * @class: the class to initialize
1754 * VTables are domain specific because we create domain specific code, and
1755 * they contain the domain specific static class data.
1756 * On failure, NULL is returned, and class->exception_type is set.
1759 mono_class_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1762 MonoVTable
* vtable
= mono_class_vtable_full (domain
, klass
, &error
);
1763 mono_error_cleanup (&error
);
1768 * mono_class_vtable_full:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1771 * @error set on failure.
1773 * VTables are domain specific because we create domain specific code, and
1774 * they contain the domain specific static class data.
1777 mono_class_vtable_full (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
1779 MONO_REQ_GC_UNSAFE_MODE
;
1781 MonoClassRuntimeInfo
*runtime_info
;
1783 mono_error_init (error
);
1787 if (mono_class_has_failure (klass
)) {
1788 mono_error_set_for_class_failure (error
, klass
);
1792 /* this check can be inlined in jitted code, too */
1793 runtime_info
= klass
->runtime_info
;
1794 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1795 return runtime_info
->domain_vtables
[domain
->domain_id
];
1796 return mono_class_create_runtime_vtable (domain
, klass
, error
);
1800 * mono_class_try_get_vtable:
1801 * @domain: the application domain
1802 * @class: the class to initialize
1804 * This function tries to get the associated vtable from @class if
1805 * it was already created.
1808 mono_class_try_get_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1810 MONO_REQ_GC_NEUTRAL_MODE
;
1812 MonoClassRuntimeInfo
*runtime_info
;
1816 runtime_info
= klass
->runtime_info
;
1817 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1818 return runtime_info
->domain_vtables
[domain
->domain_id
];
1823 alloc_vtable (MonoDomain
*domain
, size_t vtable_size
, size_t imt_table_bytes
)
1825 MONO_REQ_GC_NEUTRAL_MODE
;
1827 size_t alloc_offset
;
1830 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1831 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1832 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1834 if (sizeof (gpointer
) == 4 && (imt_table_bytes
& 7)) {
1835 g_assert ((imt_table_bytes
& 7) == 4);
1842 return (gpointer
*) ((char*)mono_domain_alloc0 (domain
, vtable_size
) + alloc_offset
);
1846 mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
1848 MONO_REQ_GC_UNSAFE_MODE
;
1851 MonoClassRuntimeInfo
*runtime_info
, *old_info
;
1852 MonoClassField
*field
;
1854 int i
, vtable_slots
;
1855 size_t imt_table_bytes
;
1857 guint32 vtable_size
, class_size
;
1859 gpointer
*interface_offsets
;
1861 mono_error_init (error
);
1863 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1864 mono_domain_lock (domain
);
1865 runtime_info
= klass
->runtime_info
;
1866 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
]) {
1867 mono_domain_unlock (domain
);
1868 mono_loader_unlock ();
1869 return runtime_info
->domain_vtables
[domain
->domain_id
];
1871 if (!klass
->inited
|| mono_class_has_failure (klass
)) {
1872 if (!mono_class_init (klass
) || mono_class_has_failure (klass
)) {
1873 mono_domain_unlock (domain
);
1874 mono_loader_unlock ();
1875 mono_error_set_for_class_failure (error
, klass
);
1880 /* Array types require that their element type be valid*/
1881 if (klass
->byval_arg
.type
== MONO_TYPE_ARRAY
|| klass
->byval_arg
.type
== MONO_TYPE_SZARRAY
) {
1882 MonoClass
*element_class
= klass
->element_class
;
1883 if (!element_class
->inited
)
1884 mono_class_init (element_class
);
1886 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1887 if (!mono_class_has_failure (element_class
) && !element_class
->vtable_size
)
1888 mono_class_setup_vtable (element_class
);
1890 if (mono_class_has_failure (element_class
)) {
1891 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1892 if (!mono_class_has_failure (klass
))
1893 mono_class_set_failure (klass
, MONO_EXCEPTION_TYPE_LOAD
, NULL
);
1894 mono_domain_unlock (domain
);
1895 mono_loader_unlock ();
1896 mono_error_set_for_class_failure (error
, klass
);
1902 * For some classes, mono_class_init () already computed klass->vtable_size, and
1903 * that is all that is needed because of the vtable trampolines.
1905 if (!klass
->vtable_size
)
1906 mono_class_setup_vtable (klass
);
1908 if (klass
->generic_class
&& !klass
->vtable
)
1909 mono_class_check_vtable_constraints (klass
, NULL
);
1911 /* Initialize klass->has_finalize */
1912 mono_class_has_finalizer (klass
);
1914 if (mono_class_has_failure (klass
)) {
1915 mono_domain_unlock (domain
);
1916 mono_loader_unlock ();
1917 mono_error_set_for_class_failure (error
, klass
);
1921 vtable_slots
= klass
->vtable_size
;
1922 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1923 class_size
= mono_class_data_size (klass
);
1927 if (klass
->interface_offsets_count
) {
1928 imt_table_bytes
= sizeof (gpointer
) * (MONO_IMT_SIZE
);
1929 mono_stats
.imt_number_of_tables
++;
1930 mono_stats
.imt_tables_size
+= imt_table_bytes
;
1932 imt_table_bytes
= 0;
1935 vtable_size
= imt_table_bytes
+ MONO_SIZEOF_VTABLE
+ vtable_slots
* sizeof (gpointer
);
1937 mono_stats
.used_class_count
++;
1938 mono_stats
.class_vtable_size
+= vtable_size
;
1940 interface_offsets
= alloc_vtable (domain
, vtable_size
, imt_table_bytes
);
1941 vt
= (MonoVTable
*) ((char*)interface_offsets
+ imt_table_bytes
);
1942 g_assert (!((gsize
)vt
& 7));
1945 vt
->rank
= klass
->rank
;
1946 vt
->domain
= domain
;
1948 mono_class_compute_gc_descriptor (klass
);
1950 * We can't use typed allocation in the non-root domains, since the
1951 * collector needs the GC descriptor stored in the vtable even after
1952 * the mempool containing the vtable is destroyed when the domain is
1953 * unloaded. An alternative might be to allocate vtables in the GC
1954 * heap, but this does not seem to work (it leads to crashes inside
1955 * libgc). If that approach is tried, two gc descriptors need to be
1956 * allocated for each class: one for the root domain, and one for all
1957 * other domains. The second descriptor should contain a bit for the
1958 * vtable field in MonoObject, since we can no longer assume the
1959 * vtable is reachable by other roots after the appdomain is unloaded.
1961 #ifdef HAVE_BOEHM_GC
1962 if (domain
!= mono_get_root_domain () && !mono_dont_free_domains
)
1963 vt
->gc_descr
= MONO_GC_DESCRIPTOR_NULL
;
1966 vt
->gc_descr
= klass
->gc_descr
;
1968 gc_bits
= mono_gc_get_vtable_bits (klass
);
1969 g_assert (!(gc_bits
& ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS
) - 1)));
1971 vt
->gc_bits
= gc_bits
;
1974 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1975 if (klass
->has_static_refs
) {
1976 MonoGCDescriptor statics_gc_descr
;
1978 gsize default_bitmap
[4] = {0};
1981 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, TRUE
);
1982 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1983 statics_gc_descr
= mono_gc_make_descr_from_bitmap (bitmap
, max_set
+ 1);
1984 vt
->vtable
[klass
->vtable_size
] = mono_gc_alloc_fixed (class_size
, statics_gc_descr
, MONO_ROOT_SOURCE_STATIC
, "managed static variables");
1985 mono_domain_add_class_static_data (domain
, klass
, vt
->vtable
[klass
->vtable_size
], NULL
);
1986 if (bitmap
!= default_bitmap
)
1989 vt
->vtable
[klass
->vtable_size
] = mono_domain_alloc0 (domain
, class_size
);
1991 vt
->has_static_fields
= TRUE
;
1992 mono_stats
.class_static_data_size
+= class_size
;
1996 while ((field
= mono_class_get_fields (klass
, &iter
))) {
1997 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
1999 if (mono_field_is_deleted (field
))
2001 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
2002 gint32 special_static
= klass
->no_special_static_fields
? SPECIAL_STATIC_NONE
: field_is_special_static (klass
, field
);
2003 if (special_static
!= SPECIAL_STATIC_NONE
) {
2004 guint32 size
, offset
;
2006 gsize default_bitmap
[4] = {0};
2011 if (mono_type_is_reference (field
->type
)) {
2012 default_bitmap
[0] = 1;
2014 bitmap
= default_bitmap
;
2015 } else if (mono_type_is_struct (field
->type
)) {
2016 fclass
= mono_class_from_mono_type (field
->type
);
2017 bitmap
= compute_class_bitmap (fclass
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(sizeof (MonoObject
) / sizeof (gpointer
)), &max_set
, FALSE
);
2018 numbits
= max_set
+ 1;
2020 default_bitmap
[0] = 0;
2022 bitmap
= default_bitmap
;
2024 size
= mono_type_size (field
->type
, &align
);
2025 offset
= mono_alloc_special_static_data (special_static
, size
, align
, (uintptr_t*)bitmap
, numbits
);
2026 if (!domain
->special_static_fields
)
2027 domain
->special_static_fields
= g_hash_table_new (NULL
, NULL
);
2028 g_hash_table_insert (domain
->special_static_fields
, field
, GUINT_TO_POINTER (offset
));
2029 if (bitmap
!= default_bitmap
)
2032 * This marks the field as special static to speed up the
2033 * checks in mono_field_static_get/set_value ().
2039 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_RVA
)) {
2040 MonoClass
*fklass
= mono_class_from_mono_type (field
->type
);
2041 const char *data
= mono_field_get_data (field
);
2043 g_assert (!(field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_DEFAULT
));
2044 t
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
2045 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2048 if (fklass
->valuetype
) {
2049 memcpy (t
, data
, mono_class_value_size (fklass
, NULL
));
2051 /* it's a pointer type: add check */
2052 g_assert ((fklass
->byval_arg
.type
== MONO_TYPE_PTR
) || (fklass
->byval_arg
.type
== MONO_TYPE_FNPTR
));
2059 vt
->max_interface_id
= klass
->max_interface_id
;
2060 vt
->interface_bitmap
= klass
->interface_bitmap
;
2062 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2063 // class->name, klass->interface_offsets_count);
2065 /* Initialize vtable */
2066 if (callbacks
.get_vtable_trampoline
) {
2067 // This also covers the AOT case
2068 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2069 vt
->vtable
[i
] = callbacks
.get_vtable_trampoline (vt
, i
);
2072 mono_class_setup_vtable (klass
);
2074 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2077 cm
= klass
->vtable
[i
];
2079 vt
->vtable
[i
] = callbacks
.create_jit_trampoline (domain
, cm
, error
);
2080 if (!is_ok (error
)) {
2081 mono_domain_unlock (domain
);
2082 mono_loader_unlock ();
2089 if (imt_table_bytes
) {
2090 /* Now that the vtable is full, we can actually fill up the IMT */
2091 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
)
2092 interface_offsets
[i
] = callbacks
.get_imt_trampoline (vt
, i
);
2096 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2097 * re-acquire them and check if another thread has created the vtable in the meantime.
2099 /* Special case System.MonoType to avoid infinite recursion */
2100 if (klass
!= mono_defaults
.runtimetype_class
) {
2101 vt
->type
= mono_type_get_object_checked (domain
, &klass
->byval_arg
, error
);
2102 if (!is_ok (error
)) {
2103 mono_domain_unlock (domain
);
2104 mono_loader_unlock ();
2108 if (mono_object_get_class ((MonoObject
*)vt
->type
) != mono_defaults
.runtimetype_class
)
2109 /* This is unregistered in
2110 unregister_vtable_reflection_type() in
2112 MONO_GC_REGISTER_ROOT_IF_MOVING(vt
->type
, MONO_ROOT_SOURCE_REFLECTION
, "vtable reflection type");
2115 mono_vtable_set_is_remote (vt
, mono_class_is_contextbound (klass
));
2117 /* class_vtable_array keeps an array of created vtables
2119 g_ptr_array_add (domain
->class_vtable_array
, vt
);
2120 /* klass->runtime_info is protected by the loader lock, both when
2121 * it it enlarged and when it is stored info.
2125 * Store the vtable in klass->runtime_info.
2126 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2128 mono_memory_barrier ();
2130 old_info
= klass
->runtime_info
;
2131 if (old_info
&& old_info
->max_domain
>= domain
->domain_id
) {
2132 /* someone already created a large enough runtime info */
2133 old_info
->domain_vtables
[domain
->domain_id
] = vt
;
2135 int new_size
= domain
->domain_id
;
2137 new_size
= MAX (new_size
, old_info
->max_domain
);
2139 /* make the new size a power of two */
2141 while (new_size
> i
)
2144 /* this is a bounded memory retention issue: may want to
2145 * handle it differently when we'll have a rcu-like system.
2147 runtime_info
= (MonoClassRuntimeInfo
*)mono_image_alloc0 (klass
->image
, MONO_SIZEOF_CLASS_RUNTIME_INFO
+ new_size
* sizeof (gpointer
));
2148 runtime_info
->max_domain
= new_size
- 1;
2149 /* copy the stuff from the older info */
2151 memcpy (runtime_info
->domain_vtables
, old_info
->domain_vtables
, (old_info
->max_domain
+ 1) * sizeof (gpointer
));
2153 runtime_info
->domain_vtables
[domain
->domain_id
] = vt
;
2155 mono_memory_barrier ();
2156 klass
->runtime_info
= runtime_info
;
2159 if (klass
== mono_defaults
.runtimetype_class
) {
2160 vt
->type
= mono_type_get_object_checked (domain
, &klass
->byval_arg
, error
);
2161 if (!is_ok (error
)) {
2162 mono_domain_unlock (domain
);
2163 mono_loader_unlock ();
2167 if (mono_object_get_class ((MonoObject
*)vt
->type
) != mono_defaults
.runtimetype_class
)
2168 /* This is unregistered in
2169 unregister_vtable_reflection_type() in
2171 MONO_GC_REGISTER_ROOT_IF_MOVING(vt
->type
, MONO_ROOT_SOURCE_REFLECTION
, "vtable reflection type");
2174 mono_domain_unlock (domain
);
2175 mono_loader_unlock ();
2177 /* make sure the parent is initialized */
2178 /*FIXME shouldn't this fail the current type?*/
2180 mono_class_vtable_full (domain
, klass
->parent
, error
);
2185 #ifndef DISABLE_REMOTING
2187 * mono_class_proxy_vtable:
2188 * @domain: the application domain
2189 * @remove_class: the remote class
2190 * @error: set on error
2192 * Creates a vtable for transparent proxies. It is basically
2193 * a copy of the real vtable of the class wrapped in @remote_class,
2194 * but all function pointers invoke the remoting functions, and
2195 * vtable->klass points to the transparent proxy class, and not to @class.
2197 * On failure returns NULL and sets @error
2200 mono_class_proxy_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRemotingTarget target_type
, MonoError
*error
)
2202 MONO_REQ_GC_UNSAFE_MODE
;
2204 MonoVTable
*vt
, *pvt
;
2205 int i
, j
, vtsize
, max_interface_id
, extra_interface_vtsize
= 0;
2207 GSList
*extra_interfaces
= NULL
;
2208 MonoClass
*klass
= remote_class
->proxy_class
;
2209 gpointer
*interface_offsets
;
2210 uint8_t *bitmap
= NULL
;
2212 size_t imt_table_bytes
;
2214 #ifdef COMPRESSED_INTERFACE_BITMAP
2218 mono_error_init (error
);
2220 vt
= mono_class_vtable (domain
, klass
);
2221 g_assert (vt
); /*FIXME property handle failure*/
2222 max_interface_id
= vt
->max_interface_id
;
2224 /* Calculate vtable space for extra interfaces */
2225 for (j
= 0; j
< remote_class
->interface_count
; j
++) {
2226 MonoClass
* iclass
= remote_class
->interfaces
[j
];
2230 /*FIXME test for interfaces with variant generic arguments*/
2231 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, iclass
->interface_id
))
2232 continue; /* interface implemented by the class */
2233 if (g_slist_find (extra_interfaces
, iclass
))
2236 extra_interfaces
= g_slist_prepend (extra_interfaces
, iclass
);
2238 method_count
= mono_class_num_methods (iclass
);
2240 ifaces
= mono_class_get_implemented_interfaces (iclass
, error
);
2244 for (i
= 0; i
< ifaces
->len
; ++i
) {
2245 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2246 /*FIXME test for interfaces with variant generic arguments*/
2247 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, ic
->interface_id
))
2248 continue; /* interface implemented by the class */
2249 if (g_slist_find (extra_interfaces
, ic
))
2251 extra_interfaces
= g_slist_prepend (extra_interfaces
, ic
);
2252 method_count
+= mono_class_num_methods (ic
);
2254 g_ptr_array_free (ifaces
, TRUE
);
2258 extra_interface_vtsize
+= method_count
* sizeof (gpointer
);
2259 if (iclass
->max_interface_id
> max_interface_id
) max_interface_id
= iclass
->max_interface_id
;
2262 imt_table_bytes
= sizeof (gpointer
) * MONO_IMT_SIZE
;
2263 mono_stats
.imt_number_of_tables
++;
2264 mono_stats
.imt_tables_size
+= imt_table_bytes
;
2266 vtsize
= imt_table_bytes
+ MONO_SIZEOF_VTABLE
+ klass
->vtable_size
* sizeof (gpointer
);
2268 mono_stats
.class_vtable_size
+= vtsize
+ extra_interface_vtsize
;
2270 interface_offsets
= alloc_vtable (domain
, vtsize
+ extra_interface_vtsize
, imt_table_bytes
);
2271 pvt
= (MonoVTable
*) ((char*)interface_offsets
+ imt_table_bytes
);
2272 g_assert (!((gsize
)pvt
& 7));
2274 memcpy (pvt
, vt
, MONO_SIZEOF_VTABLE
+ klass
->vtable_size
* sizeof (gpointer
));
2276 pvt
->klass
= mono_defaults
.transparent_proxy_class
;
2277 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2278 pvt
->gc_descr
= mono_defaults
.transparent_proxy_class
->gc_descr
;
2280 /* initialize vtable */
2281 mono_class_setup_vtable (klass
);
2282 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2285 if ((cm
= klass
->vtable
[i
])) {
2286 pvt
->vtable
[i
] = arch_create_remoting_trampoline (domain
, cm
, target_type
, error
);
2290 pvt
->vtable
[i
] = NULL
;
2293 if (klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
) {
2294 /* create trampolines for abstract methods */
2295 for (k
= klass
; k
; k
= k
->parent
) {
2297 gpointer iter
= NULL
;
2298 while ((m
= mono_class_get_methods (k
, &iter
)))
2299 if (!pvt
->vtable
[m
->slot
]) {
2300 pvt
->vtable
[m
->slot
] = arch_create_remoting_trampoline (domain
, m
, target_type
, error
);
2307 pvt
->max_interface_id
= max_interface_id
;
2308 bsize
= sizeof (guint8
) * (max_interface_id
/8 + 1 );
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bitmap
= (uint8_t *)g_malloc0 (bsize
);
2312 bitmap
= (uint8_t *)mono_domain_alloc0 (domain
, bsize
);
2315 for (i
= 0; i
< klass
->interface_offsets_count
; ++i
) {
2316 int interface_id
= klass
->interfaces_packed
[i
]->interface_id
;
2317 bitmap
[interface_id
>> 3] |= (1 << (interface_id
& 7));
2320 if (extra_interfaces
) {
2321 int slot
= klass
->vtable_size
;
2327 /* Create trampolines for the methods of the interfaces */
2328 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
2329 interf
= (MonoClass
*)list_item
->data
;
2331 bitmap
[interf
->interface_id
>> 3] |= (1 << (interf
->interface_id
& 7));
2335 while ((cm
= mono_class_get_methods (interf
, &iter
))) {
2336 pvt
->vtable
[slot
+ j
++] = arch_create_remoting_trampoline (domain
, cm
, target_type
, error
);
2341 slot
+= mono_class_num_methods (interf
);
2345 /* Now that the vtable is full, we can actually fill up the IMT */
2346 build_imt (klass
, pvt
, domain
, interface_offsets
, extra_interfaces
);
2347 if (extra_interfaces
) {
2348 g_slist_free (extra_interfaces
);
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2352 bcsize
= mono_compress_bitmap (NULL
, bitmap
, bsize
);
2353 pvt
->interface_bitmap
= mono_domain_alloc0 (domain
, bcsize
);
2354 mono_compress_bitmap (pvt
->interface_bitmap
, bitmap
, bsize
);
2357 pvt
->interface_bitmap
= bitmap
;
2361 if (extra_interfaces
)
2362 g_slist_free (extra_interfaces
);
2363 #ifdef COMPRESSED_INTERFACE_BITMAP
2369 #endif /* DISABLE_REMOTING */
2372 * mono_class_field_is_special_static:
2374 * Returns whether @field is a thread/context static field.
2377 mono_class_field_is_special_static (MonoClassField
*field
)
2379 MONO_REQ_GC_NEUTRAL_MODE
2381 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2383 if (mono_field_is_deleted (field
))
2385 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
2386 if (field_is_special_static (field
->parent
, field
) != SPECIAL_STATIC_NONE
)
2393 * mono_class_field_get_special_static_type:
2394 * @field: The MonoClassField describing the field.
2396 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2397 * SPECIAL_STATIC_NONE otherwise.
2400 mono_class_field_get_special_static_type (MonoClassField
*field
)
2402 MONO_REQ_GC_NEUTRAL_MODE
2404 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2405 return SPECIAL_STATIC_NONE
;
2406 if (mono_field_is_deleted (field
))
2407 return SPECIAL_STATIC_NONE
;
2408 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
2409 return field_is_special_static (field
->parent
, field
);
2410 return SPECIAL_STATIC_NONE
;
2414 * mono_class_has_special_static_fields:
2416 * Returns whenever @klass has any thread/context static fields.
2419 mono_class_has_special_static_fields (MonoClass
*klass
)
2421 MONO_REQ_GC_NEUTRAL_MODE
2423 MonoClassField
*field
;
2427 while ((field
= mono_class_get_fields (klass
, &iter
))) {
2428 g_assert (field
->parent
== klass
);
2429 if (mono_class_field_is_special_static (field
))
2436 #ifndef DISABLE_REMOTING
2438 * create_remote_class_key:
2439 * Creates an array of pointers that can be used as a hash key for a remote class.
2440 * The first element of the array is the number of pointers.
2443 create_remote_class_key (MonoRemoteClass
*remote_class
, MonoClass
*extra_class
)
2445 MONO_REQ_GC_NEUTRAL_MODE
;
2450 if (remote_class
== NULL
) {
2451 if (extra_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2452 key
= (void **)g_malloc (sizeof(gpointer
) * 3);
2453 key
[0] = GINT_TO_POINTER (2);
2454 key
[1] = mono_defaults
.marshalbyrefobject_class
;
2455 key
[2] = extra_class
;
2457 key
= (void **)g_malloc (sizeof(gpointer
) * 2);
2458 key
[0] = GINT_TO_POINTER (1);
2459 key
[1] = extra_class
;
2462 if (extra_class
!= NULL
&& (extra_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
)) {
2463 key
= (void **)g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 3));
2464 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 2);
2465 key
[1] = remote_class
->proxy_class
;
2467 // Keep the list of interfaces sorted
2468 for (i
= 0, j
= 2; i
< remote_class
->interface_count
; i
++, j
++) {
2469 if (extra_class
&& remote_class
->interfaces
[i
] > extra_class
) {
2470 key
[j
++] = extra_class
;
2473 key
[j
] = remote_class
->interfaces
[i
];
2476 key
[j
] = extra_class
;
2478 // Replace the old class. The interface list is the same
2479 key
= (void **)g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 2));
2480 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 1);
2481 key
[1] = extra_class
!= NULL
? extra_class
: remote_class
->proxy_class
;
2482 for (i
= 0; i
< remote_class
->interface_count
; i
++)
2483 key
[2 + i
] = remote_class
->interfaces
[i
];
2491 * copy_remote_class_key:
2493 * Make a copy of KEY in the domain and return the copy.
2496 copy_remote_class_key (MonoDomain
*domain
, gpointer
*key
)
2498 MONO_REQ_GC_NEUTRAL_MODE
2500 int key_size
= (GPOINTER_TO_UINT (key
[0]) + 1) * sizeof (gpointer
);
2501 gpointer
*mp_key
= (gpointer
*)mono_domain_alloc (domain
, key_size
);
2503 memcpy (mp_key
, key
, key_size
);
2509 * mono_remote_class:
2510 * @domain: the application domain
2511 * @class_name: name of the remote class
2512 * @error: set on error
2514 * Creates and initializes a MonoRemoteClass object for a remote type.
2516 * On failure returns NULL and sets @error
2519 mono_remote_class (MonoDomain
*domain
, MonoString
*class_name
, MonoClass
*proxy_class
, MonoError
*error
)
2521 MONO_REQ_GC_UNSAFE_MODE
;
2523 MonoRemoteClass
*rc
;
2524 gpointer
* key
, *mp_key
;
2527 mono_error_init (error
);
2529 key
= create_remote_class_key (NULL
, proxy_class
);
2531 mono_domain_lock (domain
);
2532 rc
= (MonoRemoteClass
*)g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2536 mono_domain_unlock (domain
);
2540 name
= mono_string_to_utf8_mp (domain
->mp
, class_name
, error
);
2541 if (!is_ok (error
)) {
2543 mono_domain_unlock (domain
);
2547 mp_key
= copy_remote_class_key (domain
, key
);
2551 if (proxy_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2552 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*));
2553 rc
->interface_count
= 1;
2554 rc
->interfaces
[0] = proxy_class
;
2555 rc
->proxy_class
= mono_defaults
.marshalbyrefobject_class
;
2557 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
);
2558 rc
->interface_count
= 0;
2559 rc
->proxy_class
= proxy_class
;
2562 rc
->default_vtable
= NULL
;
2563 rc
->xdomain_vtable
= NULL
;
2564 rc
->proxy_class_name
= name
;
2565 #ifndef DISABLE_PERFCOUNTERS
2566 mono_perfcounters
->loader_bytes
+= mono_string_length (class_name
) + 1;
2569 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2571 mono_domain_unlock (domain
);
2576 * clone_remote_class:
2577 * Creates a copy of the remote_class, adding the provided class or interface
2579 static MonoRemoteClass
*
2580 clone_remote_class (MonoDomain
*domain
, MonoRemoteClass
* remote_class
, MonoClass
*extra_class
)
2582 MONO_REQ_GC_NEUTRAL_MODE
;
2584 MonoRemoteClass
*rc
;
2585 gpointer
* key
, *mp_key
;
2587 key
= create_remote_class_key (remote_class
, extra_class
);
2588 rc
= (MonoRemoteClass
*)g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2594 mp_key
= copy_remote_class_key (domain
, key
);
2598 if (extra_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2600 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * (remote_class
->interface_count
+ 1));
2601 rc
->proxy_class
= remote_class
->proxy_class
;
2602 rc
->interface_count
= remote_class
->interface_count
+ 1;
2604 // Keep the list of interfaces sorted, since the hash key of
2605 // the remote class depends on this
2606 for (i
= 0, j
= 0; i
< remote_class
->interface_count
; i
++, j
++) {
2607 if (remote_class
->interfaces
[i
] > extra_class
&& i
== j
)
2608 rc
->interfaces
[j
++] = extra_class
;
2609 rc
->interfaces
[j
] = remote_class
->interfaces
[i
];
2612 rc
->interfaces
[j
] = extra_class
;
2614 // Replace the old class. The interface array is the same
2615 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * remote_class
->interface_count
);
2616 rc
->proxy_class
= extra_class
;
2617 rc
->interface_count
= remote_class
->interface_count
;
2618 if (rc
->interface_count
> 0)
2619 memcpy (rc
->interfaces
, remote_class
->interfaces
, rc
->interface_count
* sizeof (MonoClass
*));
2622 rc
->default_vtable
= NULL
;
2623 rc
->xdomain_vtable
= NULL
;
2624 rc
->proxy_class_name
= remote_class
->proxy_class_name
;
2626 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2632 mono_remote_class_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRealProxy
*rp
, MonoError
*error
)
2634 MONO_REQ_GC_UNSAFE_MODE
;
2636 mono_error_init (error
);
2638 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2639 mono_domain_lock (domain
);
2640 if (rp
->target_domain_id
!= -1) {
2641 if (remote_class
->xdomain_vtable
== NULL
)
2642 remote_class
->xdomain_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_APPDOMAIN
, error
);
2643 mono_domain_unlock (domain
);
2644 mono_loader_unlock ();
2645 return_val_if_nok (error
, NULL
);
2646 return remote_class
->xdomain_vtable
;
2648 if (remote_class
->default_vtable
== NULL
) {
2651 type
= ((MonoReflectionType
*)rp
->class_to_proxy
)->type
;
2652 klass
= mono_class_from_mono_type (type
);
2654 if ((mono_class_is_com_object (klass
) || (mono_class_get_com_object_class () && klass
== mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass
)))
2655 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_COMINTEROP
, error
);
2658 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_UNKNOWN
, error
);
2659 /* N.B. both branches of the if modify error */
2660 if (!is_ok (error
)) {
2661 mono_domain_unlock (domain
);
2662 mono_loader_unlock ();
2667 mono_domain_unlock (domain
);
2668 mono_loader_unlock ();
2669 return remote_class
->default_vtable
;
2673 * mono_upgrade_remote_class:
2674 * @domain: the application domain
2675 * @tproxy: the proxy whose remote class has to be upgraded.
2676 * @klass: class to which the remote class can be casted.
2677 * @error: set on error
2679 * Updates the vtable of the remote class by adding the necessary method slots
2680 * and interface offsets so it can be safely casted to klass. klass can be a
2681 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2684 mono_upgrade_remote_class (MonoDomain
*domain
, MonoObject
*proxy_object
, MonoClass
*klass
, MonoError
*error
)
2686 MONO_REQ_GC_UNSAFE_MODE
;
2688 MonoTransparentProxy
*tproxy
;
2689 MonoRemoteClass
*remote_class
;
2690 gboolean redo_vtable
;
2692 mono_error_init (error
);
2693 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2694 mono_domain_lock (domain
);
2696 tproxy
= (MonoTransparentProxy
*) proxy_object
;
2697 remote_class
= tproxy
->remote_class
;
2699 if (klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2702 for (i
= 0; i
< remote_class
->interface_count
&& redo_vtable
; i
++)
2703 if (remote_class
->interfaces
[i
] == klass
)
2704 redo_vtable
= FALSE
;
2707 redo_vtable
= (remote_class
->proxy_class
!= klass
);
2711 tproxy
->remote_class
= clone_remote_class (domain
, remote_class
, klass
);
2712 proxy_object
->vtable
= (MonoVTable
*)mono_remote_class_vtable (domain
, tproxy
->remote_class
, tproxy
->rp
, error
);
2718 mono_domain_unlock (domain
);
2719 mono_loader_unlock ();
2720 return is_ok (error
);
2722 #endif /* DISABLE_REMOTING */
2726 * mono_object_get_virtual_method:
2727 * @obj: object to operate on.
2730 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2731 * the instance of a callvirt of method.
2734 mono_object_get_virtual_method (MonoObject
*obj
, MonoMethod
*method
)
2736 MONO_REQ_GC_UNSAFE_MODE
;
2739 MonoMethod
**vtable
;
2740 gboolean is_proxy
= FALSE
;
2741 MonoMethod
*res
= NULL
;
2743 klass
= mono_object_class (obj
);
2744 #ifndef DISABLE_REMOTING
2745 if (klass
== mono_defaults
.transparent_proxy_class
) {
2746 klass
= ((MonoTransparentProxy
*)obj
)->remote_class
->proxy_class
;
2751 if (!is_proxy
&& ((method
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)))
2754 mono_class_setup_vtable (klass
);
2755 vtable
= klass
->vtable
;
2757 if (method
->slot
== -1) {
2758 /* method->slot might not be set for instances of generic methods */
2759 if (method
->is_inflated
) {
2760 g_assert (((MonoMethodInflated
*)method
)->declaring
->slot
!= -1);
2761 method
->slot
= ((MonoMethodInflated
*)method
)->declaring
->slot
;
2764 g_assert_not_reached ();
2768 /* check method->slot is a valid index: perform isinstance? */
2769 if (method
->slot
!= -1) {
2770 if (method
->klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2772 gboolean variance_used
= FALSE
;
2773 int iface_offset
= mono_class_interface_offset_with_variance (klass
, method
->klass
, &variance_used
);
2774 g_assert (iface_offset
> 0);
2775 res
= vtable
[iface_offset
+ method
->slot
];
2778 res
= vtable
[method
->slot
];
2782 #ifndef DISABLE_REMOTING
2784 /* It may be an interface, abstract class method or generic method */
2785 if (!res
|| mono_method_signature (res
)->generic_param_count
)
2788 /* generic methods demand invoke_with_check */
2789 if (mono_method_signature (res
)->generic_param_count
)
2790 res
= mono_marshal_get_remoting_invoke_with_check (res
);
2793 if (klass
== mono_class_get_com_object_class () || mono_class_is_com_object (klass
))
2794 res
= mono_cominterop_get_invoke (res
);
2797 res
= mono_marshal_get_remoting_invoke (res
);
2802 if (method
->is_inflated
) {
2804 /* Have to inflate the result */
2805 res
= mono_class_inflate_generic_method_checked (res
, &((MonoMethodInflated
*)method
)->context
, &error
);
2806 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2816 do_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2818 MONO_REQ_GC_UNSAFE_MODE
;
2820 MonoObject
*result
= NULL
;
2822 g_assert (callbacks
.runtime_invoke
);
2824 mono_error_init (error
);
2826 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS
)
2827 mono_profiler_method_start_invoke (method
);
2829 result
= callbacks
.runtime_invoke (method
, obj
, params
, exc
, error
);
2831 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS
)
2832 mono_profiler_method_end_invoke (method
);
2834 if (!mono_error_ok (error
))
2841 * mono_runtime_invoke:
2842 * @method: method to invoke
2843 * @obJ: object instance
2844 * @params: arguments to the method
2845 * @exc: exception information.
2847 * Invokes the method represented by @method on the object @obj.
2849 * obj is the 'this' pointer, it should be NULL for static
2850 * methods, a MonoObject* for object instances and a pointer to
2851 * the value type for value types.
2853 * The params array contains the arguments to the method with the
2854 * same convention: MonoObject* pointers for object instances and
2855 * pointers to the value type otherwise.
2857 * From unmanaged code you'll usually use the
2858 * mono_runtime_invoke() variant.
2860 * Note that this function doesn't handle virtual methods for
2861 * you, it will exec the exact method you pass: we still need to
2862 * expose a function to lookup the derived class implementation
2863 * of a virtual method (there are examples of this in the code,
2866 * You can pass NULL as the exc argument if you don't want to
2867 * catch exceptions, otherwise, *exc will be set to the exception
2868 * thrown, if any. if an exception is thrown, you can't use the
2869 * MonoObject* result from the function.
2871 * If the method returns a value type, it is boxed in an object
2875 mono_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
2880 res
= mono_runtime_try_invoke (method
, obj
, params
, exc
, &error
);
2881 if (*exc
== NULL
&& !mono_error_ok(&error
)) {
2882 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
2884 mono_error_cleanup (&error
);
2886 res
= mono_runtime_invoke_checked (method
, obj
, params
, &error
);
2887 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
2893 * mono_runtime_try_invoke:
2894 * @method: method to invoke
2895 * @obJ: object instance
2896 * @params: arguments to the method
2897 * @exc: exception information.
2898 * @error: set on error
2900 * Invokes the method represented by @method on the object @obj.
2902 * obj is the 'this' pointer, it should be NULL for static
2903 * methods, a MonoObject* for object instances and a pointer to
2904 * the value type for value types.
2906 * The params array contains the arguments to the method with the
2907 * same convention: MonoObject* pointers for object instances and
2908 * pointers to the value type otherwise.
2910 * From unmanaged code you'll usually use the
2911 * mono_runtime_invoke() variant.
2913 * Note that this function doesn't handle virtual methods for
2914 * you, it will exec the exact method you pass: we still need to
2915 * expose a function to lookup the derived class implementation
2916 * of a virtual method (there are examples of this in the code,
2919 * For this function, you must not pass NULL as the exc argument if
2920 * you don't want to catch exceptions, use
2921 * mono_runtime_invoke_checked(). If an exception is thrown, you
2922 * can't use the MonoObject* result from the function.
2924 * If this method cannot be invoked, @error will be set and @exc and
2925 * the return value must not be used.
2927 * If the method returns a value type, it is boxed in an object
2931 mono_runtime_try_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
* error
)
2933 MONO_REQ_GC_UNSAFE_MODE
;
2935 g_assert (exc
!= NULL
);
2937 if (mono_runtime_get_no_exec ())
2938 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method
, TRUE
));
2940 return do_runtime_invoke (method
, obj
, params
, exc
, error
);
2944 * mono_runtime_invoke_checked:
2945 * @method: method to invoke
2946 * @obJ: object instance
2947 * @params: arguments to the method
2948 * @error: set on error
2950 * Invokes the method represented by @method on the object @obj.
2952 * obj is the 'this' pointer, it should be NULL for static
2953 * methods, a MonoObject* for object instances and a pointer to
2954 * the value type for value types.
2956 * The params array contains the arguments to the method with the
2957 * same convention: MonoObject* pointers for object instances and
2958 * pointers to the value type otherwise.
2960 * From unmanaged code you'll usually use the
2961 * mono_runtime_invoke() variant.
2963 * Note that this function doesn't handle virtual methods for
2964 * you, it will exec the exact method you pass: we still need to
2965 * expose a function to lookup the derived class implementation
2966 * of a virtual method (there are examples of this in the code,
2969 * If an exception is thrown, you can't use the MonoObject* result
2970 * from the function.
2972 * If this method cannot be invoked, @error will be set. If the
2973 * method throws an exception (and we're in coop mode) the exception
2974 * will be set in @error.
2976 * If the method returns a value type, it is boxed in an object
2980 mono_runtime_invoke_checked (MonoMethod
*method
, void *obj
, void **params
, MonoError
* error
)
2982 MONO_REQ_GC_UNSAFE_MODE
;
2984 if (mono_runtime_get_no_exec ())
2985 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method
, TRUE
));
2987 return do_runtime_invoke (method
, obj
, params
, NULL
, error
);
2991 * mono_method_get_unmanaged_thunk:
2992 * @method: method to generate a thunk for.
2994 * Returns an unmanaged->managed thunk that can be used to call
2995 * a managed method directly from C.
2997 * The thunk's C signature closely matches the managed signature:
2999 * C#: public bool Equals (object obj);
3000 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3001 * MonoObject*, MonoException**);
3003 * The 1st ("this") parameter must not be used with static methods:
3005 * C#: public static bool ReferenceEquals (object a, object b);
3006 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3009 * The last argument must be a non-null pointer of a MonoException* pointer.
3010 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3011 * exception has been thrown in managed code. Otherwise it will point
3012 * to the MonoException* caught by the thunk. In this case, the result of
3013 * the thunk is undefined:
3015 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3016 * MonoException *ex = NULL;
3017 * Equals func = mono_method_get_unmanaged_thunk (method);
3018 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3020 * // handle exception
3023 * The calling convention of the thunk matches the platform's default
3024 * convention. This means that under Windows, C declarations must
3025 * contain the __stdcall attribute:
3027 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3028 * MonoObject*, MonoException**);
3032 * Value type arguments and return values are treated as they were objects:
3034 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3035 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3037 * Arguments must be properly boxed upon trunk's invocation, while return
3038 * values must be unboxed.
3041 mono_method_get_unmanaged_thunk (MonoMethod
*method
)
3043 MONO_REQ_GC_NEUTRAL_MODE
;
3044 MONO_REQ_API_ENTRYPOINT
;
3049 g_assert (!mono_threads_is_coop_enabled ());
3051 MONO_ENTER_GC_UNSAFE
;
3052 method
= mono_marshal_get_thunk_invoke_wrapper (method
);
3053 res
= mono_compile_method_checked (method
, &error
);
3054 mono_error_cleanup (&error
);
3055 MONO_EXIT_GC_UNSAFE
;
3061 mono_copy_value (MonoType
*type
, void *dest
, void *value
, int deref_pointer
)
3063 MONO_REQ_GC_UNSAFE_MODE
;
3067 /* object fields cannot be byref, so we don't need a
3069 gpointer
*p
= (gpointer
*)dest
;
3076 case MONO_TYPE_BOOLEAN
:
3078 case MONO_TYPE_U1
: {
3079 guint8
*p
= (guint8
*)dest
;
3080 *p
= value
? *(guint8
*)value
: 0;
3085 case MONO_TYPE_CHAR
: {
3086 guint16
*p
= (guint16
*)dest
;
3087 *p
= value
? *(guint16
*)value
: 0;
3090 #if SIZEOF_VOID_P == 4
3095 case MONO_TYPE_U4
: {
3096 gint32
*p
= (gint32
*)dest
;
3097 *p
= value
? *(gint32
*)value
: 0;
3100 #if SIZEOF_VOID_P == 8
3105 case MONO_TYPE_U8
: {
3106 gint64
*p
= (gint64
*)dest
;
3107 *p
= value
? *(gint64
*)value
: 0;
3110 case MONO_TYPE_R4
: {
3111 float *p
= (float*)dest
;
3112 *p
= value
? *(float*)value
: 0;
3115 case MONO_TYPE_R8
: {
3116 double *p
= (double*)dest
;
3117 *p
= value
? *(double*)value
: 0;
3120 case MONO_TYPE_STRING
:
3121 case MONO_TYPE_SZARRAY
:
3122 case MONO_TYPE_CLASS
:
3123 case MONO_TYPE_OBJECT
:
3124 case MONO_TYPE_ARRAY
:
3125 mono_gc_wbarrier_generic_store (dest
, deref_pointer
? *(MonoObject
**)value
: (MonoObject
*)value
);
3127 case MONO_TYPE_FNPTR
:
3128 case MONO_TYPE_PTR
: {
3129 gpointer
*p
= (gpointer
*)dest
;
3130 *p
= deref_pointer
? *(gpointer
*)value
: value
;
3133 case MONO_TYPE_VALUETYPE
:
3134 /* note that 't' and 'type->type' can be different */
3135 if (type
->type
== MONO_TYPE_VALUETYPE
&& type
->data
.klass
->enumtype
) {
3136 t
= mono_class_enum_basetype (type
->data
.klass
)->type
;
3139 MonoClass
*klass
= mono_class_from_mono_type (type
);
3140 int size
= mono_class_value_size (klass
, NULL
);
3142 mono_gc_bzero_atomic (dest
, size
);
3144 mono_gc_wbarrier_value_copy (dest
, value
, 1, klass
);
3147 case MONO_TYPE_GENERICINST
:
3148 t
= type
->data
.generic_class
->container_class
->byval_arg
.type
;
3151 g_error ("got type %x", type
->type
);
3156 * mono_field_set_value:
3157 * @obj: Instance object
3158 * @field: MonoClassField describing the field to set
3159 * @value: The value to be set
3161 * Sets the value of the field described by @field in the object instance @obj
3162 * to the value passed in @value. This method should only be used for instance
3163 * fields. For static fields, use mono_field_static_set_value.
3165 * The value must be on the native format of the field type.
3168 mono_field_set_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3170 MONO_REQ_GC_UNSAFE_MODE
;
3174 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
));
3176 dest
= (char*)obj
+ field
->offset
;
3177 mono_copy_value (field
->type
, dest
, value
, FALSE
);
3181 * mono_field_static_set_value:
3182 * @field: MonoClassField describing the field to set
3183 * @value: The value to be set
3185 * Sets the value of the static field described by @field
3186 * to the value passed in @value.
3188 * The value must be on the native format of the field type.
3191 mono_field_static_set_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3193 MONO_REQ_GC_UNSAFE_MODE
;
3197 g_return_if_fail (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3198 /* you cant set a constant! */
3199 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
));
3201 if (field
->offset
== -1) {
3202 /* Special static */
3205 mono_domain_lock (vt
->domain
);
3206 addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3207 mono_domain_unlock (vt
->domain
);
3208 dest
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
3210 dest
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3212 mono_copy_value (field
->type
, dest
, value
, FALSE
);
3216 * mono_vtable_get_static_field_data:
3218 * Internal use function: return a pointer to the memory holding the static fields
3219 * for a class or NULL if there are no static fields.
3220 * This is exported only for use by the debugger.
3223 mono_vtable_get_static_field_data (MonoVTable
*vt
)
3225 MONO_REQ_GC_NEUTRAL_MODE
3227 if (!vt
->has_static_fields
)
3229 return vt
->vtable
[vt
->klass
->vtable_size
];
3233 mono_field_get_addr (MonoObject
*obj
, MonoVTable
*vt
, MonoClassField
*field
)
3235 MONO_REQ_GC_UNSAFE_MODE
;
3239 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3240 if (field
->offset
== -1) {
3241 /* Special static */
3244 mono_domain_lock (vt
->domain
);
3245 addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3246 mono_domain_unlock (vt
->domain
);
3247 src
= (guint8
*)mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
3249 src
= (guint8
*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3252 src
= (guint8
*)obj
+ field
->offset
;
3259 * mono_field_get_value:
3260 * @obj: Object instance
3261 * @field: MonoClassField describing the field to fetch information from
3262 * @value: pointer to the location where the value will be stored
3264 * Use this routine to get the value of the field @field in the object
3267 * The pointer provided by value must be of the field type, for reference
3268 * types this is a MonoObject*, for value types its the actual pointer to
3273 * mono_field_get_value (obj, int_field, &i);
3276 mono_field_get_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3278 MONO_REQ_GC_UNSAFE_MODE
;
3284 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
));
3286 src
= (char*)obj
+ field
->offset
;
3287 mono_copy_value (field
->type
, value
, src
, TRUE
);
3291 * mono_field_get_value_object:
3292 * @domain: domain where the object will be created (if boxing)
3293 * @field: MonoClassField describing the field to fetch information from
3294 * @obj: The object instance for the field.
3296 * Returns: a new MonoObject with the value from the given field. If the
3297 * field represents a value type, the value is boxed.
3301 mono_field_get_value_object (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
)
3304 MonoObject
* result
= mono_field_get_value_object_checked (domain
, field
, obj
, &error
);
3305 mono_error_assert_ok (&error
);
3310 * mono_field_get_value_object_checked:
3311 * @domain: domain where the object will be created (if boxing)
3312 * @field: MonoClassField describing the field to fetch information from
3313 * @obj: The object instance for the field.
3314 * @error: Set on error.
3316 * Returns: a new MonoObject with the value from the given field. If the
3317 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3321 mono_field_get_value_object_checked (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
, MonoError
*error
)
3323 MONO_REQ_GC_UNSAFE_MODE
;
3325 mono_error_init (error
);
3329 MonoVTable
*vtable
= NULL
;
3331 gboolean is_static
= FALSE
;
3332 gboolean is_ref
= FALSE
;
3333 gboolean is_literal
= FALSE
;
3334 gboolean is_ptr
= FALSE
;
3335 MonoType
*type
= mono_field_get_type_checked (field
, error
);
3337 return_val_if_nok (error
, NULL
);
3339 switch (type
->type
) {
3340 case MONO_TYPE_STRING
:
3341 case MONO_TYPE_OBJECT
:
3342 case MONO_TYPE_CLASS
:
3343 case MONO_TYPE_ARRAY
:
3344 case MONO_TYPE_SZARRAY
:
3349 case MONO_TYPE_BOOLEAN
:
3352 case MONO_TYPE_CHAR
:
3361 case MONO_TYPE_VALUETYPE
:
3362 is_ref
= type
->byref
;
3364 case MONO_TYPE_GENERICINST
:
3365 is_ref
= !mono_type_generic_inst_is_valuetype (type
);
3371 g_error ("type 0x%x not handled in "
3372 "mono_field_get_value_object", type
->type
);
3376 if (type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
3379 if (type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3383 vtable
= mono_class_vtable_full (domain
, field
->parent
, error
);
3384 return_val_if_nok (error
, NULL
);
3386 if (!vtable
->initialized
) {
3387 mono_runtime_class_init_full (vtable
, error
);
3388 return_val_if_nok (error
, NULL
);
3397 get_default_field_value (domain
, field
, &o
, error
);
3398 return_val_if_nok (error
, NULL
);
3399 } else if (is_static
) {
3400 mono_field_static_get_value_checked (vtable
, field
, &o
, error
);
3401 return_val_if_nok (error
, NULL
);
3403 mono_field_get_value (obj
, field
, &o
);
3409 static MonoMethod
*m
;
3415 MonoClass
*ptr_klass
= mono_class_get_pointer_class ();
3416 m
= mono_class_get_method_from_name_flags (ptr_klass
, "Box", 2, METHOD_ATTRIBUTE_STATIC
);
3422 get_default_field_value (domain
, field
, v
, error
);
3423 return_val_if_nok (error
, NULL
);
3424 } else if (is_static
) {
3425 mono_field_static_get_value_checked (vtable
, field
, v
, error
);
3426 return_val_if_nok (error
, NULL
);
3428 mono_field_get_value (obj
, field
, v
);
3431 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3432 args
[0] = ptr
? *ptr
: NULL
;
3433 args
[1] = mono_type_get_object_checked (mono_domain_get (), type
, error
);
3434 return_val_if_nok (error
, NULL
);
3436 o
= mono_runtime_invoke_checked (m
, NULL
, args
, error
);
3437 return_val_if_nok (error
, NULL
);
3442 /* boxed value type */
3443 klass
= mono_class_from_mono_type (type
);
3445 if (mono_class_is_nullable (klass
))
3446 return mono_nullable_box (mono_field_get_addr (obj
, vtable
, field
), klass
, error
);
3448 o
= mono_object_new_checked (domain
, klass
, error
);
3449 return_val_if_nok (error
, NULL
);
3450 v
= ((gchar
*) o
) + sizeof (MonoObject
);
3453 get_default_field_value (domain
, field
, v
, error
);
3454 return_val_if_nok (error
, NULL
);
3455 } else if (is_static
) {
3456 mono_field_static_get_value_checked (vtable
, field
, v
, error
);
3457 return_val_if_nok (error
, NULL
);
3459 mono_field_get_value (obj
, field
, v
);
3466 mono_get_constant_value_from_blob (MonoDomain
* domain
, MonoTypeEnum type
, const char *blob
, void *value
, MonoError
*error
)
3468 MONO_REQ_GC_UNSAFE_MODE
;
3470 mono_error_init (error
);
3472 const char *p
= blob
;
3473 mono_metadata_decode_blob_size (p
, &p
);
3476 case MONO_TYPE_BOOLEAN
:
3479 *(guint8
*) value
= *p
;
3481 case MONO_TYPE_CHAR
:
3484 *(guint16
*) value
= read16 (p
);
3488 *(guint32
*) value
= read32 (p
);
3492 *(guint64
*) value
= read64 (p
);
3495 readr4 (p
, (float*) value
);
3498 readr8 (p
, (double*) value
);
3500 case MONO_TYPE_STRING
:
3501 *(gpointer
*) value
= mono_ldstr_metadata_sig (domain
, blob
, error
);
3503 case MONO_TYPE_CLASS
:
3504 *(gpointer
*) value
= NULL
;
3508 g_warning ("type 0x%02x should not be in constant table", type
);
3514 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
, MonoError
*error
)
3516 MONO_REQ_GC_NEUTRAL_MODE
;
3518 MonoTypeEnum def_type
;
3521 mono_error_init (error
);
3523 data
= mono_class_get_field_default_value (field
, &def_type
);
3524 mono_get_constant_value_from_blob (domain
, def_type
, data
, value
, error
);
3528 mono_field_static_get_value_for_thread (MonoInternalThread
*thread
, MonoVTable
*vt
, MonoClassField
*field
, void *value
, MonoError
*error
)
3530 MONO_REQ_GC_UNSAFE_MODE
;
3534 mono_error_init (error
);
3536 g_return_if_fail (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3538 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
) {
3539 get_default_field_value (vt
->domain
, field
, value
, error
);
3543 if (field
->offset
== -1) {
3544 /* Special static */
3545 gpointer addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3546 src
= mono_get_special_static_data_for_thread (thread
, GPOINTER_TO_UINT (addr
));
3548 src
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3550 mono_copy_value (field
->type
, value
, src
, TRUE
);
3554 * mono_field_static_get_value:
3555 * @vt: vtable to the object
3556 * @field: MonoClassField describing the field to fetch information from
3557 * @value: where the value is returned
3559 * Use this routine to get the value of the static field @field value.
3561 * The pointer provided by value must be of the field type, for reference
3562 * types this is a MonoObject*, for value types its the actual pointer to
3567 * mono_field_static_get_value (vt, int_field, &i);
3570 mono_field_static_get_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3572 MONO_REQ_GC_NEUTRAL_MODE
;
3575 mono_field_static_get_value_checked (vt
, field
, value
, &error
);
3576 mono_error_cleanup (&error
);
3580 * mono_field_static_get_value_checked:
3581 * @vt: vtable to the object
3582 * @field: MonoClassField describing the field to fetch information from
3583 * @value: where the value is returned
3584 * @error: set on error
3586 * Use this routine to get the value of the static field @field value.
3588 * The pointer provided by value must be of the field type, for reference
3589 * types this is a MonoObject*, for value types its the actual pointer to
3594 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3595 * if (!is_ok (error)) { ... }
3597 * On failure sets @error.
3600 mono_field_static_get_value_checked (MonoVTable
*vt
, MonoClassField
*field
, void *value
, MonoError
*error
)
3602 MONO_REQ_GC_NEUTRAL_MODE
;
3604 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt
, field
, value
, error
);
3608 * mono_property_set_value:
3609 * @prop: MonoProperty to set
3610 * @obj: instance object on which to act
3611 * @params: parameters to pass to the propery
3612 * @exc: optional exception
3614 * Invokes the property's set method with the given arguments on the
3615 * object instance obj (or NULL for static properties).
3617 * You can pass NULL as the exc argument if you don't want to
3618 * catch exceptions, otherwise, *exc will be set to the exception
3619 * thrown, if any. if an exception is thrown, you can't use the
3620 * MonoObject* result from the function.
3623 mono_property_set_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3625 MONO_REQ_GC_UNSAFE_MODE
;
3628 do_runtime_invoke (prop
->set
, obj
, params
, exc
, &error
);
3629 if (exc
&& *exc
== NULL
&& !mono_error_ok (&error
)) {
3630 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
3632 mono_error_cleanup (&error
);
3637 * mono_property_set_value_checked:
3638 * @prop: MonoProperty to set
3639 * @obj: instance object on which to act
3640 * @params: parameters to pass to the propery
3641 * @error: set on error
3643 * Invokes the property's set method with the given arguments on the
3644 * object instance obj (or NULL for static properties).
3646 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3647 * If an exception is thrown, it will be caught and returned via @error.
3650 mono_property_set_value_checked (MonoProperty
*prop
, void *obj
, void **params
, MonoError
*error
)
3652 MONO_REQ_GC_UNSAFE_MODE
;
3656 mono_error_init (error
);
3657 do_runtime_invoke (prop
->set
, obj
, params
, &exc
, error
);
3658 if (exc
!= NULL
&& is_ok (error
))
3659 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
3660 return is_ok (error
);
3664 * mono_property_get_value:
3665 * @prop: MonoProperty to fetch
3666 * @obj: instance object on which to act
3667 * @params: parameters to pass to the propery
3668 * @exc: optional exception
3670 * Invokes the property's get method with the given arguments on the
3671 * object instance obj (or NULL for static properties).
3673 * You can pass NULL as the exc argument if you don't want to
3674 * catch exceptions, otherwise, *exc will be set to the exception
3675 * thrown, if any. if an exception is thrown, you can't use the
3676 * MonoObject* result from the function.
3678 * Returns: the value from invoking the get method on the property.
3681 mono_property_get_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3683 MONO_REQ_GC_UNSAFE_MODE
;
3686 MonoObject
*val
= do_runtime_invoke (prop
->get
, obj
, params
, exc
, &error
);
3687 if (exc
&& *exc
== NULL
&& !mono_error_ok (&error
)) {
3688 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
3690 mono_error_cleanup (&error
); /* FIXME don't raise here */
3697 * mono_property_get_value_checked:
3698 * @prop: MonoProperty to fetch
3699 * @obj: instance object on which to act
3700 * @params: parameters to pass to the propery
3701 * @error: set on error
3703 * Invokes the property's get method with the given arguments on the
3704 * object instance obj (or NULL for static properties).
3706 * If an exception is thrown, you can't use the
3707 * MonoObject* result from the function. The exception will be propagated via @error.
3709 * Returns: the value from invoking the get method on the property. On
3710 * failure returns NULL and sets @error.
3713 mono_property_get_value_checked (MonoProperty
*prop
, void *obj
, void **params
, MonoError
*error
)
3715 MONO_REQ_GC_UNSAFE_MODE
;
3718 MonoObject
*val
= do_runtime_invoke (prop
->get
, obj
, params
, &exc
, error
);
3719 if (exc
!= NULL
&& !is_ok (error
))
3720 mono_error_set_exception_instance (error
, (MonoException
*) exc
);
3728 * mono_nullable_init:
3729 * @buf: The nullable structure to initialize.
3730 * @value: the value to initialize from
3731 * @klass: the type for the object
3733 * Initialize the nullable structure pointed to by @buf from @value which
3734 * should be a boxed value type. The size of @buf should be able to hold
3735 * as much data as the @klass->instance_size (which is the number of bytes
3736 * that will be copies).
3738 * Since Nullables have variable structure, we can not define a C
3739 * structure for them.
3742 mono_nullable_init (guint8
*buf
, MonoObject
*value
, MonoClass
*klass
)
3744 MONO_REQ_GC_UNSAFE_MODE
;
3746 MonoClass
*param_class
= klass
->cast_class
;
3748 mono_class_setup_fields_locking (klass
);
3749 g_assert (klass
->fields_inited
);
3751 g_assert (mono_class_from_mono_type (klass
->fields
[0].type
) == param_class
);
3752 g_assert (mono_class_from_mono_type (klass
->fields
[1].type
) == mono_defaults
.boolean_class
);
3754 *(guint8
*)(buf
+ klass
->fields
[1].offset
- sizeof (MonoObject
)) = value
? 1 : 0;
3756 if (param_class
->has_references
)
3757 mono_gc_wbarrier_value_copy (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_object_unbox (value
), 1, param_class
);
3759 mono_gc_memmove_atomic (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_object_unbox (value
), mono_class_value_size (param_class
, NULL
));
3761 mono_gc_bzero_atomic (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_class_value_size (param_class
, NULL
));
3766 * mono_nullable_box:
3767 * @buf: The buffer representing the data to be boxed
3768 * @klass: the type to box it as.
3769 * @error: set on oerr
3771 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3772 * @buf. On failure returns NULL and sets @error
3775 mono_nullable_box (guint8
*buf
, MonoClass
*klass
, MonoError
*error
)
3777 MONO_REQ_GC_UNSAFE_MODE
;
3779 mono_error_init (error
);
3780 MonoClass
*param_class
= klass
->cast_class
;
3782 mono_class_setup_fields_locking (klass
);
3783 g_assert (klass
->fields_inited
);
3785 g_assert (mono_class_from_mono_type (klass
->fields
[0].type
) == param_class
);
3786 g_assert (mono_class_from_mono_type (klass
->fields
[1].type
) == mono_defaults
.boolean_class
);
3788 if (*(guint8
*)(buf
+ klass
->fields
[1].offset
- sizeof (MonoObject
))) {
3789 MonoObject
*o
= mono_object_new_checked (mono_domain_get (), param_class
, error
);
3790 return_val_if_nok (error
, NULL
);
3791 if (param_class
->has_references
)
3792 mono_gc_wbarrier_value_copy (mono_object_unbox (o
), buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), 1, param_class
);
3794 mono_gc_memmove_atomic (mono_object_unbox (o
), buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_class_value_size (param_class
, NULL
));
3802 * mono_get_delegate_invoke:
3803 * @klass: The delegate class
3805 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3808 mono_get_delegate_invoke (MonoClass
*klass
)
3810 MONO_REQ_GC_NEUTRAL_MODE
;
3814 /* This is called at runtime, so avoid the slower search in metadata */
3815 mono_class_setup_methods (klass
);
3816 if (mono_class_has_failure (klass
))
3818 im
= mono_class_get_method_from_name (klass
, "Invoke", -1);
3823 * mono_get_delegate_begin_invoke:
3824 * @klass: The delegate class
3826 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3829 mono_get_delegate_begin_invoke (MonoClass
*klass
)
3831 MONO_REQ_GC_NEUTRAL_MODE
;
3835 /* This is called at runtime, so avoid the slower search in metadata */
3836 mono_class_setup_methods (klass
);
3837 if (mono_class_has_failure (klass
))
3839 im
= mono_class_get_method_from_name (klass
, "BeginInvoke", -1);
3844 * mono_get_delegate_end_invoke:
3845 * @klass: The delegate class
3847 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3850 mono_get_delegate_end_invoke (MonoClass
*klass
)
3852 MONO_REQ_GC_NEUTRAL_MODE
;
3856 /* This is called at runtime, so avoid the slower search in metadata */
3857 mono_class_setup_methods (klass
);
3858 if (mono_class_has_failure (klass
))
3860 im
= mono_class_get_method_from_name (klass
, "EndInvoke", -1);
3865 * mono_runtime_delegate_invoke:
3866 * @delegate: pointer to a delegate object.
3867 * @params: parameters for the delegate.
3868 * @exc: Pointer to the exception result.
3870 * Invokes the delegate method @delegate with the parameters provided.
3872 * You can pass NULL as the exc argument if you don't want to
3873 * catch exceptions, otherwise, *exc will be set to the exception
3874 * thrown, if any. if an exception is thrown, you can't use the
3875 * MonoObject* result from the function.
3878 mono_runtime_delegate_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
)
3880 MONO_REQ_GC_UNSAFE_MODE
;
3884 MonoObject
*result
= mono_runtime_delegate_try_invoke (delegate
, params
, exc
, &error
);
3886 mono_error_cleanup (&error
);
3889 if (!is_ok (&error
))
3890 *exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
3894 MonoObject
*result
= mono_runtime_delegate_invoke_checked (delegate
, params
, &error
);
3895 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
3901 * mono_runtime_delegate_try_invoke:
3902 * @delegate: pointer to a delegate object.
3903 * @params: parameters for the delegate.
3904 * @exc: Pointer to the exception result.
3905 * @error: set on error
3907 * Invokes the delegate method @delegate with the parameters provided.
3909 * You can pass NULL as the exc argument if you don't want to
3910 * catch exceptions, otherwise, *exc will be set to the exception
3911 * thrown, if any. On failure to execute, @error will be set.
3912 * if an exception is thrown, you can't use the
3913 * MonoObject* result from the function.
3916 mono_runtime_delegate_try_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
, MonoError
*error
)
3918 MONO_REQ_GC_UNSAFE_MODE
;
3920 mono_error_init (error
);
3922 MonoClass
*klass
= delegate
->vtable
->klass
;
3925 im
= mono_get_delegate_invoke (klass
);
3927 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass
));
3930 o
= mono_runtime_try_invoke (im
, delegate
, params
, exc
, error
);
3932 o
= mono_runtime_invoke_checked (im
, delegate
, params
, error
);
3939 * mono_runtime_delegate_invoke_checked:
3940 * @delegate: pointer to a delegate object.
3941 * @params: parameters for the delegate.
3942 * @error: set on error
3944 * Invokes the delegate method @delegate with the parameters provided.
3946 * On failure @error will be set and you can't use the MonoObject*
3947 * result from the function.
3950 mono_runtime_delegate_invoke_checked (MonoObject
*delegate
, void **params
, MonoError
*error
)
3952 mono_error_init (error
);
3953 return mono_runtime_delegate_try_invoke (delegate
, params
, NULL
, error
);
3956 static char **main_args
= NULL
;
3957 static int num_main_args
= 0;
3960 * mono_runtime_get_main_args:
3962 * Returns: a MonoArray with the arguments passed to the main program
3965 mono_runtime_get_main_args (void)
3967 MONO_REQ_GC_UNSAFE_MODE
;
3969 MonoArray
*result
= mono_runtime_get_main_args_checked (&error
);
3970 mono_error_assert_ok (&error
);
3975 * mono_runtime_get_main_args:
3976 * @error: set on error
3978 * Returns: a MonoArray with the arguments passed to the main
3979 * program. On failure returns NULL and sets @error.
3982 mono_runtime_get_main_args_checked (MonoError
*error
)
3986 MonoDomain
*domain
= mono_domain_get ();
3988 mono_error_init (error
);
3990 res
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, num_main_args
, error
);
3991 return_val_if_nok (error
, NULL
);
3993 for (i
= 0; i
< num_main_args
; ++i
)
3994 mono_array_setref (res
, i
, mono_string_new (domain
, main_args
[i
]));
4000 free_main_args (void)
4002 MONO_REQ_GC_NEUTRAL_MODE
;
4006 for (i
= 0; i
< num_main_args
; ++i
)
4007 g_free (main_args
[i
]);
4014 * mono_runtime_set_main_args:
4015 * @argc: number of arguments from the command line
4016 * @argv: array of strings from the command line
4018 * Set the command line arguments from an embedding application that doesn't otherwise call
4019 * mono_runtime_run_main ().
4022 mono_runtime_set_main_args (int argc
, char* argv
[])
4024 MONO_REQ_GC_NEUTRAL_MODE
;
4029 main_args
= g_new0 (char*, argc
);
4030 num_main_args
= argc
;
4032 for (i
= 0; i
< argc
; ++i
) {
4035 utf8_arg
= mono_utf8_from_external (argv
[i
]);
4036 if (utf8_arg
== NULL
) {
4037 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i
, argv
[i
]);
4038 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4042 main_args
[i
] = utf8_arg
;
4049 * Prepare an array of arguments in order to execute a standard Main()
4050 * method (argc/argv contains the executable name). This method also
4051 * sets the command line argument value needed by System.Environment.
4055 prepare_run_main (MonoMethod
*method
, int argc
, char *argv
[])
4057 MONO_REQ_GC_UNSAFE_MODE
;
4061 MonoArray
*args
= NULL
;
4062 MonoDomain
*domain
= mono_domain_get ();
4063 gchar
*utf8_fullpath
;
4064 MonoMethodSignature
*sig
;
4066 g_assert (method
!= NULL
);
4068 mono_thread_set_main (mono_thread_current ());
4070 main_args
= g_new0 (char*, argc
);
4071 num_main_args
= argc
;
4073 if (!g_path_is_absolute (argv
[0])) {
4074 gchar
*basename
= g_path_get_basename (argv
[0]);
4075 gchar
*fullpath
= g_build_filename (method
->klass
->image
->assembly
->basedir
,
4079 utf8_fullpath
= mono_utf8_from_external (fullpath
);
4080 if(utf8_fullpath
== NULL
) {
4081 /* Printing the arg text will cause glib to
4082 * whinge about "Invalid UTF-8", but at least
4083 * its relevant, and shows the problem text
4086 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath
);
4087 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4094 utf8_fullpath
= mono_utf8_from_external (argv
[0]);
4095 if(utf8_fullpath
== NULL
) {
4096 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv
[0]);
4097 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4102 main_args
[0] = utf8_fullpath
;
4104 for (i
= 1; i
< argc
; ++i
) {
4107 utf8_arg
=mono_utf8_from_external (argv
[i
]);
4108 if(utf8_arg
==NULL
) {
4109 /* Ditto the comment about Invalid UTF-8 here */
4110 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i
, argv
[i
]);
4111 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4115 main_args
[i
] = utf8_arg
;
4120 sig
= mono_method_signature (method
);
4122 g_print ("Unable to load Main method.\n");
4126 if (sig
->param_count
) {
4127 args
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, argc
, &error
);
4128 mono_error_assert_ok (&error
);
4129 for (i
= 0; i
< argc
; ++i
) {
4130 /* The encodings should all work, given that
4131 * we've checked all these args for the
4134 gchar
*str
= mono_utf8_from_external (argv
[i
]);
4135 MonoString
*arg
= mono_string_new (domain
, str
);
4136 mono_array_setref (args
, i
, arg
);
4140 args
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, 0, &error
);
4141 mono_error_assert_ok (&error
);
4144 mono_assembly_set_main (method
->klass
->image
->assembly
);
4150 * mono_runtime_run_main:
4151 * @method: the method to start the application with (usually Main)
4152 * @argc: number of arguments from the command line
4153 * @argv: array of strings from the command line
4154 * @exc: excetption results
4156 * Execute a standard Main() method (argc/argv contains the
4157 * executable name). This method also sets the command line argument value
4158 * needed by System.Environment.
4163 mono_runtime_run_main (MonoMethod
*method
, int argc
, char* argv
[],
4166 MONO_REQ_GC_UNSAFE_MODE
;
4169 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4172 res
= mono_runtime_try_exec_main (method
, args
, exc
);
4174 res
= mono_runtime_exec_main_checked (method
, args
, &error
);
4175 mono_error_raise_exception (&error
); /* OK to throw, external only without a better alternative */
4181 * mono_runtime_run_main_checked:
4182 * @method: the method to start the application with (usually Main)
4183 * @argc: number of arguments from the command line
4184 * @argv: array of strings from the command line
4185 * @error: set on error
4187 * Execute a standard Main() method (argc/argv contains the
4188 * executable name). This method also sets the command line argument value
4189 * needed by System.Environment. On failure sets @error.
4194 mono_runtime_run_main_checked (MonoMethod
*method
, int argc
, char* argv
[],
4197 mono_error_init (error
);
4198 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4199 return mono_runtime_exec_main_checked (method
, args
, error
);
4203 * mono_runtime_try_run_main:
4204 * @method: the method to start the application with (usually Main)
4205 * @argc: number of arguments from the command line
4206 * @argv: array of strings from the command line
4207 * @exc: set if Main throws an exception
4208 * @error: set if Main can't be executed
4210 * Execute a standard Main() method (argc/argv contains the executable
4211 * name). This method also sets the command line argument value needed
4212 * by System.Environment. On failure sets @error if Main can't be
4213 * executed or @exc if it threw and exception.
4218 mono_runtime_try_run_main (MonoMethod
*method
, int argc
, char* argv
[],
4222 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4223 return mono_runtime_try_exec_main (method
, args
, exc
);
4228 serialize_object (MonoObject
*obj
, gboolean
*failure
, MonoObject
**exc
)
4230 static MonoMethod
*serialize_method
;
4236 if (!serialize_method
) {
4237 MonoClass
*klass
= mono_class_get_remoting_services_class ();
4238 serialize_method
= mono_class_get_method_from_name (klass
, "SerializeCallData", -1);
4241 if (!serialize_method
) {
4246 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj
)));
4251 array
= mono_runtime_try_invoke (serialize_method
, NULL
, params
, exc
, &error
);
4252 if (*exc
== NULL
&& !mono_error_ok (&error
))
4253 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
); /* FIXME convert serialize_object to MonoError */
4255 mono_error_cleanup (&error
);
4264 deserialize_object (MonoObject
*obj
, gboolean
*failure
, MonoObject
**exc
)
4266 MONO_REQ_GC_UNSAFE_MODE
;
4268 static MonoMethod
*deserialize_method
;
4274 if (!deserialize_method
) {
4275 MonoClass
*klass
= mono_class_get_remoting_services_class ();
4276 deserialize_method
= mono_class_get_method_from_name (klass
, "DeserializeCallData", -1);
4278 if (!deserialize_method
) {
4286 result
= mono_runtime_try_invoke (deserialize_method
, NULL
, params
, exc
, &error
);
4287 if (*exc
== NULL
&& !mono_error_ok (&error
))
4288 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
); /* FIXME convert deserialize_object to MonoError */
4290 mono_error_cleanup (&error
);
4298 #ifndef DISABLE_REMOTING
4300 make_transparent_proxy (MonoObject
*obj
, MonoError
*error
)
4302 MONO_REQ_GC_UNSAFE_MODE
;
4304 static MonoMethod
*get_proxy_method
;
4306 MonoDomain
*domain
= mono_domain_get ();
4307 MonoRealProxy
*real_proxy
;
4308 MonoReflectionType
*reflection_type
;
4309 MonoTransparentProxy
*transparent_proxy
;
4311 mono_error_init (error
);
4313 if (!get_proxy_method
)
4314 get_proxy_method
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0);
4316 g_assert (mono_class_is_marshalbyref (obj
->vtable
->klass
));
4318 real_proxy
= (MonoRealProxy
*) mono_object_new_checked (domain
, mono_defaults
.real_proxy_class
, error
);
4319 return_val_if_nok (error
, NULL
);
4320 reflection_type
= mono_type_get_object_checked (domain
, &obj
->vtable
->klass
->byval_arg
, error
);
4321 return_val_if_nok (error
, NULL
);
4323 MONO_OBJECT_SETREF (real_proxy
, class_to_proxy
, reflection_type
);
4324 MONO_OBJECT_SETREF (real_proxy
, unwrapped_server
, obj
);
4326 MonoObject
*exc
= NULL
;
4328 transparent_proxy
= (MonoTransparentProxy
*) mono_runtime_try_invoke (get_proxy_method
, real_proxy
, NULL
, &exc
, error
);
4329 if (exc
!= NULL
&& is_ok (error
))
4330 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
4332 return (MonoObject
*) transparent_proxy
;
4334 #endif /* DISABLE_REMOTING */
4337 * mono_object_xdomain_representation
4339 * @target_domain: a domain
4340 * @error: set on error.
4342 * Creates a representation of obj in the domain target_domain. This
4343 * is either a copy of obj arrived through via serialization and
4344 * deserialization or a proxy, depending on whether the object is
4345 * serializable or marshal by ref. obj must not be in target_domain.
4347 * If the object cannot be represented in target_domain, NULL is
4348 * returned and @error is set appropriately.
4351 mono_object_xdomain_representation (MonoObject
*obj
, MonoDomain
*target_domain
, MonoError
*error
)
4353 MONO_REQ_GC_UNSAFE_MODE
;
4355 mono_error_init (error
);
4356 MonoObject
*deserialized
= NULL
;
4358 #ifndef DISABLE_REMOTING
4359 if (mono_class_is_marshalbyref (mono_object_class (obj
))) {
4360 deserialized
= make_transparent_proxy (obj
, error
);
4365 gboolean failure
= FALSE
;
4366 MonoDomain
*domain
= mono_domain_get ();
4367 MonoObject
*serialized
;
4368 MonoObject
*exc
= NULL
;
4370 mono_domain_set_internal_with_options (mono_object_domain (obj
), FALSE
);
4371 serialized
= serialize_object (obj
, &failure
, &exc
);
4372 mono_domain_set_internal_with_options (target_domain
, FALSE
);
4374 deserialized
= deserialize_object (serialized
, &failure
, &exc
);
4375 if (domain
!= target_domain
)
4376 mono_domain_set_internal_with_options (domain
, FALSE
);
4378 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
4381 return deserialized
;
4384 /* Used in call_unhandled_exception_delegate */
4386 create_unhandled_exception_eventargs (MonoObject
*exc
, MonoError
*error
)
4388 MONO_REQ_GC_UNSAFE_MODE
;
4390 mono_error_init (error
);
4393 MonoMethod
*method
= NULL
;
4394 MonoBoolean is_terminating
= TRUE
;
4397 klass
= mono_class_get_unhandled_exception_event_args_class ();
4398 mono_class_init (klass
);
4400 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4401 method
= mono_class_get_method_from_name_flags (klass
, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC
);
4405 args
[1] = &is_terminating
;
4407 obj
= mono_object_new_checked (mono_domain_get (), klass
, error
);
4408 return_val_if_nok (error
, NULL
);
4410 mono_runtime_invoke_checked (method
, obj
, args
, error
);
4411 return_val_if_nok (error
, NULL
);
4416 /* Used in mono_unhandled_exception */
4418 call_unhandled_exception_delegate (MonoDomain
*domain
, MonoObject
*delegate
, MonoObject
*exc
) {
4419 MONO_REQ_GC_UNSAFE_MODE
;
4422 MonoObject
*e
= NULL
;
4424 MonoDomain
*current_domain
= mono_domain_get ();
4426 if (domain
!= current_domain
)
4427 mono_domain_set_internal_with_options (domain
, FALSE
);
4429 g_assert (domain
== mono_object_domain (domain
->domain
));
4431 if (mono_object_domain (exc
) != domain
) {
4433 exc
= mono_object_xdomain_representation (exc
, domain
, &error
);
4435 if (!is_ok (&error
)) {
4436 MonoError inner_error
;
4437 MonoException
*serialization_exc
= mono_error_convert_to_exception (&error
);
4438 exc
= mono_object_xdomain_representation ((MonoObject
*)serialization_exc
, domain
, &inner_error
);
4439 mono_error_assert_ok (&inner_error
);
4441 exc
= (MonoObject
*) mono_exception_from_name_msg (mono_get_corlib (),
4442 "System.Runtime.Serialization", "SerializationException",
4443 "Could not serialize unhandled exception.");
4447 g_assert (mono_object_domain (exc
) == domain
);
4449 pa
[0] = domain
->domain
;
4450 pa
[1] = create_unhandled_exception_eventargs (exc
, &error
);
4451 mono_error_assert_ok (&error
);
4452 mono_runtime_delegate_try_invoke (delegate
, pa
, &e
, &error
);
4453 if (!is_ok (&error
)) {
4455 e
= (MonoObject
*)mono_error_convert_to_exception (&error
);
4457 mono_error_cleanup (&error
);
4460 if (domain
!= current_domain
)
4461 mono_domain_set_internal_with_options (current_domain
, FALSE
);
4464 gchar
*msg
= mono_string_to_utf8_checked (((MonoException
*) e
)->message
, &error
);
4465 if (!mono_error_ok (&error
)) {
4466 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4467 mono_error_cleanup (&error
);
4469 g_warning ("exception inside UnhandledException handler: %s\n", msg
);
4475 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy
= MONO_UNHANDLED_POLICY_CURRENT
;
4478 * mono_runtime_unhandled_exception_policy_set:
4479 * @policy: the new policy
4481 * This is a VM internal routine.
4483 * Sets the runtime policy for handling unhandled exceptions.
4486 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy
) {
4487 runtime_unhandled_exception_policy
= policy
;
4491 * mono_runtime_unhandled_exception_policy_get:
4493 * This is a VM internal routine.
4495 * Gets the runtime policy for handling unhandled exceptions.
4497 MonoRuntimeUnhandledExceptionPolicy
4498 mono_runtime_unhandled_exception_policy_get (void) {
4499 return runtime_unhandled_exception_policy
;
4503 * mono_unhandled_exception:
4504 * @exc: exception thrown
4506 * This is a VM internal routine.
4508 * We call this function when we detect an unhandled exception
4509 * in the default domain.
4511 * It invokes the * UnhandledException event in AppDomain or prints
4512 * a warning to the console
4515 mono_unhandled_exception (MonoObject
*exc
)
4517 MONO_REQ_GC_UNSAFE_MODE
;
4520 MonoClassField
*field
;
4521 MonoDomain
*current_domain
, *root_domain
;
4522 MonoObject
*current_appdomain_delegate
= NULL
, *root_appdomain_delegate
= NULL
;
4524 if (mono_class_has_parent (exc
->vtable
->klass
, mono_defaults
.threadabortexception_class
))
4527 field
= mono_class_get_field_from_name (mono_defaults
.appdomain_class
, "UnhandledException");
4530 current_domain
= mono_domain_get ();
4531 root_domain
= mono_get_root_domain ();
4533 root_appdomain_delegate
= mono_field_get_value_object_checked (root_domain
, field
, (MonoObject
*) root_domain
->domain
, &error
);
4534 mono_error_assert_ok (&error
);
4535 if (current_domain
!= root_domain
) {
4536 current_appdomain_delegate
= mono_field_get_value_object_checked (current_domain
, field
, (MonoObject
*) current_domain
->domain
, &error
);
4537 mono_error_assert_ok (&error
);
4540 if (!current_appdomain_delegate
&& !root_appdomain_delegate
) {
4541 mono_print_unhandled_exception (exc
);
4543 /* unhandled exception callbacks must not be aborted */
4544 mono_threads_begin_abort_protected_block ();
4545 if (root_appdomain_delegate
)
4546 call_unhandled_exception_delegate (root_domain
, root_appdomain_delegate
, exc
);
4547 if (current_appdomain_delegate
)
4548 call_unhandled_exception_delegate (current_domain
, current_appdomain_delegate
, exc
);
4549 mono_threads_end_abort_protected_block ();
4552 /* set exitcode only if we will abort the process */
4553 if ((main_thread
&& mono_thread_internal_current () == main_thread
->internal_thread
)
4554 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
)
4556 mono_environment_exitcode_set (1);
4561 * mono_runtime_exec_managed_code:
4562 * @domain: Application domain
4563 * @main_func: function to invoke from the execution thread
4564 * @main_args: parameter to the main_func
4566 * Launch a new thread to execute a function
4568 * main_func is called back from the thread with main_args as the
4569 * parameter. The callback function is expected to start Main()
4570 * eventually. This function then waits for all managed threads to
4572 * It is not necesseray anymore to execute managed code in a subthread,
4573 * so this function should not be used anymore by default: just
4574 * execute the code and then call mono_thread_manage ().
4577 mono_runtime_exec_managed_code (MonoDomain
*domain
,
4578 MonoMainThreadFunc main_func
,
4582 mono_thread_create_checked (domain
, main_func
, main_args
, &error
);
4583 mono_error_assert_ok (&error
);
4585 mono_thread_manage ();
4589 prepare_thread_to_exec_main (MonoDomain
*domain
, MonoMethod
*method
)
4591 MonoInternalThread
* thread
= mono_thread_internal_current ();
4592 MonoCustomAttrInfo
* cinfo
;
4593 gboolean has_stathread_attribute
;
4595 if (!domain
->entry_assembly
) {
4597 MonoAssembly
*assembly
;
4599 assembly
= method
->klass
->image
->assembly
;
4600 domain
->entry_assembly
= assembly
;
4601 /* Domains created from another domain already have application_base and configuration_file set */
4602 if (domain
->setup
->application_base
== NULL
) {
4603 MONO_OBJECT_SETREF (domain
->setup
, application_base
, mono_string_new (domain
, assembly
->basedir
));
4606 if (domain
->setup
->configuration_file
== NULL
) {
4607 str
= g_strconcat (assembly
->image
->name
, ".config", NULL
);
4608 MONO_OBJECT_SETREF (domain
->setup
, configuration_file
, mono_string_new (domain
, str
));
4610 mono_domain_set_options_from_config (domain
);
4614 MonoError cattr_error
;
4615 cinfo
= mono_custom_attrs_from_method_checked (method
, &cattr_error
);
4616 mono_error_cleanup (&cattr_error
); /* FIXME warn here? */
4618 has_stathread_attribute
= mono_custom_attrs_has_attr (cinfo
, mono_class_get_sta_thread_attribute_class ());
4620 mono_custom_attrs_free (cinfo
);
4622 has_stathread_attribute
= FALSE
;
4624 if (has_stathread_attribute
) {
4625 thread
->apartment_state
= ThreadApartmentState_STA
;
4627 thread
->apartment_state
= ThreadApartmentState_MTA
;
4629 mono_thread_init_apartment_state ();
4634 do_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*error
)
4636 MONO_REQ_GC_UNSAFE_MODE
;
4641 mono_error_init (error
);
4646 /* FIXME: check signature of method */
4647 if (mono_method_signature (method
)->ret
->type
== MONO_TYPE_I4
) {
4649 res
= mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
4651 rval
= *(guint32
*)((char *)res
+ sizeof (MonoObject
));
4654 mono_environment_exitcode_set (rval
);
4656 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
4668 do_try_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
4670 MONO_REQ_GC_UNSAFE_MODE
;
4680 /* FIXME: check signature of method */
4681 if (mono_method_signature (method
)->ret
->type
== MONO_TYPE_I4
) {
4682 MonoError inner_error
;
4684 res
= mono_runtime_try_invoke (method
, NULL
, pa
, exc
, &inner_error
);
4685 if (*exc
== NULL
&& !mono_error_ok (&inner_error
))
4686 *exc
= (MonoObject
*) mono_error_convert_to_exception (&inner_error
);
4688 mono_error_cleanup (&inner_error
);
4691 rval
= *(guint32
*)((char *)res
+ sizeof (MonoObject
));
4695 mono_environment_exitcode_set (rval
);
4697 MonoError inner_error
;
4698 mono_runtime_try_invoke (method
, NULL
, pa
, exc
, &inner_error
);
4699 if (*exc
== NULL
&& !mono_error_ok (&inner_error
))
4700 *exc
= (MonoObject
*) mono_error_convert_to_exception (&inner_error
);
4702 mono_error_cleanup (&inner_error
);
4707 /* If the return type of Main is void, only
4708 * set the exitcode if an exception was thrown
4709 * (we don't want to blow away an
4710 * explicitly-set exit code)
4713 mono_environment_exitcode_set (rval
);
4721 * Execute a standard Main() method (args doesn't contain the
4725 mono_runtime_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
4728 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
4730 int rval
= do_try_exec_main (method
, args
, exc
);
4733 int rval
= do_exec_main_checked (method
, args
, &error
);
4734 mono_error_raise_exception (&error
); /* OK to throw, external only with no better option */
4740 * Execute a standard Main() method (args doesn't contain the
4743 * On failure sets @error
4746 mono_runtime_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*error
)
4748 mono_error_init (error
);
4749 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
4750 return do_exec_main_checked (method
, args
, error
);
4754 * Execute a standard Main() method (args doesn't contain the
4757 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4760 mono_runtime_try_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
4762 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
4763 return do_try_exec_main (method
, args
, exc
);
4768 /** invoke_array_extract_argument:
4769 * @params: array of arguments to the method.
4770 * @i: the index of the argument to extract.
4771 * @t: ith type from the method signature.
4772 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4773 * @error: set on error.
4775 * Given an array of method arguments, return the ith one using the corresponding type
4776 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4778 * On failure sets @error and returns NULL.
4781 invoke_array_extract_argument (MonoArray
*params
, int i
, MonoType
*t
, gboolean
* has_byref_nullables
, MonoError
*error
)
4783 MonoType
*t_orig
= t
;
4784 gpointer result
= NULL
;
4785 mono_error_init (error
);
4790 case MONO_TYPE_BOOLEAN
:
4793 case MONO_TYPE_CHAR
:
4802 case MONO_TYPE_VALUETYPE
:
4803 if (t
->type
== MONO_TYPE_VALUETYPE
&& mono_class_is_nullable (mono_class_from_mono_type (t_orig
))) {
4804 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4805 result
= mono_array_get (params
, MonoObject
*, i
);
4807 *has_byref_nullables
= TRUE
;
4809 /* MS seems to create the objects if a null is passed in */
4810 if (!mono_array_get (params
, MonoObject
*, i
)) {
4811 MonoObject
*o
= mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig
), error
);
4812 return_val_if_nok (error
, NULL
);
4813 mono_array_setref (params
, i
, o
);
4818 * We can't pass the unboxed vtype byref to the callee, since
4819 * that would mean the callee would be able to modify boxed
4820 * primitive types. So we (and MS) make a copy of the boxed
4821 * object, pass that to the callee, and replace the original
4822 * boxed object in the arg array with the copy.
4824 MonoObject
*orig
= mono_array_get (params
, MonoObject
*, i
);
4825 MonoObject
*copy
= mono_value_box_checked (mono_domain_get (), orig
->vtable
->klass
, mono_object_unbox (orig
), error
);
4826 return_val_if_nok (error
, NULL
);
4827 mono_array_setref (params
, i
, copy
);
4830 result
= mono_object_unbox (mono_array_get (params
, MonoObject
*, i
));
4833 case MONO_TYPE_STRING
:
4834 case MONO_TYPE_OBJECT
:
4835 case MONO_TYPE_CLASS
:
4836 case MONO_TYPE_ARRAY
:
4837 case MONO_TYPE_SZARRAY
:
4839 result
= mono_array_addr (params
, MonoObject
*, i
);
4840 // FIXME: I need to check this code path
4842 result
= mono_array_get (params
, MonoObject
*, i
);
4844 case MONO_TYPE_GENERICINST
:
4846 t
= &t
->data
.generic_class
->container_class
->this_arg
;
4848 t
= &t
->data
.generic_class
->container_class
->byval_arg
;
4850 case MONO_TYPE_PTR
: {
4853 /* The argument should be an IntPtr */
4854 arg
= mono_array_get (params
, MonoObject
*, i
);
4858 g_assert (arg
->vtable
->klass
== mono_defaults
.int_class
);
4859 result
= ((MonoIntPtr
*)arg
)->m_value
;
4864 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig
->type
);
4869 * mono_runtime_invoke_array:
4870 * @method: method to invoke
4871 * @obJ: object instance
4872 * @params: arguments to the method
4873 * @exc: exception information.
4875 * Invokes the method represented by @method on the object @obj.
4877 * obj is the 'this' pointer, it should be NULL for static
4878 * methods, a MonoObject* for object instances and a pointer to
4879 * the value type for value types.
4881 * The params array contains the arguments to the method with the
4882 * same convention: MonoObject* pointers for object instances and
4883 * pointers to the value type otherwise. The _invoke_array
4884 * variant takes a C# object[] as the params argument (MonoArray
4885 * *params): in this case the value types are boxed inside the
4886 * respective reference representation.
4888 * From unmanaged code you'll usually use the
4889 * mono_runtime_invoke_checked() variant.
4891 * Note that this function doesn't handle virtual methods for
4892 * you, it will exec the exact method you pass: we still need to
4893 * expose a function to lookup the derived class implementation
4894 * of a virtual method (there are examples of this in the code,
4897 * You can pass NULL as the exc argument if you don't want to
4898 * catch exceptions, otherwise, *exc will be set to the exception
4899 * thrown, if any. if an exception is thrown, you can't use the
4900 * MonoObject* result from the function.
4902 * If the method returns a value type, it is boxed in an object
4906 mono_runtime_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
4911 MonoObject
*result
= mono_runtime_try_invoke_array (method
, obj
, params
, exc
, &error
);
4913 mono_error_cleanup (&error
);
4916 if (!is_ok (&error
))
4917 *exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
4921 MonoObject
*result
= mono_runtime_try_invoke_array (method
, obj
, params
, NULL
, &error
);
4922 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
4928 * mono_runtime_invoke_array_checked:
4929 * @method: method to invoke
4930 * @obJ: object instance
4931 * @params: arguments to the method
4932 * @error: set on failure.
4934 * Invokes the method represented by @method on the object @obj.
4936 * obj is the 'this' pointer, it should be NULL for static
4937 * methods, a MonoObject* for object instances and a pointer to
4938 * the value type for value types.
4940 * The params array contains the arguments to the method with the
4941 * same convention: MonoObject* pointers for object instances and
4942 * pointers to the value type otherwise. The _invoke_array
4943 * variant takes a C# object[] as the params argument (MonoArray
4944 * *params): in this case the value types are boxed inside the
4945 * respective reference representation.
4947 * From unmanaged code you'll usually use the
4948 * mono_runtime_invoke_checked() variant.
4950 * Note that this function doesn't handle virtual methods for
4951 * you, it will exec the exact method you pass: we still need to
4952 * expose a function to lookup the derived class implementation
4953 * of a virtual method (there are examples of this in the code,
4956 * On failure or exception, @error will be set. In that case, you
4957 * can't use the MonoObject* result from the function.
4959 * If the method returns a value type, it is boxed in an object
4963 mono_runtime_invoke_array_checked (MonoMethod
*method
, void *obj
, MonoArray
*params
,
4966 mono_error_init (error
);
4967 return mono_runtime_try_invoke_array (method
, obj
, params
, NULL
, error
);
4971 * mono_runtime_try_invoke_array:
4972 * @method: method to invoke
4973 * @obJ: object instance
4974 * @params: arguments to the method
4975 * @exc: exception information.
4976 * @error: set on failure.
4978 * Invokes the method represented by @method on the object @obj.
4980 * obj is the 'this' pointer, it should be NULL for static
4981 * methods, a MonoObject* for object instances and a pointer to
4982 * the value type for value types.
4984 * The params array contains the arguments to the method with the
4985 * same convention: MonoObject* pointers for object instances and
4986 * pointers to the value type otherwise. The _invoke_array
4987 * variant takes a C# object[] as the params argument (MonoArray
4988 * *params): in this case the value types are boxed inside the
4989 * respective reference representation.
4991 * From unmanaged code you'll usually use the
4992 * mono_runtime_invoke_checked() variant.
4994 * Note that this function doesn't handle virtual methods for
4995 * you, it will exec the exact method you pass: we still need to
4996 * expose a function to lookup the derived class implementation
4997 * of a virtual method (there are examples of this in the code,
5000 * You can pass NULL as the exc argument if you don't want to catch
5001 * exceptions, otherwise, *exc will be set to the exception thrown, if
5002 * any. On other failures, @error will be set. If an exception is
5003 * thrown or there's an error, you can't use the MonoObject* result
5004 * from the function.
5006 * If the method returns a value type, it is boxed in an object
5010 mono_runtime_try_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
5011 MonoObject
**exc
, MonoError
*error
)
5013 MONO_REQ_GC_UNSAFE_MODE
;
5015 mono_error_init (error
);
5017 MonoMethodSignature
*sig
= mono_method_signature (method
);
5018 gpointer
*pa
= NULL
;
5021 gboolean has_byref_nullables
= FALSE
;
5023 if (NULL
!= params
) {
5024 pa
= (void **)alloca (sizeof (gpointer
) * mono_array_length (params
));
5025 for (i
= 0; i
< mono_array_length (params
); i
++) {
5026 MonoType
*t
= sig
->params
[i
];
5027 pa
[i
] = invoke_array_extract_argument (params
, i
, t
, &has_byref_nullables
, error
);
5028 return_val_if_nok (error
, NULL
);
5032 if (!strcmp (method
->name
, ".ctor") && method
->klass
!= mono_defaults
.string_class
) {
5035 if (mono_class_is_nullable (method
->klass
)) {
5036 /* Need to create a boxed vtype instead */
5042 return mono_value_box_checked (mono_domain_get (), method
->klass
->cast_class
, pa
[0], error
);
5047 obj
= mono_object_new_checked (mono_domain_get (), method
->klass
, error
);
5048 mono_error_assert_ok (error
);
5049 g_assert (obj
); /*maybe we should raise a TLE instead?*/
5050 #ifndef DISABLE_REMOTING
5051 if (mono_object_class(obj
) == mono_defaults
.transparent_proxy_class
) {
5052 method
= mono_marshal_get_remoting_invoke (method
->slot
== -1 ? method
: method
->klass
->vtable
[method
->slot
]);
5055 if (method
->klass
->valuetype
)
5056 o
= (MonoObject
*)mono_object_unbox ((MonoObject
*)obj
);
5059 } else if (method
->klass
->valuetype
) {
5060 obj
= mono_value_box_checked (mono_domain_get (), method
->klass
, obj
, error
);
5061 return_val_if_nok (error
, NULL
);
5065 mono_runtime_try_invoke (method
, o
, pa
, exc
, error
);
5067 mono_runtime_invoke_checked (method
, o
, pa
, error
);
5070 return (MonoObject
*)obj
;
5072 if (mono_class_is_nullable (method
->klass
)) {
5073 MonoObject
*nullable
;
5075 /* Convert the unboxed vtype into a Nullable structure */
5076 nullable
= mono_object_new_checked (mono_domain_get (), method
->klass
, error
);
5077 return_val_if_nok (error
, NULL
);
5079 MonoObject
*boxed
= mono_value_box_checked (mono_domain_get (), method
->klass
->cast_class
, obj
, error
);
5080 return_val_if_nok (error
, NULL
);
5081 mono_nullable_init ((guint8
*)mono_object_unbox (nullable
), boxed
, method
->klass
);
5082 obj
= mono_object_unbox (nullable
);
5085 /* obj must be already unboxed if needed */
5087 res
= mono_runtime_try_invoke (method
, obj
, pa
, exc
, error
);
5089 res
= mono_runtime_invoke_checked (method
, obj
, pa
, error
);
5091 return_val_if_nok (error
, NULL
);
5093 if (sig
->ret
->type
== MONO_TYPE_PTR
) {
5094 MonoClass
*pointer_class
;
5095 static MonoMethod
*box_method
;
5097 MonoObject
*box_exc
;
5100 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5101 * convert it to a Pointer object.
5103 pointer_class
= mono_class_get_pointer_class ();
5105 box_method
= mono_class_get_method_from_name (pointer_class
, "Box", -1);
5107 g_assert (res
->vtable
->klass
== mono_defaults
.int_class
);
5108 box_args
[0] = ((MonoIntPtr
*)res
)->m_value
;
5109 box_args
[1] = mono_type_get_object_checked (mono_domain_get (), sig
->ret
, error
);
5110 return_val_if_nok (error
, NULL
);
5112 res
= mono_runtime_try_invoke (box_method
, NULL
, box_args
, &box_exc
, error
);
5113 g_assert (box_exc
== NULL
);
5114 mono_error_assert_ok (error
);
5117 if (has_byref_nullables
) {
5119 * The runtime invoke wrapper already converted byref nullables back,
5120 * and stored them in pa, we just need to copy them back to the
5123 for (i
= 0; i
< mono_array_length (params
); i
++) {
5124 MonoType
*t
= sig
->params
[i
];
5126 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
5127 mono_array_setref (params
, i
, pa
[i
]);
5137 * @klass: the class of the object that we want to create
5139 * Returns: a newly created object whose definition is
5140 * looked up using @klass. This will not invoke any constructors,
5141 * so the consumer of this routine has to invoke any constructors on
5142 * its own to initialize the object.
5144 * It returns NULL on failure.
5147 mono_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5149 MONO_REQ_GC_UNSAFE_MODE
;
5153 MonoObject
* result
= mono_object_new_checked (domain
, klass
, &error
);
5155 mono_error_cleanup (&error
);
5160 ves_icall_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5162 MONO_REQ_GC_UNSAFE_MODE
;
5166 MonoObject
* result
= mono_object_new_checked (domain
, klass
, &error
);
5168 mono_error_set_pending_exception (&error
);
5173 * mono_object_new_checked:
5174 * @klass: the class of the object that we want to create
5175 * @error: set on error
5177 * Returns: a newly created object whose definition is
5178 * looked up using @klass. This will not invoke any constructors,
5179 * so the consumer of this routine has to invoke any constructors on
5180 * its own to initialize the object.
5182 * It returns NULL on failure and sets @error.
5185 mono_object_new_checked (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5187 MONO_REQ_GC_UNSAFE_MODE
;
5191 vtable
= mono_class_vtable (domain
, klass
);
5192 g_assert (vtable
); /* FIXME don't swallow the error */
5194 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
5199 * mono_object_new_pinned:
5201 * Same as mono_object_new, but the returned object will be pinned.
5202 * For SGEN, these objects will only be freed at appdomain unload.
5205 mono_object_new_pinned (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5207 MONO_REQ_GC_UNSAFE_MODE
;
5211 mono_error_init (error
);
5213 vtable
= mono_class_vtable (domain
, klass
);
5214 g_assert (vtable
); /* FIXME don't swallow the error */
5216 MonoObject
*o
= (MonoObject
*)mono_gc_alloc_pinned_obj (vtable
, mono_class_instance_size (klass
));
5218 if (G_UNLIKELY (!o
))
5219 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", mono_class_instance_size (klass
));
5220 else if (G_UNLIKELY (vtable
->klass
->has_finalize
))
5221 mono_object_register_finalizer (o
);
5227 * mono_object_new_specific:
5228 * @vtable: the vtable of the object that we want to create
5230 * Returns: A newly created object with class and domain specified
5234 mono_object_new_specific (MonoVTable
*vtable
)
5237 MonoObject
*o
= mono_object_new_specific_checked (vtable
, &error
);
5238 mono_error_cleanup (&error
);
5244 mono_object_new_specific_checked (MonoVTable
*vtable
, MonoError
*error
)
5246 MONO_REQ_GC_UNSAFE_MODE
;
5250 mono_error_init (error
);
5252 /* check for is_com_object for COM Interop */
5253 if (mono_vtable_is_remote (vtable
) || mono_class_is_com_object (vtable
->klass
))
5256 MonoMethod
*im
= vtable
->domain
->create_proxy_for_type_method
;
5259 MonoClass
*klass
= mono_class_get_activation_services_class ();
5262 mono_class_init (klass
);
5264 im
= mono_class_get_method_from_name (klass
, "CreateProxyForType", 1);
5266 mono_error_set_not_supported (error
, "Linked away.");
5269 vtable
->domain
->create_proxy_for_type_method
= im
;
5272 pa
[0] = mono_type_get_object_checked (mono_domain_get (), &vtable
->klass
->byval_arg
, error
);
5273 if (!mono_error_ok (error
))
5276 o
= mono_runtime_invoke_checked (im
, NULL
, pa
, error
);
5277 if (!mono_error_ok (error
))
5284 return mono_object_new_alloc_specific_checked (vtable
, error
);
5288 ves_icall_object_new_specific (MonoVTable
*vtable
)
5291 MonoObject
*o
= mono_object_new_specific_checked (vtable
, &error
);
5292 mono_error_set_pending_exception (&error
);
5298 * mono_object_new_alloc_specific:
5299 * @vtable: virtual table for the object.
5301 * This function allocates a new `MonoObject` with the type derived
5302 * from the @vtable information. If the class of this object has a
5303 * finalizer, then the object will be tracked for finalization.
5305 * This method might raise an exception on errors. Use the
5306 * `mono_object_new_fast_checked` method if you want to manually raise
5309 * Returns: the allocated object.
5312 mono_object_new_alloc_specific (MonoVTable
*vtable
)
5315 MonoObject
*o
= mono_object_new_alloc_specific_checked (vtable
, &error
);
5316 mono_error_cleanup (&error
);
5322 * mono_object_new_alloc_specific_checked:
5323 * @vtable: virtual table for the object.
5324 * @error: holds the error return value.
5326 * This function allocates a new `MonoObject` with the type derived
5327 * from the @vtable information. If the class of this object has a
5328 * finalizer, then the object will be tracked for finalization.
5330 * If there is not enough memory, the @error parameter will be set
5331 * and will contain a user-visible message with the amount of bytes
5332 * that were requested.
5334 * Returns: the allocated object, or NULL if there is not enough memory
5338 mono_object_new_alloc_specific_checked (MonoVTable
*vtable
, MonoError
*error
)
5340 MONO_REQ_GC_UNSAFE_MODE
;
5344 mono_error_init (error
);
5346 o
= (MonoObject
*)mono_gc_alloc_obj (vtable
, vtable
->klass
->instance_size
);
5348 if (G_UNLIKELY (!o
))
5349 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", vtable
->klass
->instance_size
);
5350 else if (G_UNLIKELY (vtable
->klass
->has_finalize
))
5351 mono_object_register_finalizer (o
);
5357 * mono_object_new_fast:
5358 * @vtable: virtual table for the object.
5360 * This function allocates a new `MonoObject` with the type derived
5361 * from the @vtable information. The returned object is not tracked
5362 * for finalization. If your object implements a finalizer, you should
5363 * use `mono_object_new_alloc_specific` instead.
5365 * This method might raise an exception on errors. Use the
5366 * `mono_object_new_fast_checked` method if you want to manually raise
5369 * Returns: the allocated object.
5372 mono_object_new_fast (MonoVTable
*vtable
)
5375 MonoObject
*o
= mono_object_new_fast_checked (vtable
, &error
);
5376 mono_error_cleanup (&error
);
5382 * mono_object_new_fast_checked:
5383 * @vtable: virtual table for the object.
5384 * @error: holds the error return value.
5386 * This function allocates a new `MonoObject` with the type derived
5387 * from the @vtable information. The returned object is not tracked
5388 * for finalization. If your object implements a finalizer, you should
5389 * use `mono_object_new_alloc_specific_checked` instead.
5391 * If there is not enough memory, the @error parameter will be set
5392 * and will contain a user-visible message with the amount of bytes
5393 * that were requested.
5395 * Returns: the allocated object, or NULL if there is not enough memory
5399 mono_object_new_fast_checked (MonoVTable
*vtable
, MonoError
*error
)
5401 MONO_REQ_GC_UNSAFE_MODE
;
5405 mono_error_init (error
);
5407 o
= mono_gc_alloc_obj (vtable
, vtable
->klass
->instance_size
);
5409 if (G_UNLIKELY (!o
))
5410 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", vtable
->klass
->instance_size
);
5416 ves_icall_object_new_fast (MonoVTable
*vtable
)
5419 MonoObject
*o
= mono_object_new_fast_checked (vtable
, &error
);
5420 mono_error_set_pending_exception (&error
);
5426 mono_object_new_mature (MonoVTable
*vtable
, MonoError
*error
)
5428 MONO_REQ_GC_UNSAFE_MODE
;
5432 mono_error_init (error
);
5434 o
= mono_gc_alloc_mature (vtable
, vtable
->klass
->instance_size
);
5436 if (G_UNLIKELY (!o
))
5437 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", vtable
->klass
->instance_size
);
5438 else if (G_UNLIKELY (vtable
->klass
->has_finalize
))
5439 mono_object_register_finalizer (o
);
5445 * mono_class_get_allocation_ftn:
5447 * @for_box: the object will be used for boxing
5448 * @pass_size_in_words:
5450 * Return the allocation function appropriate for the given class.
5454 mono_class_get_allocation_ftn (MonoVTable
*vtable
, gboolean for_box
, gboolean
*pass_size_in_words
)
5456 MONO_REQ_GC_NEUTRAL_MODE
;
5458 *pass_size_in_words
= FALSE
;
5460 if (mono_class_has_finalizer (vtable
->klass
) || mono_class_is_marshalbyref (vtable
->klass
))
5461 return ves_icall_object_new_specific
;
5463 if (vtable
->gc_descr
!= MONO_GC_DESCRIPTOR_NULL
) {
5465 return ves_icall_object_new_fast
;
5468 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5469 * of the overhead of parameter passing.
5472 *pass_size_in_words = TRUE;
5473 #ifdef GC_REDIRECT_TO_LOCAL
5474 return GC_local_gcj_fast_malloc;
5476 return GC_gcj_fast_malloc;
5481 return ves_icall_object_new_specific
;
5485 * mono_object_new_from_token:
5486 * @image: Context where the type_token is hosted
5487 * @token: a token of the type that we want to create
5489 * Returns: A newly created object whose definition is
5490 * looked up using @token in the @image image
5493 mono_object_new_from_token (MonoDomain
*domain
, MonoImage
*image
, guint32 token
)
5495 MONO_REQ_GC_UNSAFE_MODE
;
5501 klass
= mono_class_get_checked (image
, token
, &error
);
5502 mono_error_assert_ok (&error
);
5504 result
= mono_object_new_checked (domain
, klass
, &error
);
5506 mono_error_cleanup (&error
);
5513 * mono_object_clone:
5514 * @obj: the object to clone
5516 * Returns: A newly created object who is a shallow copy of @obj
5519 mono_object_clone (MonoObject
*obj
)
5522 MonoObject
*o
= mono_object_clone_checked (obj
, &error
);
5523 mono_error_cleanup (&error
);
5529 mono_object_clone_checked (MonoObject
*obj
, MonoError
*error
)
5531 MONO_REQ_GC_UNSAFE_MODE
;
5536 mono_error_init (error
);
5538 size
= obj
->vtable
->klass
->instance_size
;
5540 if (obj
->vtable
->klass
->rank
)
5541 return (MonoObject
*)mono_array_clone_checked ((MonoArray
*)obj
, error
);
5543 o
= (MonoObject
*)mono_gc_alloc_obj (obj
->vtable
, size
);
5545 if (G_UNLIKELY (!o
)) {
5546 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", size
);
5550 /* If the object doesn't contain references this will do a simple memmove. */
5551 mono_gc_wbarrier_object_copy (o
, obj
);
5553 if (obj
->vtable
->klass
->has_finalize
)
5554 mono_object_register_finalizer (o
);
5559 * mono_array_full_copy:
5560 * @src: source array to copy
5561 * @dest: destination array
5563 * Copies the content of one array to another with exactly the same type and size.
5566 mono_array_full_copy (MonoArray
*src
, MonoArray
*dest
)
5568 MONO_REQ_GC_UNSAFE_MODE
;
5571 MonoClass
*klass
= src
->obj
.vtable
->klass
;
5573 g_assert (klass
== dest
->obj
.vtable
->klass
);
5575 size
= mono_array_length (src
);
5576 g_assert (size
== mono_array_length (dest
));
5577 size
*= mono_array_element_size (klass
);
5579 if (klass
->element_class
->valuetype
) {
5580 if (klass
->element_class
->has_references
)
5581 mono_value_copy_array (dest
, 0, mono_array_addr_with_size_fast (src
, 0, 0), mono_array_length (src
));
5583 mono_gc_memmove_atomic (&dest
->vector
, &src
->vector
, size
);
5585 mono_array_memcpy_refs (dest
, 0, src
, 0, mono_array_length (src
));
5588 mono_gc_memmove_atomic (&dest
->vector
, &src
->vector
, size
);
5593 * mono_array_clone_in_domain:
5594 * @domain: the domain in which the array will be cloned into
5595 * @array: the array to clone
5596 * @error: set on error
5598 * This routine returns a copy of the array that is hosted on the
5599 * specified MonoDomain. On failure returns NULL and sets @error.
5602 mono_array_clone_in_domain (MonoDomain
*domain
, MonoArray
*array
, MonoError
*error
)
5604 MONO_REQ_GC_UNSAFE_MODE
;
5609 MonoClass
*klass
= array
->obj
.vtable
->klass
;
5611 mono_error_init (error
);
5613 if (array
->bounds
== NULL
) {
5614 size
= mono_array_length (array
);
5615 o
= mono_array_new_full_checked (domain
, klass
, &size
, NULL
, error
);
5616 return_val_if_nok (error
, NULL
);
5618 size
*= mono_array_element_size (klass
);
5620 if (klass
->element_class
->valuetype
) {
5621 if (klass
->element_class
->has_references
)
5622 mono_value_copy_array (o
, 0, mono_array_addr_with_size_fast (array
, 0, 0), mono_array_length (array
));
5624 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5626 mono_array_memcpy_refs (o
, 0, array
, 0, mono_array_length (array
));
5629 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5634 sizes
= (uintptr_t *)alloca (klass
->rank
* sizeof(intptr_t) * 2);
5635 size
= mono_array_element_size (klass
);
5636 for (i
= 0; i
< klass
->rank
; ++i
) {
5637 sizes
[i
] = array
->bounds
[i
].length
;
5638 size
*= array
->bounds
[i
].length
;
5639 sizes
[i
+ klass
->rank
] = array
->bounds
[i
].lower_bound
;
5641 o
= mono_array_new_full_checked (domain
, klass
, sizes
, (intptr_t*)sizes
+ klass
->rank
, error
);
5642 return_val_if_nok (error
, NULL
);
5644 if (klass
->element_class
->valuetype
) {
5645 if (klass
->element_class
->has_references
)
5646 mono_value_copy_array (o
, 0, mono_array_addr_with_size_fast (array
, 0, 0), mono_array_length (array
));
5648 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5650 mono_array_memcpy_refs (o
, 0, array
, 0, mono_array_length (array
));
5653 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5661 * @array: the array to clone
5663 * Returns: A newly created array who is a shallow copy of @array
5666 mono_array_clone (MonoArray
*array
)
5668 MONO_REQ_GC_UNSAFE_MODE
;
5671 MonoArray
*result
= mono_array_clone_checked (array
, &error
);
5672 mono_error_cleanup (&error
);
5677 * mono_array_clone_checked:
5678 * @array: the array to clone
5679 * @error: set on error
5681 * Returns: A newly created array who is a shallow copy of @array. On
5682 * failure returns NULL and sets @error.
5685 mono_array_clone_checked (MonoArray
*array
, MonoError
*error
)
5688 MONO_REQ_GC_UNSAFE_MODE
;
5689 return mono_array_clone_in_domain (((MonoObject
*)array
)->vtable
->domain
, array
, error
);
5692 /* helper macros to check for overflow when calculating the size of arrays */
5693 #ifdef MONO_BIG_ARRAYS
5694 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5695 #define MYGUINT_MAX MYGUINT64_MAX
5696 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5697 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5698 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5699 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5700 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5702 #define MYGUINT32_MAX 4294967295U
5703 #define MYGUINT_MAX MYGUINT32_MAX
5704 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5705 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5706 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5707 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5708 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5712 mono_array_calc_byte_len (MonoClass
*klass
, uintptr_t len
, uintptr_t *res
)
5714 MONO_REQ_GC_NEUTRAL_MODE
;
5718 byte_len
= mono_array_element_size (klass
);
5719 if (CHECK_MUL_OVERFLOW_UN (byte_len
, len
))
5722 if (CHECK_ADD_OVERFLOW_UN (byte_len
, MONO_SIZEOF_MONO_ARRAY
))
5724 byte_len
+= MONO_SIZEOF_MONO_ARRAY
;
5732 * mono_array_new_full:
5733 * @domain: domain where the object is created
5734 * @array_class: array class
5735 * @lengths: lengths for each dimension in the array
5736 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5738 * This routine creates a new array objects with the given dimensions,
5739 * lower bounds and type.
5742 mono_array_new_full (MonoDomain
*domain
, MonoClass
*array_class
, uintptr_t *lengths
, intptr_t *lower_bounds
)
5745 MonoArray
*array
= mono_array_new_full_checked (domain
, array_class
, lengths
, lower_bounds
, &error
);
5746 mono_error_cleanup (&error
);
5752 mono_array_new_full_checked (MonoDomain
*domain
, MonoClass
*array_class
, uintptr_t *lengths
, intptr_t *lower_bounds
, MonoError
*error
)
5754 MONO_REQ_GC_UNSAFE_MODE
;
5756 uintptr_t byte_len
= 0, len
, bounds_size
;
5759 MonoArrayBounds
*bounds
;
5763 mono_error_init (error
);
5765 if (!array_class
->inited
)
5766 mono_class_init (array_class
);
5770 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5771 if (array_class
->rank
== 1 && ((array_class
->byval_arg
.type
== MONO_TYPE_SZARRAY
) || (lower_bounds
&& lower_bounds
[0] == 0))) {
5773 if (len
> MONO_ARRAY_MAX_INDEX
) {
5774 mono_error_set_generic_error (error
, "System", "OverflowException", "");
5779 bounds_size
= sizeof (MonoArrayBounds
) * array_class
->rank
;
5781 for (i
= 0; i
< array_class
->rank
; ++i
) {
5782 if (lengths
[i
] > MONO_ARRAY_MAX_INDEX
) {
5783 mono_error_set_generic_error (error
, "System", "OverflowException", "");
5786 if (CHECK_MUL_OVERFLOW_UN (len
, lengths
[i
])) {
5787 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5794 if (!mono_array_calc_byte_len (array_class
, len
, &byte_len
)) {
5795 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5801 if (CHECK_ADD_OVERFLOW_UN (byte_len
, 3)) {
5802 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5805 byte_len
= (byte_len
+ 3) & ~3;
5806 if (CHECK_ADD_OVERFLOW_UN (byte_len
, bounds_size
)) {
5807 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5810 byte_len
+= bounds_size
;
5813 * Following three lines almost taken from mono_object_new ():
5814 * they need to be kept in sync.
5816 vtable
= mono_class_vtable_full (domain
, array_class
, error
);
5817 return_val_if_nok (error
, NULL
);
5820 o
= (MonoObject
*)mono_gc_alloc_array (vtable
, byte_len
, len
, bounds_size
);
5822 o
= (MonoObject
*)mono_gc_alloc_vector (vtable
, byte_len
, len
);
5824 if (G_UNLIKELY (!o
)) {
5825 mono_error_set_out_of_memory (error
, "Could not allocate %zd bytes", (gsize
) byte_len
);
5829 array
= (MonoArray
*)o
;
5831 bounds
= array
->bounds
;
5834 for (i
= 0; i
< array_class
->rank
; ++i
) {
5835 bounds
[i
].length
= lengths
[i
];
5837 bounds
[i
].lower_bound
= lower_bounds
[i
];
5846 * @domain: domain where the object is created
5847 * @eclass: element class
5848 * @n: number of array elements
5850 * This routine creates a new szarray with @n elements of type @eclass.
5853 mono_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
5855 MONO_REQ_GC_UNSAFE_MODE
;
5858 MonoArray
*result
= mono_array_new_checked (domain
, eclass
, n
, &error
);
5859 mono_error_cleanup (&error
);
5864 * mono_array_new_checked:
5865 * @domain: domain where the object is created
5866 * @eclass: element class
5867 * @n: number of array elements
5868 * @error: set on error
5870 * This routine creates a new szarray with @n elements of type @eclass.
5871 * On failure returns NULL and sets @error.
5874 mono_array_new_checked (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
, MonoError
*error
)
5878 mono_error_init (error
);
5880 ac
= mono_array_class_get (eclass
, 1);
5883 MonoVTable
*vtable
= mono_class_vtable_full (domain
, ac
, error
);
5884 return_val_if_nok (error
, NULL
);
5886 return mono_array_new_specific_checked (vtable
, n
, error
);
5890 ves_icall_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
5893 MonoArray
*arr
= mono_array_new_checked (domain
, eclass
, n
, &error
);
5894 mono_error_set_pending_exception (&error
);
5900 * mono_array_new_specific:
5901 * @vtable: a vtable in the appropriate domain for an initialized class
5902 * @n: number of array elements
5904 * This routine is a fast alternative to mono_array_new() for code which
5905 * can be sure about the domain it operates in.
5908 mono_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
5911 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, &error
);
5912 mono_error_cleanup (&error
);
5918 mono_array_new_specific_checked (MonoVTable
*vtable
, uintptr_t n
, MonoError
*error
)
5920 MONO_REQ_GC_UNSAFE_MODE
;
5925 mono_error_init (error
);
5927 if (G_UNLIKELY (n
> MONO_ARRAY_MAX_INDEX
)) {
5928 mono_error_set_generic_error (error
, "System", "OverflowException", "");
5932 if (!mono_array_calc_byte_len (vtable
->klass
, n
, &byte_len
)) {
5933 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5936 o
= (MonoObject
*)mono_gc_alloc_vector (vtable
, byte_len
, n
);
5938 if (G_UNLIKELY (!o
)) {
5939 mono_error_set_out_of_memory (error
, "Could not allocate %zd bytes", (gsize
) byte_len
);
5943 return (MonoArray
*)o
;
5947 ves_icall_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
5950 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, &error
);
5951 mono_error_set_pending_exception (&error
);
5957 * mono_string_new_utf16:
5958 * @text: a pointer to an utf16 string
5959 * @len: the length of the string
5961 * Returns: A newly created string object which contains @text.
5964 mono_string_new_utf16 (MonoDomain
*domain
, const guint16
*text
, gint32 len
)
5966 MONO_REQ_GC_UNSAFE_MODE
;
5969 MonoString
*res
= NULL
;
5970 res
= mono_string_new_utf16_checked (domain
, text
, len
, &error
);
5971 mono_error_cleanup (&error
);
5977 * mono_string_new_utf16_checked:
5978 * @text: a pointer to an utf16 string
5979 * @len: the length of the string
5980 * @error: written on error.
5982 * Returns: A newly created string object which contains @text.
5983 * On error, returns NULL and sets @error.
5986 mono_string_new_utf16_checked (MonoDomain
*domain
, const guint16
*text
, gint32 len
, MonoError
*error
)
5988 MONO_REQ_GC_UNSAFE_MODE
;
5992 mono_error_init (error
);
5994 s
= mono_string_new_size_checked (domain
, len
, error
);
5996 memcpy (mono_string_chars (s
), text
, len
* 2);
6002 * mono_string_new_utf32:
6003 * @text: a pointer to an utf32 string
6004 * @len: the length of the string
6005 * @error: set on failure.
6007 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6010 mono_string_new_utf32_checked (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
, MonoError
*error
)
6012 MONO_REQ_GC_UNSAFE_MODE
;
6015 mono_unichar2
*utf16_output
= NULL
;
6016 gint32 utf16_len
= 0;
6017 GError
*gerror
= NULL
;
6018 glong items_written
;
6020 mono_error_init (error
);
6021 utf16_output
= g_ucs4_to_utf16 (text
, len
, NULL
, &items_written
, &gerror
);
6024 g_error_free (gerror
);
6026 while (utf16_output
[utf16_len
]) utf16_len
++;
6028 s
= mono_string_new_size_checked (domain
, utf16_len
, error
);
6029 return_val_if_nok (error
, NULL
);
6031 memcpy (mono_string_chars (s
), utf16_output
, utf16_len
* 2);
6033 g_free (utf16_output
);
6039 * mono_string_new_utf32:
6040 * @text: a pointer to an utf32 string
6041 * @len: the length of the string
6043 * Returns: A newly created string object which contains @text.
6046 mono_string_new_utf32 (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
)
6049 MonoString
*result
= mono_string_new_utf32_checked (domain
, text
, len
, &error
);
6050 mono_error_cleanup (&error
);
6055 * mono_string_new_size:
6056 * @text: a pointer to an utf16 string
6057 * @len: the length of the string
6059 * Returns: A newly created string object of @len
6062 mono_string_new_size (MonoDomain
*domain
, gint32 len
)
6065 MonoString
*str
= mono_string_new_size_checked (domain
, len
, &error
);
6066 mono_error_cleanup (&error
);
6072 mono_string_new_size_checked (MonoDomain
*domain
, gint32 len
, MonoError
*error
)
6074 MONO_REQ_GC_UNSAFE_MODE
;
6080 mono_error_init (error
);
6082 /* check for overflow */
6083 if (len
< 0 || len
> ((SIZE_MAX
- G_STRUCT_OFFSET (MonoString
, chars
) - 8) / 2)) {
6084 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", -1);
6088 size
= (G_STRUCT_OFFSET (MonoString
, chars
) + (((size_t)len
+ 1) * 2));
6089 g_assert (size
> 0);
6091 vtable
= mono_class_vtable (domain
, mono_defaults
.string_class
);
6094 s
= (MonoString
*)mono_gc_alloc_string (vtable
, size
, len
);
6096 if (G_UNLIKELY (!s
)) {
6097 mono_error_set_out_of_memory (error
, "Could not allocate %zd bytes", size
);
6105 * mono_string_new_len:
6106 * @text: a pointer to an utf8 string
6107 * @length: number of bytes in @text to consider
6109 * Returns: A newly created string object which contains @text.
6112 mono_string_new_len (MonoDomain
*domain
, const char *text
, guint length
)
6114 MONO_REQ_GC_UNSAFE_MODE
;
6117 MonoString
*result
= mono_string_new_len_checked (domain
, text
, length
, &error
);
6118 mono_error_cleanup (&error
);
6123 * mono_string_new_len_checked:
6124 * @text: a pointer to an utf8 string
6125 * @length: number of bytes in @text to consider
6126 * @error: set on error
6128 * Returns: A newly created string object which contains @text. On
6129 * failure returns NULL and sets @error.
6132 mono_string_new_len_checked (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6134 MONO_REQ_GC_UNSAFE_MODE
;
6136 mono_error_init (error
);
6138 GError
*eg_error
= NULL
;
6139 MonoString
*o
= NULL
;
6141 glong items_written
;
6143 ut
= eg_utf8_to_utf16_with_nuls (text
, length
, NULL
, &items_written
, &eg_error
);
6146 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6148 g_error_free (eg_error
);
6157 * @text: a pointer to an utf8 string
6159 * Returns: A newly created string object which contains @text.
6161 * This function asserts if it cannot allocate a new string.
6163 * @deprecated Use mono_string_new_checked in new code.
6166 mono_string_new (MonoDomain
*domain
, const char *text
)
6169 MonoString
*res
= NULL
;
6170 res
= mono_string_new_checked (domain
, text
, &error
);
6171 mono_error_assert_ok (&error
);
6176 * mono_string_new_checked:
6177 * @text: a pointer to an utf8 string
6178 * @merror: set on error
6180 * Returns: A newly created string object which contains @text.
6181 * On error returns NULL and sets @merror.
6184 mono_string_new_checked (MonoDomain
*domain
, const char *text
, MonoError
*error
)
6186 MONO_REQ_GC_UNSAFE_MODE
;
6188 GError
*eg_error
= NULL
;
6189 MonoString
*o
= NULL
;
6191 glong items_written
;
6194 mono_error_init (error
);
6198 ut
= g_utf8_to_utf16 (text
, l
, NULL
, &items_written
, &eg_error
);
6201 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6203 g_error_free (eg_error
);
6207 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6212 MonoString
*o
= NULL
;
6214 if (!g_utf8_validate (text
, -1, &end
)) {
6215 mono_error_set_argument (error
, "text", "Not a valid utf8 string");
6219 len
= g_utf8_strlen (text
, -1);
6220 o
= mono_string_new_size_checked (domain
, len
, error
);
6223 str
= mono_string_chars (o
);
6225 while (text
< end
) {
6226 *str
++ = g_utf8_get_char (text
);
6227 text
= g_utf8_next_char (text
);
6236 * mono_string_new_wrapper:
6237 * @text: pointer to utf8 characters.
6239 * Helper function to create a string object from @text in the current domain.
6242 mono_string_new_wrapper (const char *text
)
6244 MONO_REQ_GC_UNSAFE_MODE
;
6246 MonoDomain
*domain
= mono_domain_get ();
6249 return mono_string_new (domain
, text
);
6256 * @class: the class of the value
6257 * @value: a pointer to the unboxed data
6259 * Returns: A newly created object which contains @value.
6262 mono_value_box (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
)
6265 MonoObject
*result
= mono_value_box_checked (domain
, klass
, value
, &error
);
6266 mono_error_cleanup (&error
);
6271 * mono_value_box_checked:
6272 * @domain: the domain of the new object
6273 * @class: the class of the value
6274 * @value: a pointer to the unboxed data
6275 * @error: set on error
6277 * Returns: A newly created object which contains @value. On failure
6278 * returns NULL and sets @error.
6281 mono_value_box_checked (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
, MonoError
*error
)
6283 MONO_REQ_GC_UNSAFE_MODE
;
6288 mono_error_init (error
);
6290 g_assert (klass
->valuetype
);
6291 if (mono_class_is_nullable (klass
))
6292 return mono_nullable_box ((guint8
*)value
, klass
, error
);
6294 vtable
= mono_class_vtable (domain
, klass
);
6297 size
= mono_class_instance_size (klass
);
6298 res
= mono_object_new_alloc_specific_checked (vtable
, error
);
6299 return_val_if_nok (error
, NULL
);
6301 size
= size
- sizeof (MonoObject
);
6304 g_assert (size
== mono_class_value_size (klass
, NULL
));
6305 mono_gc_wbarrier_value_copy ((char *)res
+ sizeof (MonoObject
), value
, 1, klass
);
6307 #if NO_UNALIGNED_ACCESS
6308 mono_gc_memmove_atomic ((char *)res
+ sizeof (MonoObject
), value
, size
);
6312 *((guint8
*) res
+ sizeof (MonoObject
)) = *(guint8
*) value
;
6315 *(guint16
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint16
*) value
;
6318 *(guint32
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint32
*) value
;
6321 *(guint64
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint64
*) value
;
6324 mono_gc_memmove_atomic ((char *)res
+ sizeof (MonoObject
), value
, size
);
6328 if (klass
->has_finalize
) {
6329 mono_object_register_finalizer (res
);
6330 return_val_if_nok (error
, NULL
);
6337 * @dest: destination pointer
6338 * @src: source pointer
6339 * @klass: a valuetype class
6341 * Copy a valuetype from @src to @dest. This function must be used
6342 * when @klass contains references fields.
6345 mono_value_copy (gpointer dest
, gpointer src
, MonoClass
*klass
)
6347 MONO_REQ_GC_UNSAFE_MODE
;
6349 mono_gc_wbarrier_value_copy (dest
, src
, 1, klass
);
6353 * mono_value_copy_array:
6354 * @dest: destination array
6355 * @dest_idx: index in the @dest array
6356 * @src: source pointer
6357 * @count: number of items
6359 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6360 * This function must be used when @klass contains references fields.
6361 * Overlap is handled.
6364 mono_value_copy_array (MonoArray
*dest
, int dest_idx
, gpointer src
, int count
)
6366 MONO_REQ_GC_UNSAFE_MODE
;
6368 int size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
6369 char *d
= mono_array_addr_with_size_fast (dest
, size
, dest_idx
);
6370 g_assert (size
== mono_class_value_size (mono_object_class (dest
)->element_class
, NULL
));
6371 mono_gc_wbarrier_value_copy (d
, src
, count
, mono_object_class (dest
)->element_class
);
6375 * mono_object_get_domain:
6376 * @obj: object to query
6378 * Returns: the MonoDomain where the object is hosted
6381 mono_object_get_domain (MonoObject
*obj
)
6383 MONO_REQ_GC_UNSAFE_MODE
;
6385 return mono_object_domain (obj
);
6389 * mono_object_get_class:
6390 * @obj: object to query
6392 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6394 * Returns: the MonoClass of the object.
6397 mono_object_get_class (MonoObject
*obj
)
6399 MONO_REQ_GC_UNSAFE_MODE
;
6401 return mono_object_class (obj
);
6404 * mono_object_get_size:
6405 * @o: object to query
6407 * Returns: the size, in bytes, of @o
6410 mono_object_get_size (MonoObject
* o
)
6412 MONO_REQ_GC_UNSAFE_MODE
;
6414 MonoClass
* klass
= mono_object_class (o
);
6415 if (klass
== mono_defaults
.string_class
) {
6416 return sizeof (MonoString
) + 2 * mono_string_length ((MonoString
*) o
) + 2;
6417 } else if (o
->vtable
->rank
) {
6418 MonoArray
*array
= (MonoArray
*)o
;
6419 size_t size
= MONO_SIZEOF_MONO_ARRAY
+ mono_array_element_size (klass
) * mono_array_length (array
);
6420 if (array
->bounds
) {
6423 size
+= sizeof (MonoArrayBounds
) * o
->vtable
->rank
;
6427 return mono_class_instance_size (klass
);
6432 * mono_object_unbox:
6433 * @obj: object to unbox
6435 * Returns: a pointer to the start of the valuetype boxed in this
6438 * This method will assert if the object passed is not a valuetype.
6441 mono_object_unbox (MonoObject
*obj
)
6443 MONO_REQ_GC_UNSAFE_MODE
;
6445 /* add assert for valuetypes? */
6446 g_assert (obj
->vtable
->klass
->valuetype
);
6447 return ((char*)obj
) + sizeof (MonoObject
);
6451 * mono_object_isinst:
6453 * @klass: a pointer to a class
6455 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6458 mono_object_isinst (MonoObject
*obj
, MonoClass
*klass
)
6460 MONO_REQ_GC_UNSAFE_MODE
;
6463 MonoObject
*result
= mono_object_isinst_checked (obj
, klass
, &error
);
6464 mono_error_cleanup (&error
);
6470 * mono_object_isinst_checked:
6472 * @klass: a pointer to a class
6473 * @error: set on error
6475 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6476 * On failure returns NULL and sets @error.
6479 mono_object_isinst_checked (MonoObject
*obj
, MonoClass
*klass
, MonoError
*error
)
6481 MONO_REQ_GC_UNSAFE_MODE
;
6483 mono_error_init (error
);
6485 MonoObject
*result
= NULL
;
6488 mono_class_init (klass
);
6490 if (mono_class_is_marshalbyref (klass
) || (klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
)) {
6491 result
= mono_object_isinst_mbyref_checked (obj
, klass
, error
);
6498 return mono_class_is_assignable_from (klass
, obj
->vtable
->klass
) ? obj
: NULL
;
6502 mono_object_isinst_mbyref (MonoObject
*obj
, MonoClass
*klass
)
6504 MONO_REQ_GC_UNSAFE_MODE
;
6507 MonoObject
*result
= mono_object_isinst_mbyref_checked (obj
, klass
, &error
);
6508 mono_error_cleanup (&error
); /* FIXME better API that doesn't swallow the error */
6513 mono_object_isinst_mbyref_checked (MonoObject
*obj
, MonoClass
*klass
, MonoError
*error
)
6515 MONO_REQ_GC_UNSAFE_MODE
;
6519 mono_error_init (error
);
6526 if (klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
6527 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt
, klass
->interface_id
)) {
6531 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6532 if (mono_class_has_variant_generic_params (klass
) && mono_class_is_assignable_from (klass
, obj
->vtable
->klass
))
6535 MonoClass
*oklass
= vt
->klass
;
6536 if (mono_class_is_transparent_proxy (oklass
))
6537 oklass
= ((MonoTransparentProxy
*)obj
)->remote_class
->proxy_class
;
6539 mono_class_setup_supertypes (klass
);
6540 if ((oklass
->idepth
>= klass
->idepth
) && (oklass
->supertypes
[klass
->idepth
- 1] == klass
))
6543 #ifndef DISABLE_REMOTING
6544 if (vt
->klass
== mono_defaults
.transparent_proxy_class
&& ((MonoTransparentProxy
*)obj
)->custom_type_info
)
6546 MonoDomain
*domain
= mono_domain_get ();
6548 MonoObject
*rp
= (MonoObject
*)((MonoTransparentProxy
*)obj
)->rp
;
6549 MonoClass
*rpklass
= mono_defaults
.iremotingtypeinfo_class
;
6550 MonoMethod
*im
= NULL
;
6553 im
= mono_class_get_method_from_name (rpklass
, "CanCastTo", -1);
6555 mono_error_set_not_supported (error
, "Linked away.");
6558 im
= mono_object_get_virtual_method (rp
, im
);
6561 pa
[0] = mono_type_get_object_checked (domain
, &klass
->byval_arg
, error
);
6562 return_val_if_nok (error
, NULL
);
6565 res
= mono_runtime_invoke_checked (im
, rp
, pa
, error
);
6566 return_val_if_nok (error
, NULL
);
6568 if (*(MonoBoolean
*) mono_object_unbox(res
)) {
6569 /* Update the vtable of the remote type, so it can safely cast to this new type */
6570 mono_upgrade_remote_class (domain
, obj
, klass
, error
);
6571 return_val_if_nok (error
, NULL
);
6575 #endif /* DISABLE_REMOTING */
6580 * mono_object_castclass_mbyref:
6582 * @klass: a pointer to a class
6584 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6587 mono_object_castclass_mbyref (MonoObject
*obj
, MonoClass
*klass
)
6589 MONO_REQ_GC_UNSAFE_MODE
;
6592 if (!obj
) return NULL
;
6593 if (mono_object_isinst_mbyref_checked (obj
, klass
, &error
)) return obj
;
6594 mono_error_cleanup (&error
);
6599 MonoDomain
*orig_domain
;
6605 str_lookup (MonoDomain
*domain
, gpointer user_data
)
6607 MONO_REQ_GC_UNSAFE_MODE
;
6609 LDStrInfo
*info
= (LDStrInfo
*)user_data
;
6610 if (info
->res
|| domain
== info
->orig_domain
)
6612 info
->res
= (MonoString
*)mono_g_hash_table_lookup (domain
->ldstr_table
, info
->ins
);
6616 mono_string_get_pinned (MonoString
*str
, MonoError
*error
)
6618 MONO_REQ_GC_UNSAFE_MODE
;
6620 mono_error_init (error
);
6622 /* We only need to make a pinned version of a string if this is a moving GC */
6623 if (!mono_gc_is_moving ())
6627 size
= sizeof (MonoString
) + 2 * (mono_string_length (str
) + 1);
6628 news
= (MonoString
*)mono_gc_alloc_pinned_obj (((MonoObject
*)str
)->vtable
, size
);
6630 memcpy (mono_string_chars (news
), mono_string_chars (str
), mono_string_length (str
) * 2);
6631 news
->length
= mono_string_length (str
);
6633 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", size
);
6639 mono_string_is_interned_lookup (MonoString
*str
, int insert
, MonoError
*error
)
6641 MONO_REQ_GC_UNSAFE_MODE
;
6643 MonoGHashTable
*ldstr_table
;
6644 MonoString
*s
, *res
;
6647 mono_error_init (error
);
6649 domain
= ((MonoObject
*)str
)->vtable
->domain
;
6650 ldstr_table
= domain
->ldstr_table
;
6652 res
= (MonoString
*)mono_g_hash_table_lookup (ldstr_table
, str
);
6658 /* Allocate outside the lock */
6660 s
= mono_string_get_pinned (str
, error
);
6661 return_val_if_nok (error
, NULL
);
6664 res
= (MonoString
*)mono_g_hash_table_lookup (ldstr_table
, str
);
6669 mono_g_hash_table_insert (ldstr_table
, s
, s
);
6674 LDStrInfo ldstr_info
;
6675 ldstr_info
.orig_domain
= domain
;
6676 ldstr_info
.ins
= str
;
6677 ldstr_info
.res
= NULL
;
6679 mono_domain_foreach (str_lookup
, &ldstr_info
);
6680 if (ldstr_info
.res
) {
6682 * the string was already interned in some other domain:
6683 * intern it in the current one as well.
6685 mono_g_hash_table_insert (ldstr_table
, str
, str
);
6695 * mono_string_is_interned:
6696 * @o: String to probe
6698 * Returns whether the string has been interned.
6701 mono_string_is_interned (MonoString
*o
)
6704 MonoString
*result
= mono_string_is_interned_lookup (o
, FALSE
, &error
);
6705 /* This function does not fail. */
6706 mono_error_assert_ok (&error
);
6711 * mono_string_intern:
6712 * @o: String to intern
6714 * Interns the string passed.
6715 * Returns: The interned string.
6718 mono_string_intern (MonoString
*str
)
6721 MonoString
*result
= mono_string_intern_checked (str
, &error
);
6722 mono_error_assert_ok (&error
);
6727 * mono_string_intern_checked:
6728 * @o: String to intern
6729 * @error: set on error.
6731 * Interns the string passed.
6732 * Returns: The interned string. On failure returns NULL and sets @error
6735 mono_string_intern_checked (MonoString
*str
, MonoError
*error
)
6737 MONO_REQ_GC_UNSAFE_MODE
;
6739 mono_error_init (error
);
6741 return mono_string_is_interned_lookup (str
, TRUE
, error
);
6746 * @domain: the domain where the string will be used.
6747 * @image: a metadata context
6748 * @idx: index into the user string table.
6750 * Implementation for the ldstr opcode.
6751 * Returns: a loaded string from the @image/@idx combination.
6754 mono_ldstr (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
)
6757 MonoString
*result
= mono_ldstr_checked (domain
, image
, idx
, &error
);
6758 mono_error_cleanup (&error
);
6763 * mono_ldstr_checked:
6764 * @domain: the domain where the string will be used.
6765 * @image: a metadata context
6766 * @idx: index into the user string table.
6767 * @error: set on error.
6769 * Implementation for the ldstr opcode.
6770 * Returns: a loaded string from the @image/@idx combination.
6771 * On failure returns NULL and sets @error.
6774 mono_ldstr_checked (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
, MonoError
*error
)
6776 MONO_REQ_GC_UNSAFE_MODE
;
6777 mono_error_init (error
);
6779 if (image
->dynamic
) {
6780 MonoString
*str
= (MonoString
*)mono_lookup_dynamic_token (image
, MONO_TOKEN_STRING
| idx
, NULL
, error
);
6783 if (!mono_verifier_verify_string_signature (image
, idx
, NULL
))
6784 return NULL
; /*FIXME we should probably be raising an exception here*/
6785 MonoString
*str
= mono_ldstr_metadata_sig (domain
, mono_metadata_user_string (image
, idx
), error
);
6791 * mono_ldstr_metadata_sig
6792 * @domain: the domain for the string
6793 * @sig: the signature of a metadata string
6794 * @error: set on error
6796 * Returns: a MonoString for a string stored in the metadata. On
6797 * failure returns NULL and sets @error.
6800 mono_ldstr_metadata_sig (MonoDomain
*domain
, const char* sig
, MonoError
*error
)
6802 MONO_REQ_GC_UNSAFE_MODE
;
6804 mono_error_init (error
);
6805 const char *str
= sig
;
6806 MonoString
*o
, *interned
;
6809 len2
= mono_metadata_decode_blob_size (str
, &str
);
6812 o
= mono_string_new_utf16_checked (domain
, (guint16
*)str
, len2
, error
);
6813 return_val_if_nok (error
, NULL
);
6814 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6817 guint16
*p2
= (guint16
*)mono_string_chars (o
);
6818 for (i
= 0; i
< len2
; ++i
) {
6819 *p2
= GUINT16_FROM_LE (*p2
);
6825 interned
= (MonoString
*)mono_g_hash_table_lookup (domain
->ldstr_table
, o
);
6828 return interned
; /* o will get garbage collected */
6830 o
= mono_string_get_pinned (o
, error
);
6833 interned
= (MonoString
*)mono_g_hash_table_lookup (domain
->ldstr_table
, o
);
6835 mono_g_hash_table_insert (domain
->ldstr_table
, o
, o
);
6847 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6851 mono_ldstr_utf8 (MonoImage
*image
, guint32 idx
, MonoError
*error
)
6857 GError
*gerror
= NULL
;
6859 mono_error_init (error
);
6861 if (!mono_verifier_verify_string_signature (image
, idx
, NULL
))
6862 return NULL
; /*FIXME we should probably be raising an exception here*/
6863 str
= mono_metadata_user_string (image
, idx
);
6865 len2
= mono_metadata_decode_blob_size (str
, &str
);
6868 as
= g_utf16_to_utf8 ((guint16
*)str
, len2
, NULL
, &written
, &gerror
);
6870 mono_error_set_argument (error
, "string", "%s", gerror
->message
);
6871 g_error_free (gerror
);
6874 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6875 if (len2
> written
) {
6876 /* allocate the total length and copy the part of the string that has been converted */
6877 char *as2
= (char *)g_malloc0 (len2
);
6878 memcpy (as2
, as
, written
);
6887 * mono_string_to_utf8:
6888 * @s: a System.String
6890 * Returns the UTF8 representation for @s.
6891 * The resulting buffer needs to be freed with mono_free().
6893 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6896 mono_string_to_utf8 (MonoString
*s
)
6898 MONO_REQ_GC_UNSAFE_MODE
;
6901 char *result
= mono_string_to_utf8_checked (s
, &error
);
6903 if (!is_ok (&error
)) {
6904 mono_error_cleanup (&error
);
6911 * mono_string_to_utf8_checked:
6912 * @s: a System.String
6913 * @error: a MonoError.
6915 * Converts a MonoString to its UTF8 representation. May fail; check
6916 * @error to determine whether the conversion was successful.
6917 * The resulting buffer should be freed with mono_free().
6920 mono_string_to_utf8_checked (MonoString
*s
, MonoError
*error
)
6922 MONO_REQ_GC_UNSAFE_MODE
;
6926 GError
*gerror
= NULL
;
6928 mono_error_init (error
);
6934 return g_strdup ("");
6936 as
= g_utf16_to_utf8 (mono_string_chars (s
), s
->length
, NULL
, &written
, &gerror
);
6938 mono_error_set_argument (error
, "string", "%s", gerror
->message
);
6939 g_error_free (gerror
);
6942 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6943 if (s
->length
> written
) {
6944 /* allocate the total length and copy the part of the string that has been converted */
6945 char *as2
= (char *)g_malloc0 (s
->length
);
6946 memcpy (as2
, as
, written
);
6955 * mono_string_to_utf8_ignore:
6958 * Converts a MonoString to its UTF8 representation. Will ignore
6959 * invalid surrogate pairs.
6960 * The resulting buffer should be freed with mono_free().
6964 mono_string_to_utf8_ignore (MonoString
*s
)
6966 MONO_REQ_GC_UNSAFE_MODE
;
6975 return g_strdup ("");
6977 as
= g_utf16_to_utf8 (mono_string_chars (s
), s
->length
, NULL
, &written
, NULL
);
6979 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6980 if (s
->length
> written
) {
6981 /* allocate the total length and copy the part of the string that has been converted */
6982 char *as2
= (char *)g_malloc0 (s
->length
);
6983 memcpy (as2
, as
, written
);
6992 * mono_string_to_utf8_image_ignore:
6993 * @s: a System.String
6995 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6998 mono_string_to_utf8_image_ignore (MonoImage
*image
, MonoString
*s
)
7000 MONO_REQ_GC_UNSAFE_MODE
;
7002 return mono_string_to_utf8_internal (NULL
, image
, s
, TRUE
, NULL
);
7006 * mono_string_to_utf8_mp_ignore:
7007 * @s: a System.String
7009 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7012 mono_string_to_utf8_mp_ignore (MonoMemPool
*mp
, MonoString
*s
)
7014 MONO_REQ_GC_UNSAFE_MODE
;
7016 return mono_string_to_utf8_internal (mp
, NULL
, s
, TRUE
, NULL
);
7021 * mono_string_to_utf16:
7024 * Return an null-terminated array of the utf-16 chars
7025 * contained in @s. The result must be freed with g_free().
7026 * This is a temporary helper until our string implementation
7027 * is reworked to always include the null terminating char.
7030 mono_string_to_utf16 (MonoString
*s
)
7032 MONO_REQ_GC_UNSAFE_MODE
;
7039 as
= (char *)g_malloc ((s
->length
* 2) + 2);
7040 as
[(s
->length
* 2)] = '\0';
7041 as
[(s
->length
* 2) + 1] = '\0';
7044 return (gunichar2
*)(as
);
7047 memcpy (as
, mono_string_chars(s
), s
->length
* 2);
7048 return (gunichar2
*)(as
);
7052 * mono_string_to_utf32:
7055 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7056 * contained in @s. The result must be freed with g_free().
7059 mono_string_to_utf32 (MonoString
*s
)
7061 MONO_REQ_GC_UNSAFE_MODE
;
7063 mono_unichar4
*utf32_output
= NULL
;
7064 GError
*error
= NULL
;
7065 glong items_written
;
7070 utf32_output
= g_utf16_to_ucs4 (s
->chars
, s
->length
, NULL
, &items_written
, &error
);
7073 g_error_free (error
);
7075 return utf32_output
;
7079 * mono_string_from_utf16:
7080 * @data: the UTF16 string (LPWSTR) to convert
7082 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7084 * Returns: a MonoString.
7087 mono_string_from_utf16 (gunichar2
*data
)
7090 MonoString
*result
= mono_string_from_utf16_checked (data
, &error
);
7091 mono_error_cleanup (&error
);
7096 * mono_string_from_utf16_checked:
7097 * @data: the UTF16 string (LPWSTR) to convert
7098 * @error: set on error
7100 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7102 * Returns: a MonoString. On failure sets @error and returns NULL.
7105 mono_string_from_utf16_checked (gunichar2
*data
, MonoError
*error
)
7108 MONO_REQ_GC_UNSAFE_MODE
;
7110 mono_error_init (error
);
7111 MonoDomain
*domain
= mono_domain_get ();
7117 while (data
[len
]) len
++;
7119 return mono_string_new_utf16_checked (domain
, data
, len
, error
);
7123 * mono_string_from_utf32:
7124 * @data: the UTF32 string (LPWSTR) to convert
7126 * Converts a UTF32 (UCS-4)to a MonoString.
7128 * Returns: a MonoString.
7131 mono_string_from_utf32 (mono_unichar4
*data
)
7134 MonoString
*result
= mono_string_from_utf32_checked (data
, &error
);
7135 mono_error_cleanup (&error
);
7140 * mono_string_from_utf32_checked:
7141 * @data: the UTF32 string (LPWSTR) to convert
7142 * @error: set on error
7144 * Converts a UTF32 (UCS-4)to a MonoString.
7146 * Returns: a MonoString. On failure returns NULL and sets @error.
7149 mono_string_from_utf32_checked (mono_unichar4
*data
, MonoError
*error
)
7151 MONO_REQ_GC_UNSAFE_MODE
;
7153 mono_error_init (error
);
7154 MonoString
* result
= NULL
;
7155 mono_unichar2
*utf16_output
= NULL
;
7156 GError
*gerror
= NULL
;
7157 glong items_written
;
7163 while (data
[len
]) len
++;
7165 utf16_output
= g_ucs4_to_utf16 (data
, len
, NULL
, &items_written
, &gerror
);
7168 g_error_free (gerror
);
7170 result
= mono_string_from_utf16_checked (utf16_output
, error
);
7171 g_free (utf16_output
);
7176 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, gboolean ignore_error
, MonoError
*error
)
7178 MONO_REQ_GC_UNSAFE_MODE
;
7185 r
= mono_string_to_utf8_ignore (s
);
7187 r
= mono_string_to_utf8_checked (s
, error
);
7188 if (!mono_error_ok (error
))
7195 len
= strlen (r
) + 1;
7197 mp_s
= (char *)mono_mempool_alloc (mp
, len
);
7199 mp_s
= (char *)mono_image_alloc (image
, len
);
7201 memcpy (mp_s
, r
, len
);
7209 * mono_string_to_utf8_image:
7210 * @s: a System.String
7212 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7215 mono_string_to_utf8_image (MonoImage
*image
, MonoString
*s
, MonoError
*error
)
7217 MONO_REQ_GC_UNSAFE_MODE
;
7219 return mono_string_to_utf8_internal (NULL
, image
, s
, FALSE
, error
);
7223 * mono_string_to_utf8_mp:
7224 * @s: a System.String
7226 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7229 mono_string_to_utf8_mp (MonoMemPool
*mp
, MonoString
*s
, MonoError
*error
)
7231 MONO_REQ_GC_UNSAFE_MODE
;
7233 return mono_string_to_utf8_internal (mp
, NULL
, s
, FALSE
, error
);
7237 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks
;
7240 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks
*cbs
)
7242 eh_callbacks
= *cbs
;
7245 MonoRuntimeExceptionHandlingCallbacks
*
7246 mono_get_eh_callbacks (void)
7248 return &eh_callbacks
;
7252 * mono_raise_exception:
7253 * @ex: exception object
7255 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7258 mono_raise_exception (MonoException
*ex
)
7260 MONO_REQ_GC_UNSAFE_MODE
;
7263 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7264 * that will cause gcc to omit the function epilog, causing problems when
7265 * the JIT tries to walk the stack, since the return address on the stack
7266 * will point into the next function in the executable, not this one.
7268 eh_callbacks
.mono_raise_exception (ex
);
7272 mono_raise_exception_with_context (MonoException
*ex
, MonoContext
*ctx
)
7274 MONO_REQ_GC_UNSAFE_MODE
;
7276 eh_callbacks
.mono_raise_exception_with_ctx (ex
, ctx
);
7280 * mono_wait_handle_new:
7281 * @domain: Domain where the object will be created
7282 * @handle: Handle for the wait handle
7283 * @error: set on error.
7285 * Returns: A new MonoWaitHandle created in the given domain for the
7286 * given handle. On failure returns NULL and sets @rror.
7289 mono_wait_handle_new (MonoDomain
*domain
, HANDLE handle
, MonoError
*error
)
7291 MONO_REQ_GC_UNSAFE_MODE
;
7293 MonoWaitHandle
*res
;
7294 gpointer params
[1];
7295 static MonoMethod
*handle_set
;
7297 mono_error_init (error
);
7298 res
= (MonoWaitHandle
*)mono_object_new_checked (domain
, mono_defaults
.manualresetevent_class
, error
);
7299 return_val_if_nok (error
, NULL
);
7301 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7303 handle_set
= mono_class_get_property_from_name (mono_defaults
.manualresetevent_class
, "Handle")->set
;
7305 params
[0] = &handle
;
7307 mono_runtime_invoke_checked (handle_set
, res
, params
, error
);
7312 mono_wait_handle_get_handle (MonoWaitHandle
*handle
)
7314 MONO_REQ_GC_UNSAFE_MODE
;
7316 static MonoClassField
*f_safe_handle
= NULL
;
7319 if (!f_safe_handle
) {
7320 f_safe_handle
= mono_class_get_field_from_name (mono_defaults
.manualresetevent_class
, "safeWaitHandle");
7321 g_assert (f_safe_handle
);
7324 mono_field_get_value ((MonoObject
*)handle
, f_safe_handle
, &sh
);
7330 mono_runtime_capture_context (MonoDomain
*domain
, MonoError
*error
)
7332 MONO_REQ_GC_UNSAFE_MODE
;
7334 RuntimeInvokeFunction runtime_invoke
;
7336 mono_error_init (error
);
7338 if (!domain
->capture_context_runtime_invoke
|| !domain
->capture_context_method
) {
7339 MonoMethod
*method
= mono_get_context_capture_method ();
7340 MonoMethod
*wrapper
;
7343 wrapper
= mono_marshal_get_runtime_invoke (method
, FALSE
);
7344 domain
->capture_context_runtime_invoke
= mono_compile_method_checked (wrapper
, error
);
7345 return_val_if_nok (error
, NULL
);
7346 domain
->capture_context_method
= mono_compile_method_checked (method
, error
);
7347 return_val_if_nok (error
, NULL
);
7350 runtime_invoke
= (RuntimeInvokeFunction
)domain
->capture_context_runtime_invoke
;
7352 return runtime_invoke (NULL
, NULL
, NULL
, domain
->capture_context_method
);
7355 * mono_async_result_new:
7356 * @domain:domain where the object will be created.
7357 * @handle: wait handle.
7358 * @state: state to pass to AsyncResult
7359 * @data: C closure data.
7360 * @error: set on error.
7362 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7363 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7364 * On failure returns NULL and sets @error.
7368 mono_async_result_new (MonoDomain
*domain
, HANDLE handle
, MonoObject
*state
, gpointer data
, MonoObject
*object_data
, MonoError
*error
)
7370 MONO_REQ_GC_UNSAFE_MODE
;
7372 mono_error_init (error
);
7373 MonoAsyncResult
*res
= (MonoAsyncResult
*)mono_object_new_checked (domain
, mono_defaults
.asyncresult_class
, error
);
7374 return_val_if_nok (error
, NULL
);
7375 MonoObject
*context
= mono_runtime_capture_context (domain
, error
);
7376 return_val_if_nok (error
, NULL
);
7377 /* we must capture the execution context from the original thread */
7379 MONO_OBJECT_SETREF (res
, execution_context
, context
);
7380 /* note: result may be null if the flow is suppressed */
7383 res
->data
= (void **)data
;
7384 MONO_OBJECT_SETREF (res
, object_data
, object_data
);
7385 MONO_OBJECT_SETREF (res
, async_state
, state
);
7386 MonoWaitHandle
*wait_handle
= mono_wait_handle_new (domain
, handle
, error
);
7387 return_val_if_nok (error
, NULL
);
7389 MONO_OBJECT_SETREF (res
, handle
, (MonoObject
*) wait_handle
);
7391 res
->sync_completed
= FALSE
;
7392 res
->completed
= FALSE
;
7398 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult
*ares
)
7400 MONO_REQ_GC_UNSAFE_MODE
;
7407 g_assert (ares
->async_delegate
);
7409 ac
= (MonoAsyncCall
*) ares
->object_data
;
7411 res
= mono_runtime_delegate_invoke_checked (ares
->async_delegate
, (void**) &ares
->async_state
, &error
);
7412 if (mono_error_set_pending_exception (&error
))
7415 gpointer wait_event
= NULL
;
7417 ac
->msg
->exc
= NULL
;
7419 res
= mono_message_invoke (ares
->async_delegate
, ac
->msg
, &ac
->msg
->exc
, &ac
->out_args
, &error
);
7421 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7422 mono_threads_begin_abort_protected_block ();
7424 if (!ac
->msg
->exc
) {
7425 MonoException
*ex
= mono_error_convert_to_exception (&error
);
7426 ac
->msg
->exc
= (MonoObject
*)ex
;
7428 mono_error_cleanup (&error
);
7431 MONO_OBJECT_SETREF (ac
, res
, res
);
7433 mono_monitor_enter ((MonoObject
*) ares
);
7434 ares
->completed
= 1;
7436 wait_event
= mono_wait_handle_get_handle ((MonoWaitHandle
*) ares
->handle
);
7437 mono_monitor_exit ((MonoObject
*) ares
);
7439 if (wait_event
!= NULL
)
7440 mono_w32event_set (wait_event
);
7442 mono_error_init (&error
); //the else branch would leave it in an undefined state
7444 mono_runtime_invoke_checked (ac
->cb_method
, ac
->cb_target
, (gpointer
*) &ares
, &error
);
7446 mono_threads_end_abort_protected_block ();
7448 if (mono_error_set_pending_exception (&error
))
7456 mono_message_init (MonoDomain
*domain
,
7457 MonoMethodMessage
*this_obj
,
7458 MonoReflectionMethod
*method
,
7459 MonoArray
*out_args
,
7462 MONO_REQ_GC_UNSAFE_MODE
;
7464 static MonoMethod
*init_message_method
= NULL
;
7466 if (!init_message_method
) {
7467 init_message_method
= mono_class_get_method_from_name (mono_defaults
.mono_method_message_class
, "InitMessage", 2);
7468 g_assert (init_message_method
!= NULL
);
7471 mono_error_init (error
);
7472 /* FIXME set domain instead? */
7473 g_assert (domain
== mono_domain_get ());
7480 mono_runtime_invoke_checked (init_message_method
, this_obj
, args
, error
);
7481 return is_ok (error
);
7484 #ifndef DISABLE_REMOTING
7486 * mono_remoting_invoke:
7487 * @real_proxy: pointer to a RealProxy object
7488 * @msg: The MonoMethodMessage to execute
7489 * @exc: used to store exceptions
7490 * @out_args: used to store output arguments
7492 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7493 * IMessage interface and it is not trivial to extract results from there. So
7494 * we call an helper method PrivateInvoke instead of calling
7495 * RealProxy::Invoke() directly.
7497 * Returns: the result object.
7500 mono_remoting_invoke (MonoObject
*real_proxy
, MonoMethodMessage
*msg
, MonoObject
**exc
, MonoArray
**out_args
, MonoError
*error
)
7502 MONO_REQ_GC_UNSAFE_MODE
;
7505 MonoMethod
*im
= real_proxy
->vtable
->domain
->private_invoke_method
;
7510 mono_error_init (error
);
7512 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7515 im
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "PrivateInvoke", 4);
7517 mono_error_set_not_supported (error
, "Linked away.");
7520 real_proxy
->vtable
->domain
->private_invoke_method
= im
;
7523 pa
[0] = real_proxy
;
7528 o
= mono_runtime_try_invoke (im
, NULL
, pa
, exc
, error
);
7529 return_val_if_nok (error
, NULL
);
7536 mono_message_invoke (MonoObject
*target
, MonoMethodMessage
*msg
,
7537 MonoObject
**exc
, MonoArray
**out_args
, MonoError
*error
)
7539 MONO_REQ_GC_UNSAFE_MODE
;
7541 static MonoClass
*object_array_klass
;
7542 mono_error_init (error
);
7546 MonoMethodSignature
*sig
;
7548 int i
, j
, outarg_count
= 0;
7550 #ifndef DISABLE_REMOTING
7551 if (target
&& mono_object_is_transparent_proxy (target
)) {
7552 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)target
;
7553 if (mono_class_is_contextbound (tp
->remote_class
->proxy_class
) && tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
7554 target
= tp
->rp
->unwrapped_server
;
7556 return mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, exc
, out_args
, error
);
7561 domain
= mono_domain_get ();
7562 method
= msg
->method
->method
;
7563 sig
= mono_method_signature (method
);
7565 for (i
= 0; i
< sig
->param_count
; i
++) {
7566 if (sig
->params
[i
]->byref
)
7570 if (!object_array_klass
) {
7573 klass
= mono_array_class_get (mono_defaults
.object_class
, 1);
7576 mono_memory_barrier ();
7577 object_array_klass
= klass
;
7580 arr
= mono_array_new_specific_checked (mono_class_vtable (domain
, object_array_klass
), outarg_count
, error
);
7581 return_val_if_nok (error
, NULL
);
7583 mono_gc_wbarrier_generic_store (out_args
, (MonoObject
*) arr
);
7586 MonoObject
*ret
= mono_runtime_try_invoke_array (method
, method
->klass
->valuetype
? mono_object_unbox (target
): target
, msg
->args
, exc
, error
);
7587 return_val_if_nok (error
, NULL
);
7589 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
7590 if (sig
->params
[i
]->byref
) {
7592 arg
= (MonoObject
*)mono_array_get (msg
->args
, gpointer
, i
);
7593 mono_array_setref (*out_args
, j
, arg
);
7602 * prepare_to_string_method:
7604 * @target: Set to @obj or unboxed value if a valuetype
7606 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7609 prepare_to_string_method (MonoObject
*obj
, void **target
)
7611 MONO_REQ_GC_UNSAFE_MODE
;
7613 static MonoMethod
*to_string
= NULL
;
7621 to_string
= mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL
| METHOD_ATTRIBUTE_PUBLIC
);
7623 method
= mono_object_get_virtual_method (obj
, to_string
);
7625 // Unbox value type if needed
7626 if (mono_class_is_valuetype (mono_method_get_class (method
))) {
7627 *target
= mono_object_unbox (obj
);
7633 * mono_object_to_string:
7635 * @exc: Any exception thrown by ToString (). May be NULL.
7637 * Returns: the result of calling ToString () on an object.
7640 mono_object_to_string (MonoObject
*obj
, MonoObject
**exc
)
7643 MonoString
*s
= NULL
;
7645 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
7647 s
= (MonoString
*) mono_runtime_try_invoke (method
, target
, NULL
, exc
, &error
);
7648 if (*exc
== NULL
&& !mono_error_ok (&error
))
7649 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
7651 mono_error_cleanup (&error
);
7653 s
= (MonoString
*) mono_runtime_invoke_checked (method
, target
, NULL
, &error
);
7654 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
7661 * mono_object_to_string_checked:
7663 * @error: Set on error.
7665 * Returns: the result of calling ToString () on an object. If the
7666 * method cannot be invoked or if it raises an exception, sets @error
7670 mono_object_to_string_checked (MonoObject
*obj
, MonoError
*error
)
7672 mono_error_init (error
);
7674 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
7675 return (MonoString
*) mono_runtime_invoke_checked (method
, target
, NULL
, error
);
7679 * mono_object_try_to_string:
7681 * @exc: Any exception thrown by ToString (). Must not be NULL.
7682 * @error: Set if method cannot be invoked.
7684 * Returns: the result of calling ToString () on an object. If the
7685 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7689 mono_object_try_to_string (MonoObject
*obj
, MonoObject
**exc
, MonoError
*error
)
7692 mono_error_init (error
);
7694 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
7695 return (MonoString
*) mono_runtime_try_invoke (method
, target
, NULL
, exc
, error
);
7701 * mono_print_unhandled_exception:
7702 * @exc: The exception
7704 * Prints the unhandled exception.
7707 mono_print_unhandled_exception (MonoObject
*exc
)
7709 MONO_REQ_GC_UNSAFE_MODE
;
7712 char *message
= (char*)"";
7713 gboolean free_message
= FALSE
;
7716 if (exc
== (MonoObject
*)mono_object_domain (exc
)->out_of_memory_ex
) {
7717 message
= g_strdup ("OutOfMemoryException");
7718 free_message
= TRUE
;
7719 } else if (exc
== (MonoObject
*)mono_object_domain (exc
)->stack_overflow_ex
) {
7720 message
= g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7721 free_message
= TRUE
;
7724 if (((MonoException
*)exc
)->native_trace_ips
) {
7725 message
= mono_exception_get_native_backtrace ((MonoException
*)exc
);
7726 free_message
= TRUE
;
7728 MonoObject
*other_exc
= NULL
;
7729 str
= mono_object_try_to_string (exc
, &other_exc
, &error
);
7730 if (other_exc
== NULL
&& !is_ok (&error
))
7731 other_exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
7733 mono_error_cleanup (&error
);
7735 char *original_backtrace
= mono_exception_get_managed_backtrace ((MonoException
*)exc
);
7736 char *nested_backtrace
= mono_exception_get_managed_backtrace ((MonoException
*)other_exc
);
7738 message
= g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7739 original_backtrace
, nested_backtrace
);
7741 g_free (original_backtrace
);
7742 g_free (nested_backtrace
);
7743 free_message
= TRUE
;
7745 message
= mono_string_to_utf8_checked (str
, &error
);
7746 if (!mono_error_ok (&error
)) {
7747 mono_error_cleanup (&error
);
7748 message
= (char *) "";
7750 free_message
= TRUE
;
7757 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7758 * exc->vtable->klass->name, message);
7760 g_printerr ("\nUnhandled Exception:\n%s\n", message
);
7767 * mono_delegate_ctor_with_method:
7768 * @this: pointer to an uninitialized delegate object
7769 * @target: target object
7770 * @addr: pointer to native code
7772 * @error: set on error.
7774 * Initialize a delegate and sets a specific method, not the one
7775 * associated with addr. This is useful when sharing generic code.
7776 * In that case addr will most probably not be associated with the
7777 * correct instantiation of the method.
7778 * On failure returns FALSE and sets @error.
7781 mono_delegate_ctor_with_method (MonoObject
*this_obj
, MonoObject
*target
, gpointer addr
, MonoMethod
*method
, MonoError
*error
)
7783 MONO_REQ_GC_UNSAFE_MODE
;
7785 mono_error_init (error
);
7786 MonoDelegate
*delegate
= (MonoDelegate
*)this_obj
;
7788 g_assert (this_obj
);
7791 g_assert (mono_class_has_parent (mono_object_class (this_obj
), mono_defaults
.multicastdelegate_class
));
7794 delegate
->method
= method
;
7796 mono_stats
.delegate_creations
++;
7798 #ifndef DISABLE_REMOTING
7799 if (target
&& target
->vtable
->klass
== mono_defaults
.transparent_proxy_class
) {
7801 method
= mono_marshal_get_remoting_invoke (method
);
7802 delegate
->method_ptr
= mono_compile_method_checked (method
, error
);
7803 return_val_if_nok (error
, FALSE
);
7804 MONO_OBJECT_SETREF (delegate
, target
, target
);
7808 delegate
->method_ptr
= addr
;
7809 MONO_OBJECT_SETREF (delegate
, target
, target
);
7812 delegate
->invoke_impl
= arch_create_delegate_trampoline (delegate
->object
.vtable
->domain
, delegate
->object
.vtable
->klass
);
7813 if (callbacks
.init_delegate
)
7814 callbacks
.init_delegate (delegate
);
7819 * mono_delegate_ctor:
7820 * @this: pointer to an uninitialized delegate object
7821 * @target: target object
7822 * @addr: pointer to native code
7823 * @error: set on error.
7825 * This is used to initialize a delegate.
7826 * On failure returns FALSE and sets @error.
7829 mono_delegate_ctor (MonoObject
*this_obj
, MonoObject
*target
, gpointer addr
, MonoError
*error
)
7831 MONO_REQ_GC_UNSAFE_MODE
;
7833 mono_error_init (error
);
7834 MonoDomain
*domain
= mono_domain_get ();
7836 MonoMethod
*method
= NULL
;
7840 ji
= mono_jit_info_table_find (domain
, (char *)mono_get_addr_from_ftnptr (addr
));
7842 if (!ji
&& domain
!= mono_get_root_domain ())
7843 ji
= mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr
));
7845 method
= mono_jit_info_get_method (ji
);
7846 g_assert (!method
->klass
->generic_container
);
7849 return mono_delegate_ctor_with_method (this_obj
, target
, addr
, method
, error
);
7853 * mono_method_call_message_new:
7854 * @method: method to encapsulate
7855 * @params: parameters to the method
7856 * @invoke: optional, delegate invoke.
7857 * @cb: async callback delegate.
7858 * @state: state passed to the async callback.
7859 * @error: set on error.
7861 * Translates arguments pointers into a MonoMethodMessage.
7862 * On failure returns NULL and sets @error.
7865 mono_method_call_message_new (MonoMethod
*method
, gpointer
*params
, MonoMethod
*invoke
,
7866 MonoDelegate
**cb
, MonoObject
**state
, MonoError
*error
)
7868 MONO_REQ_GC_UNSAFE_MODE
;
7870 mono_error_init (error
);
7872 MonoDomain
*domain
= mono_domain_get ();
7873 MonoMethodSignature
*sig
= mono_method_signature (method
);
7874 MonoMethodMessage
*msg
;
7877 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
7878 return_val_if_nok (error
, NULL
);
7881 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, invoke
, NULL
, error
);
7882 return_val_if_nok (error
, NULL
);
7883 mono_message_init (domain
, msg
, rm
, NULL
, error
);
7884 return_val_if_nok (error
, NULL
);
7885 count
= sig
->param_count
- 2;
7887 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
7888 return_val_if_nok (error
, NULL
);
7889 mono_message_init (domain
, msg
, rm
, NULL
, error
);
7890 return_val_if_nok (error
, NULL
);
7891 count
= sig
->param_count
;
7894 for (i
= 0; i
< count
; i
++) {
7899 if (sig
->params
[i
]->byref
)
7900 vpos
= *((gpointer
*)params
[i
]);
7904 klass
= mono_class_from_mono_type (sig
->params
[i
]);
7906 if (klass
->valuetype
) {
7907 arg
= mono_value_box_checked (domain
, klass
, vpos
, error
);
7908 return_val_if_nok (error
, NULL
);
7910 arg
= *((MonoObject
**)vpos
);
7912 mono_array_setref (msg
->args
, i
, arg
);
7915 if (cb
!= NULL
&& state
!= NULL
) {
7916 *cb
= *((MonoDelegate
**)params
[i
]);
7918 *state
= *((MonoObject
**)params
[i
]);
7925 * mono_method_return_message_restore:
7927 * Restore results from message based processing back to arguments pointers
7930 mono_method_return_message_restore (MonoMethod
*method
, gpointer
*params
, MonoArray
*out_args
, MonoError
*error
)
7932 MONO_REQ_GC_UNSAFE_MODE
;
7934 mono_error_init (error
);
7936 MonoMethodSignature
*sig
= mono_method_signature (method
);
7937 int i
, j
, type
, size
, out_len
;
7939 if (out_args
== NULL
)
7941 out_len
= mono_array_length (out_args
);
7945 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
7946 MonoType
*pt
= sig
->params
[i
];
7951 mono_error_set_execution_engine (error
, "The proxy call returned an incorrect number of output arguments");
7955 arg
= (char *)mono_array_get (out_args
, gpointer
, j
);
7958 g_assert (type
!= MONO_TYPE_VOID
);
7960 if (MONO_TYPE_IS_REFERENCE (pt
)) {
7961 mono_gc_wbarrier_generic_store (*((MonoObject
***)params
[i
]), (MonoObject
*)arg
);
7964 MonoClass
*klass
= ((MonoObject
*)arg
)->vtable
->klass
;
7965 size
= mono_class_value_size (klass
, NULL
);
7966 if (klass
->has_references
)
7967 mono_gc_wbarrier_value_copy (*((gpointer
*)params
[i
]), arg
+ sizeof (MonoObject
), 1, klass
);
7969 mono_gc_memmove_atomic (*((gpointer
*)params
[i
]), arg
+ sizeof (MonoObject
), size
);
7971 size
= mono_class_value_size (mono_class_from_mono_type (pt
), NULL
);
7972 mono_gc_bzero_atomic (*((gpointer
*)params
[i
]), size
);
7981 #ifndef DISABLE_REMOTING
7984 * mono_load_remote_field:
7985 * @this: pointer to an object
7986 * @klass: klass of the object containing @field
7987 * @field: the field to load
7988 * @res: a storage to store the result
7990 * This method is called by the runtime on attempts to load fields of
7991 * transparent proxy objects. @this points to such TP, @klass is the class of
7992 * the object containing @field. @res is a storage location which can be
7993 * used to store the result.
7995 * Returns: an address pointing to the value of field.
7998 mono_load_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
)
8001 gpointer result
= mono_load_remote_field_checked (this_obj
, klass
, field
, res
, &error
);
8002 mono_error_cleanup (&error
);
8007 * mono_load_remote_field_checked:
8008 * @this: pointer to an object
8009 * @klass: klass of the object containing @field
8010 * @field: the field to load
8011 * @res: a storage to store the result
8012 * @error: set on error
8014 * This method is called by the runtime on attempts to load fields of
8015 * transparent proxy objects. @this points to such TP, @klass is the class of
8016 * the object containing @field. @res is a storage location which can be
8017 * used to store the result.
8019 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8022 mono_load_remote_field_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
, MonoError
*error
)
8024 MONO_REQ_GC_UNSAFE_MODE
;
8026 static MonoMethod
*getter
= NULL
;
8028 mono_error_init (error
);
8030 MonoDomain
*domain
= mono_domain_get ();
8031 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this_obj
;
8032 MonoClass
*field_class
;
8033 MonoMethodMessage
*msg
;
8034 MonoArray
*out_args
;
8038 g_assert (mono_object_is_transparent_proxy (this_obj
));
8039 g_assert (res
!= NULL
);
8041 if (mono_class_is_contextbound (tp
->remote_class
->proxy_class
) && tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
8042 mono_field_get_value (tp
->rp
->unwrapped_server
, field
, res
);
8047 getter
= mono_class_get_method_from_name (mono_defaults
.object_class
, "FieldGetter", -1);
8049 mono_error_set_not_supported (error
, "Linked away.");
8054 field_class
= mono_class_from_mono_type (field
->type
);
8056 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
8057 return_val_if_nok (error
, NULL
);
8058 out_args
= mono_array_new_checked (domain
, mono_defaults
.object_class
, 1, error
);
8059 return_val_if_nok (error
, NULL
);
8060 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, getter
, NULL
, error
);
8061 return_val_if_nok (error
, NULL
);
8062 mono_message_init (domain
, msg
, rm
, out_args
, error
);
8063 return_val_if_nok (error
, NULL
);
8065 full_name
= mono_type_get_full_name (klass
);
8066 mono_array_setref (msg
->args
, 0, mono_string_new (domain
, full_name
));
8067 mono_array_setref (msg
->args
, 1, mono_string_new (domain
, mono_field_get_name (field
)));
8070 mono_remoting_invoke ((MonoObject
*)(tp
->rp
), msg
, &exc
, &out_args
, error
);
8071 return_val_if_nok (error
, NULL
);
8074 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
8078 if (mono_array_length (out_args
) == 0)
8081 mono_gc_wbarrier_generic_store (res
, mono_array_get (out_args
, MonoObject
*, 0));
8083 if (field_class
->valuetype
) {
8084 return ((char *)*res
) + sizeof (MonoObject
);
8090 * mono_load_remote_field_new:
8095 * Missing documentation.
8098 mono_load_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
)
8102 MonoObject
*result
= mono_load_remote_field_new_checked (this_obj
, klass
, field
, &error
);
8103 mono_error_cleanup (&error
);
8108 * mono_load_remote_field_new_checked:
8109 * @this: pointer to an object
8110 * @klass: klass of the object containing @field
8111 * @field: the field to load
8112 * @error: set on error.
8114 * This method is called by the runtime on attempts to load fields of
8115 * transparent proxy objects. @this points to such TP, @klass is the class of
8116 * the object containing @field.
8118 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8121 mono_load_remote_field_new_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoError
*error
)
8123 MONO_REQ_GC_UNSAFE_MODE
;
8125 mono_error_init (error
);
8127 static MonoMethod
*tp_load
= NULL
;
8129 g_assert (mono_object_is_transparent_proxy (this_obj
));
8132 tp_load
= mono_class_get_method_from_name (mono_defaults
.transparent_proxy_class
, "LoadRemoteFieldNew", -1);
8134 mono_error_set_not_supported (error
, "Linked away.");
8139 /* MonoType *type = mono_class_get_type (klass); */
8145 return mono_runtime_invoke_checked (tp_load
, this_obj
, args
, error
);
8149 * mono_store_remote_field:
8150 * @this_obj: pointer to an object
8151 * @klass: klass of the object containing @field
8152 * @field: the field to load
8153 * @val: the value/object to store
8155 * This method is called by the runtime on attempts to store fields of
8156 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8157 * the object containing @field. @val is the new value to store in @field.
8160 mono_store_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
)
8163 (void) mono_store_remote_field_checked (this_obj
, klass
, field
, val
, &error
);
8164 mono_error_cleanup (&error
);
8168 * mono_store_remote_field_checked:
8169 * @this_obj: pointer to an object
8170 * @klass: klass of the object containing @field
8171 * @field: the field to load
8172 * @val: the value/object to store
8173 * @error: set on error
8175 * This method is called by the runtime on attempts to store fields of
8176 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8177 * the object containing @field. @val is the new value to store in @field.
8179 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8182 mono_store_remote_field_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
, MonoError
*error
)
8185 MONO_REQ_GC_UNSAFE_MODE
;
8187 mono_error_init (error
);
8189 MonoDomain
*domain
= mono_domain_get ();
8190 MonoClass
*field_class
;
8193 g_assert (mono_object_is_transparent_proxy (this_obj
));
8195 field_class
= mono_class_from_mono_type (field
->type
);
8197 if (field_class
->valuetype
) {
8198 arg
= mono_value_box_checked (domain
, field_class
, val
, error
);
8199 return_val_if_nok (error
, FALSE
);
8201 arg
= *((MonoObject
**)val
);
8204 return mono_store_remote_field_new_checked (this_obj
, klass
, field
, arg
, error
);
8208 * mono_store_remote_field_new:
8214 * Missing documentation
8217 mono_store_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
)
8220 (void) mono_store_remote_field_new_checked (this_obj
, klass
, field
, arg
, &error
);
8221 mono_error_cleanup (&error
);
8225 * mono_store_remote_field_new_checked:
8232 * Missing documentation
8235 mono_store_remote_field_new_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
, MonoError
*error
)
8237 MONO_REQ_GC_UNSAFE_MODE
;
8239 static MonoMethod
*tp_store
= NULL
;
8241 mono_error_init (error
);
8243 g_assert (mono_object_is_transparent_proxy (this_obj
));
8246 tp_store
= mono_class_get_method_from_name (mono_defaults
.transparent_proxy_class
, "StoreRemoteField", -1);
8248 mono_error_set_not_supported (error
, "Linked away.");
8258 mono_runtime_invoke_checked (tp_store
, this_obj
, args
, error
);
8259 return is_ok (error
);
8264 * mono_create_ftnptr:
8266 * Given a function address, create a function descriptor for it.
8267 * This is only needed on some platforms.
8270 mono_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
8272 return callbacks
.create_ftnptr (domain
, addr
);
8276 * mono_get_addr_from_ftnptr:
8278 * Given a pointer to a function descriptor, return the function address.
8279 * This is only needed on some platforms.
8282 mono_get_addr_from_ftnptr (gpointer descr
)
8284 return callbacks
.get_addr_from_ftnptr (descr
);
8288 * mono_string_chars:
8291 * Returns a pointer to the UCS16 characters stored in the MonoString
8294 mono_string_chars (MonoString
*s
)
8296 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8302 * mono_string_length:
8305 * Returns the lenght in characters of the string
8308 mono_string_length (MonoString
*s
)
8310 MONO_REQ_GC_UNSAFE_MODE
;
8316 * mono_array_length:
8317 * @array: a MonoArray*
8319 * Returns the total number of elements in the array. This works for
8320 * both vectors and multidimensional arrays.
8323 mono_array_length (MonoArray
*array
)
8325 MONO_REQ_GC_UNSAFE_MODE
;
8327 return array
->max_length
;
8331 * mono_array_addr_with_size:
8332 * @array: a MonoArray*
8333 * @size: size of the array elements
8334 * @idx: index into the array
8336 * Use this function to obtain the address for the @idx item on the
8337 * @array containing elements of size @size.
8339 * This method performs no bounds checking or type checking.
8341 * Returns the address of the @idx element in the array.
8344 mono_array_addr_with_size (MonoArray
*array
, int size
, uintptr_t idx
)
8346 MONO_REQ_GC_UNSAFE_MODE
;
8348 return ((char*)(array
)->vector
) + size
* idx
;
8353 mono_glist_to_array (GList
*list
, MonoClass
*eclass
, MonoError
*error
)
8355 MonoDomain
*domain
= mono_domain_get ();
8359 mono_error_init (error
);
8363 len
= g_list_length (list
);
8364 res
= mono_array_new_checked (domain
, eclass
, len
, error
);
8365 return_val_if_nok (error
, NULL
);
8367 for (i
= 0; list
; list
= list
->next
, i
++)
8368 mono_array_set (res
, gpointer
, i
, list
->data
);
8375 * The following section is purely to declare prototypes and
8376 * document the API, as these C files are processed by our
8382 * @array: array to alter
8383 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8384 * @index: index into the array
8385 * @value: value to set
8387 * Value Type version: This sets the @index's element of the @array
8388 * with elements of size sizeof(type) to the provided @value.
8390 * This macro does not attempt to perform type checking or bounds checking.
8392 * Use this to set value types in a `MonoArray`.
8394 void mono_array_set(MonoArray
*array
, Type element_type
, uintptr_t index
, Value value
)
8399 * mono_array_setref:
8400 * @array: array to alter
8401 * @index: index into the array
8402 * @value: value to set
8404 * Reference Type version: This sets the @index's element of the
8405 * @array with elements of size sizeof(type) to the provided @value.
8407 * This macro does not attempt to perform type checking or bounds checking.
8409 * Use this to reference types in a `MonoArray`.
8411 void mono_array_setref(MonoArray
*array
, uintptr_t index
, MonoObject
*object
)
8417 * @array: array on which to operate on
8418 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8419 * @index: index into the array
8421 * Use this macro to retrieve the @index element of an @array and
8422 * extract the value assuming that the elements of the array match
8423 * the provided type value.
8425 * This method can be used with both arrays holding value types and
8426 * reference types. For reference types, the @type parameter should
8427 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8429 * This macro does not attempt to perform type checking or bounds checking.
8431 * Returns: The element at the @index position in the @array.
8433 Type
mono_array_get (MonoArray
*array
, Type element_type
, uintptr_t index
)