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"
53 #include <mono/io-layer/io-layer.h>
56 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
, MonoError
*error
);
59 mono_ldstr_metadata_sig (MonoDomain
*domain
, const char* sig
, MonoError
*error
);
62 free_main_args (void);
65 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, gboolean ignore_error
, MonoError
*error
);
67 /* Class lazy loading functions */
68 static GENERATE_GET_CLASS_WITH_CACHE (pointer
, System
.Reflection
, Pointer
)
69 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services
, System
.Runtime
.Remoting
, RemotingServices
)
70 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args
, System
, UnhandledExceptionEventArgs
)
71 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute
, System
, STAThreadAttribute
)
72 static GENERATE_GET_CLASS_WITH_CACHE (activation_services
, System
.Runtime
.Remoting
.Activation
, ActivationServices
)
75 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
76 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
77 static mono_mutex_t ldstr_section
;
81 * mono_runtime_object_init:
82 * @this_obj: the object to initialize
84 * This function calls the zero-argument constructor (which must
85 * exist) for the given object.
88 mono_runtime_object_init (MonoObject
*this_obj
)
91 mono_runtime_object_init_checked (this_obj
, &error
);
92 mono_error_assert_ok (&error
);
96 * mono_runtime_object_init_checked:
97 * @this_obj: the object to initialize
98 * @error: set on error.
100 * This function calls the zero-argument constructor (which must
101 * exist) for the given object and returns TRUE on success, or FALSE
102 * on error and sets @error.
105 mono_runtime_object_init_checked (MonoObject
*this_obj
, MonoError
*error
)
107 MONO_REQ_GC_UNSAFE_MODE
;
109 MonoMethod
*method
= NULL
;
110 MonoClass
*klass
= this_obj
->vtable
->klass
;
112 mono_error_init (error
);
113 method
= mono_class_get_method_from_name (klass
, ".ctor", 0);
115 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass
));
117 if (method
->klass
->valuetype
)
118 this_obj
= (MonoObject
*)mono_object_unbox (this_obj
);
120 mono_runtime_invoke_checked (method
, this_obj
, NULL
, error
);
121 return is_ok (error
);
124 /* The pseudo algorithm for type initialization from the spec
125 Note it doesn't say anything about domains - only threads.
127 2. If the type is initialized you are done.
128 2.1. If the type is not yet initialized, try to take an
130 2.2. If successful, record this thread as responsible for
131 initializing the type and proceed to step 2.3.
132 2.2.1. If not, see whether this thread or any thread
133 waiting for this thread to complete already holds the lock.
134 2.2.2. If so, return since blocking would create a deadlock. This thread
135 will now see an incompletely initialized state for the type,
136 but no deadlock will arise.
137 2.2.3 If not, block until the type is initialized then return.
138 2.3 Initialize the parent type and then all interfaces implemented
140 2.4 Execute the type initialization code for this type.
141 2.5 Mark the type as initialized, release the initialization lock,
142 awaken any threads waiting for this type to be initialized,
149 MonoNativeThreadId initializing_tid
;
150 guint32 waiting_count
;
152 MonoCoopMutex initialization_section
;
153 } TypeInitializationLock
;
155 /* for locking access to type_initialization_hash and blocked_thread_hash */
156 static MonoCoopMutex type_initialization_section
;
159 mono_type_initialization_lock (void)
161 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
162 mono_coop_mutex_lock (&type_initialization_section
);
166 mono_type_initialization_unlock (void)
168 mono_coop_mutex_unlock (&type_initialization_section
);
172 mono_type_init_lock (TypeInitializationLock
*lock
)
174 MONO_REQ_GC_NEUTRAL_MODE
;
176 mono_coop_mutex_lock (&lock
->initialization_section
);
180 mono_type_init_unlock (TypeInitializationLock
*lock
)
182 mono_coop_mutex_unlock (&lock
->initialization_section
);
185 /* from vtable to lock */
186 static GHashTable
*type_initialization_hash
;
188 /* from thread id to thread id being waited on */
189 static GHashTable
*blocked_thread_hash
;
192 static MonoThread
*main_thread
;
194 /* Functions supplied by the runtime */
195 static MonoRuntimeCallbacks callbacks
;
198 * mono_thread_set_main:
199 * @thread: thread to set as the main thread
201 * This function can be used to instruct the runtime to treat @thread
202 * as the main thread, ie, the thread that would normally execute the Main()
203 * method. This basically means that at the end of @thread, the runtime will
204 * wait for the existing foreground threads to quit and other such details.
207 mono_thread_set_main (MonoThread
*thread
)
209 MONO_REQ_GC_UNSAFE_MODE
;
211 static gboolean registered
= FALSE
;
214 MONO_GC_REGISTER_ROOT_SINGLE (main_thread
, MONO_ROOT_SOURCE_THREADING
, "main thread object");
218 main_thread
= thread
;
222 mono_thread_get_main (void)
224 MONO_REQ_GC_UNSAFE_MODE
;
230 mono_type_initialization_init (void)
232 mono_coop_mutex_init_recursive (&type_initialization_section
);
233 type_initialization_hash
= g_hash_table_new (NULL
, NULL
);
234 blocked_thread_hash
= g_hash_table_new (NULL
, NULL
);
235 mono_os_mutex_init_recursive (&ldstr_section
);
239 mono_type_initialization_cleanup (void)
242 /* This is causing race conditions with
243 * mono_release_type_locks
245 mono_coop_mutex_destroy (&type_initialization_section
);
246 g_hash_table_destroy (type_initialization_hash
);
247 type_initialization_hash
= NULL
;
249 mono_os_mutex_destroy (&ldstr_section
);
250 g_hash_table_destroy (blocked_thread_hash
);
251 blocked_thread_hash
= NULL
;
257 * get_type_init_exception_for_vtable:
259 * Return the stored type initialization exception for VTABLE.
261 static MonoException
*
262 get_type_init_exception_for_vtable (MonoVTable
*vtable
)
264 MONO_REQ_GC_UNSAFE_MODE
;
267 MonoDomain
*domain
= vtable
->domain
;
268 MonoClass
*klass
= vtable
->klass
;
272 if (!vtable
->init_failed
)
273 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass
));
276 * If the initializing thread was rudely aborted, the exception is not stored
280 mono_domain_lock (domain
);
281 if (domain
->type_init_exception_hash
)
282 ex
= (MonoException
*)mono_g_hash_table_lookup (domain
->type_init_exception_hash
, klass
);
283 mono_domain_unlock (domain
);
286 if (klass
->name_space
&& *klass
->name_space
)
287 full_name
= g_strdup_printf ("%s.%s", klass
->name_space
, klass
->name
);
289 full_name
= g_strdup (klass
->name
);
290 ex
= mono_get_exception_type_initialization_checked (full_name
, NULL
, &error
);
292 return_val_if_nok (&error
, NULL
);
299 * mono_runtime_class_init:
300 * @vtable: vtable that needs to be initialized
302 * This routine calls the class constructor for @vtable.
305 mono_runtime_class_init (MonoVTable
*vtable
)
307 MONO_REQ_GC_UNSAFE_MODE
;
310 mono_runtime_class_init_full (vtable
, &error
);
311 mono_error_assert_ok (&error
);
315 * mono_runtime_class_init_full:
316 * @vtable that neeeds to be initialized
317 * @error set on error
319 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
323 mono_runtime_class_init_full (MonoVTable
*vtable
, MonoError
*error
)
325 MONO_REQ_GC_UNSAFE_MODE
;
327 MonoMethod
*method
= NULL
;
330 MonoDomain
*domain
= vtable
->domain
;
331 TypeInitializationLock
*lock
;
332 MonoNativeThreadId tid
;
333 int do_initialization
= 0;
334 MonoDomain
*last_domain
= NULL
;
335 MonoException
* pending_tae
= NULL
;
337 mono_error_init (error
);
339 if (vtable
->initialized
)
342 klass
= vtable
->klass
;
344 if (!klass
->image
->checked_module_cctor
) {
345 mono_image_check_for_module_cctor (klass
->image
);
346 if (klass
->image
->has_module_cctor
) {
347 MonoClass
*module_klass
;
348 MonoVTable
*module_vtable
;
350 module_klass
= mono_class_get_checked (klass
->image
, MONO_TOKEN_TYPE_DEF
| 1, error
);
355 module_vtable
= mono_class_vtable_full (vtable
->domain
, module_klass
, error
);
358 if (!mono_runtime_class_init_full (module_vtable
, error
))
362 method
= mono_class_get_cctor (klass
);
364 vtable
->initialized
= 1;
368 tid
= mono_native_thread_id_get ();
370 mono_type_initialization_lock ();
371 /* double check... */
372 if (vtable
->initialized
) {
373 mono_type_initialization_unlock ();
376 if (vtable
->init_failed
) {
377 mono_type_initialization_unlock ();
379 /* The type initialization already failed once, rethrow the same exception */
380 mono_error_set_exception_instance (error
, get_type_init_exception_for_vtable (vtable
));
383 lock
= (TypeInitializationLock
*)g_hash_table_lookup (type_initialization_hash
, vtable
);
385 /* This thread will get to do the initialization */
386 if (mono_domain_get () != domain
) {
387 /* Transfer into the target domain */
388 last_domain
= mono_domain_get ();
389 if (!mono_domain_set (domain
, FALSE
)) {
390 vtable
->initialized
= 1;
391 mono_type_initialization_unlock ();
392 mono_error_set_exception_instance (error
, mono_get_exception_appdomain_unloaded ());
396 lock
= (TypeInitializationLock
*)g_malloc (sizeof (TypeInitializationLock
));
397 mono_coop_mutex_init_recursive (&lock
->initialization_section
);
398 lock
->initializing_tid
= tid
;
399 lock
->waiting_count
= 1;
401 /* grab the vtable lock while this thread still owns type_initialization_section */
402 /* This is why type_initialization_lock needs to enter blocking mode */
403 mono_type_init_lock (lock
);
404 g_hash_table_insert (type_initialization_hash
, vtable
, lock
);
405 do_initialization
= 1;
408 TypeInitializationLock
*pending_lock
;
410 if (mono_native_thread_id_equals (lock
->initializing_tid
, tid
) || lock
->done
) {
411 mono_type_initialization_unlock ();
414 /* see if the thread doing the initialization is already blocked on this thread */
415 blocked
= GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock
->initializing_tid
));
416 while ((pending_lock
= (TypeInitializationLock
*) g_hash_table_lookup (blocked_thread_hash
, blocked
))) {
417 if (mono_native_thread_id_equals (pending_lock
->initializing_tid
, tid
)) {
418 if (!pending_lock
->done
) {
419 mono_type_initialization_unlock ();
422 /* the thread doing the initialization is blocked on this thread,
423 but on a lock that has already been freed. It just hasn't got
428 blocked
= GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock
->initializing_tid
));
430 ++lock
->waiting_count
;
431 /* record the fact that we are waiting on the initializing thread */
432 g_hash_table_insert (blocked_thread_hash
, GUINT_TO_POINTER (tid
), lock
);
434 mono_type_initialization_unlock ();
436 if (do_initialization
) {
437 MonoException
*exc
= NULL
;
439 mono_threads_begin_abort_protected_block ();
440 mono_runtime_try_invoke (method
, NULL
, NULL
, (MonoObject
**) &exc
, error
);
441 mono_threads_end_abort_protected_block ();
443 //exception extracted, error will be set to the right value later
444 if (exc
== NULL
&& !mono_error_ok (error
))//invoking failed but exc was not set
445 exc
= mono_error_convert_to_exception (error
);
447 mono_error_cleanup (error
);
449 mono_error_init (error
);
451 /* If the initialization failed, mark the class as unusable. */
452 /* Avoid infinite loops */
454 (klass
->image
== mono_defaults
.corlib
&&
455 !strcmp (klass
->name_space
, "System") &&
456 !strcmp (klass
->name
, "TypeInitializationException")))) {
457 vtable
->init_failed
= 1;
459 if (klass
->name_space
&& *klass
->name_space
)
460 full_name
= g_strdup_printf ("%s.%s", klass
->name_space
, klass
->name
);
462 full_name
= g_strdup (klass
->name
);
464 MonoException
*exc_to_throw
= mono_get_exception_type_initialization_checked (full_name
, exc
, error
);
467 mono_error_assert_ok (error
); //We can't recover from this, no way to fail a type we can't alloc a failure.
470 * Store the exception object so it could be thrown on subsequent
473 mono_domain_lock (domain
);
474 if (!domain
->type_init_exception_hash
)
475 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");
476 mono_g_hash_table_insert (domain
->type_init_exception_hash
, klass
, exc_to_throw
);
477 mono_domain_unlock (domain
);
481 mono_domain_set (last_domain
, TRUE
);
483 mono_type_init_unlock (lock
);
484 if (exc
&& mono_object_class (exc
) == mono_defaults
.threadabortexception_class
)
486 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
487 if (!pending_tae
&& mono_get_eh_callbacks ()->mono_above_abort_threshold ())
488 pending_tae
= mono_thread_try_resume_interruption ();
490 /* this just blocks until the initializing thread is done */
491 mono_type_init_lock (lock
);
492 mono_type_init_unlock (lock
);
495 mono_type_initialization_lock ();
496 if (!mono_native_thread_id_equals (lock
->initializing_tid
, tid
))
497 g_hash_table_remove (blocked_thread_hash
, GUINT_TO_POINTER (tid
));
498 --lock
->waiting_count
;
499 if (lock
->waiting_count
== 0) {
500 mono_coop_mutex_destroy (&lock
->initialization_section
);
501 g_hash_table_remove (type_initialization_hash
, vtable
);
504 mono_memory_barrier ();
505 if (!vtable
->init_failed
)
506 vtable
->initialized
= 1;
507 mono_type_initialization_unlock ();
511 mono_error_set_exception_instance (error
, pending_tae
);
512 else if (vtable
->init_failed
) {
513 /* Either we were the initializing thread or we waited for the initialization */
514 mono_error_set_exception_instance (error
, get_type_init_exception_for_vtable (vtable
));
521 gboolean
release_type_locks (gpointer key
, gpointer value
, gpointer user
)
523 MONO_REQ_GC_NEUTRAL_MODE
;
525 MonoVTable
*vtable
= (MonoVTable
*)key
;
527 TypeInitializationLock
*lock
= (TypeInitializationLock
*) value
;
528 if (mono_native_thread_id_equals (lock
->initializing_tid
, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user
))) && !lock
->done
) {
531 * Have to set this since it cannot be set by the normal code in
532 * mono_runtime_class_init (). In this case, the exception object is not stored,
533 * and get_type_init_exception_for_class () needs to be aware of this.
535 vtable
->init_failed
= 1;
536 mono_type_init_unlock (lock
);
537 --lock
->waiting_count
;
538 if (lock
->waiting_count
== 0) {
539 mono_coop_mutex_destroy (&lock
->initialization_section
);
548 mono_release_type_locks (MonoInternalThread
*thread
)
550 MONO_REQ_GC_UNSAFE_MODE
;
552 mono_type_initialization_lock ();
553 g_hash_table_foreach_remove (type_initialization_hash
, release_type_locks
, GUINT_TO_POINTER (thread
->tid
));
554 mono_type_initialization_unlock ();
557 #ifndef DISABLE_REMOTING
560 create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
, MonoError
*error
)
562 if (!callbacks
.create_remoting_trampoline
)
563 g_error ("remoting not installed");
564 return callbacks
.create_remoting_trampoline (domain
, method
, target
, error
);
569 static MonoImtTrampolineBuilder imt_trampoline_builder
;
570 static gboolean always_build_imt_trampolines
;
572 #if (MONO_IMT_SIZE > 32)
573 #error "MONO_IMT_SIZE cannot be larger than 32"
577 mono_install_callbacks (MonoRuntimeCallbacks
*cbs
)
579 memcpy (&callbacks
, cbs
, sizeof (*cbs
));
582 MonoRuntimeCallbacks
*
583 mono_get_runtime_callbacks (void)
589 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func
)
591 imt_trampoline_builder
= func
;
595 mono_set_always_build_imt_trampolines (gboolean value
)
597 always_build_imt_trampolines
= value
;
601 * mono_compile_method:
602 * @method: The method to compile.
604 * This JIT-compiles the method, and returns the pointer to the native code
608 mono_compile_method (MonoMethod
*method
)
611 gpointer result
= mono_compile_method_checked (method
, &error
);
612 mono_error_cleanup (&error
);
617 * mono_compile_method:
618 * @method: The method to compile.
619 * @error: set on error.
621 * This JIT-compiles the method, and returns the pointer to the native code
622 * produced. On failure returns NULL and sets @error.
625 mono_compile_method_checked (MonoMethod
*method
, MonoError
*error
)
629 MONO_REQ_GC_NEUTRAL_MODE
631 mono_error_init (error
);
633 g_assert (callbacks
.compile_method
);
634 res
= callbacks
.compile_method (method
, error
);
639 mono_runtime_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
, MonoError
*error
)
643 MONO_REQ_GC_NEUTRAL_MODE
;
645 mono_error_init (error
);
646 res
= callbacks
.create_jump_trampoline (domain
, method
, add_sync_wrapper
, error
);
651 mono_runtime_create_delegate_trampoline (MonoClass
*klass
)
653 MONO_REQ_GC_NEUTRAL_MODE
655 g_assert (callbacks
.create_delegate_trampoline
);
656 return callbacks
.create_delegate_trampoline (mono_domain_get (), klass
);
660 * mono_runtime_free_method:
661 * @domain; domain where the method is hosted
662 * @method: method to release
664 * This routine is invoked to free the resources associated with
665 * a method that has been JIT compiled. This is used to discard
666 * methods that were used only temporarily (for example, used in marshalling)
670 mono_runtime_free_method (MonoDomain
*domain
, MonoMethod
*method
)
672 MONO_REQ_GC_NEUTRAL_MODE
674 if (callbacks
.free_method
)
675 callbacks
.free_method (domain
, method
);
677 mono_method_clear_object (domain
, method
);
679 mono_free_method (method
);
683 * The vtables in the root appdomain are assumed to be reachable by other
684 * roots, and we don't use typed allocation in the other domains.
687 /* The sync block is no longer a GC pointer */
688 #define GC_HEADER_BITMAP (0)
690 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
693 compute_class_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
, int *max_set
, gboolean static_fields
)
695 MONO_REQ_GC_NEUTRAL_MODE
;
697 MonoClassField
*field
;
703 max_size
= mono_class_data_size (klass
) / sizeof (gpointer
);
705 max_size
= klass
->instance_size
/ sizeof (gpointer
);
706 if (max_size
> size
) {
707 g_assert (offset
<= 0);
708 bitmap
= (gsize
*)g_malloc0 ((max_size
+ BITMAP_EL_SIZE
- 1) / BITMAP_EL_SIZE
* sizeof (gsize
));
713 /*An Ephemeron cannot be marked by sgen*/
714 if (!static_fields
&& klass
->image
== mono_defaults
.corlib
&& !strcmp ("Ephemeron", klass
->name
)) {
716 memset (bitmap
, 0, size
/ 8);
721 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
722 gpointer iter
= NULL
;
723 while ((field
= mono_class_get_fields (p
, &iter
))) {
727 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
729 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
732 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
735 /* FIXME: should not happen, flag as type load error */
736 if (field
->type
->byref
)
739 if (static_fields
&& field
->offset
== -1)
743 pos
= field
->offset
/ sizeof (gpointer
);
746 type
= mono_type_get_underlying_type (field
->type
);
747 switch (type
->type
) {
750 case MONO_TYPE_FNPTR
:
752 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
757 if (klass
->image
!= mono_defaults
.corlib
)
760 case MONO_TYPE_STRING
:
761 case MONO_TYPE_SZARRAY
:
762 case MONO_TYPE_CLASS
:
763 case MONO_TYPE_OBJECT
:
764 case MONO_TYPE_ARRAY
:
765 g_assert ((field
->offset
% sizeof(gpointer
)) == 0);
767 g_assert (pos
< size
|| pos
<= max_size
);
768 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
769 *max_set
= MAX (*max_set
, pos
);
771 case MONO_TYPE_GENERICINST
:
772 if (!mono_type_generic_inst_is_valuetype (type
)) {
773 g_assert ((field
->offset
% sizeof(gpointer
)) == 0);
775 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
776 *max_set
= MAX (*max_set
, pos
);
781 case MONO_TYPE_VALUETYPE
: {
782 MonoClass
*fclass
= mono_class_from_mono_type (field
->type
);
783 if (fclass
->has_references
) {
784 /* remove the object header */
785 compute_class_bitmap (fclass
, bitmap
, size
, pos
- (sizeof (MonoObject
) / sizeof (gpointer
)), max_set
, FALSE
);
799 case MONO_TYPE_BOOLEAN
:
803 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type
->type
, mono_type_get_full_name (field
->parent
), field
->name
);
814 * mono_class_compute_bitmap:
816 * Mono internal function to compute a bitmap of reference fields in a class.
819 mono_class_compute_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
, int *max_set
, gboolean static_fields
)
821 MONO_REQ_GC_NEUTRAL_MODE
;
823 return compute_class_bitmap (klass
, bitmap
, size
, offset
, max_set
, static_fields
);
828 * similar to the above, but sets the bits in the bitmap for any non-ref field
829 * and ignores static fields
832 compute_class_non_ref_bitmap (MonoClass
*klass
, gsize
*bitmap
, int size
, int offset
)
834 MonoClassField
*field
;
839 max_size
= class->instance_size
/ sizeof (gpointer
);
840 if (max_size
>= size
) {
841 bitmap
= g_malloc0 (sizeof (gsize
) * ((max_size
) + 1));
844 for (p
= class; p
!= NULL
; p
= p
->parent
) {
845 gpointer iter
= NULL
;
846 while ((field
= mono_class_get_fields (p
, &iter
))) {
849 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
851 /* FIXME: should not happen, flag as type load error */
852 if (field
->type
->byref
)
855 pos
= field
->offset
/ sizeof (gpointer
);
858 type
= mono_type_get_underlying_type (field
->type
);
859 switch (type
->type
) {
860 #if SIZEOF_VOID_P == 8
864 case MONO_TYPE_FNPTR
:
869 if ((((field
->offset
+ 7) / sizeof (gpointer
)) + offset
) != pos
) {
870 pos2
= ((field
->offset
+ 7) / sizeof (gpointer
)) + offset
;
871 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
874 #if SIZEOF_VOID_P == 4
878 case MONO_TYPE_FNPTR
:
883 if ((((field
->offset
+ 3) / sizeof (gpointer
)) + offset
) != pos
) {
884 pos2
= ((field
->offset
+ 3) / sizeof (gpointer
)) + offset
;
885 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
891 if ((((field
->offset
+ 1) / sizeof (gpointer
)) + offset
) != pos
) {
892 pos2
= ((field
->offset
+ 1) / sizeof (gpointer
)) + offset
;
893 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
896 case MONO_TYPE_BOOLEAN
:
899 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
901 case MONO_TYPE_STRING
:
902 case MONO_TYPE_SZARRAY
:
903 case MONO_TYPE_CLASS
:
904 case MONO_TYPE_OBJECT
:
905 case MONO_TYPE_ARRAY
:
907 case MONO_TYPE_GENERICINST
:
908 if (!mono_type_generic_inst_is_valuetype (type
)) {
913 case MONO_TYPE_VALUETYPE
: {
914 MonoClass
*fclass
= mono_class_from_mono_type (field
->type
);
915 /* remove the object header */
916 compute_class_non_ref_bitmap (fclass
, bitmap
, size
, pos
- (sizeof (MonoObject
) / sizeof (gpointer
)));
920 g_assert_not_reached ();
929 * mono_class_insecure_overlapping:
930 * check if a class with explicit layout has references and non-references
931 * fields overlapping.
933 * Returns: TRUE if it is insecure to load the type.
936 mono_class_insecure_overlapping (MonoClass
*klass
)
940 gsize default_bitmap
[4] = {0};
942 gsize default_nrbitmap
[4] = {0};
943 int i
, insecure
= FALSE
;
946 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
947 nrbitmap
= compute_class_non_ref_bitmap (klass
, default_nrbitmap
, sizeof (default_nrbitmap
) * 8, 0);
949 for (i
= 0; i
<= max_set
; i
+= sizeof (bitmap
[0]) * 8) {
950 int idx
= i
% (sizeof (bitmap
[0]) * 8);
951 if (bitmap
[idx
] & nrbitmap
[idx
]) {
956 if (bitmap
!= default_bitmap
)
958 if (nrbitmap
!= default_nrbitmap
)
961 g_print ("class %s.%s in assembly %s has overlapping references\n", klass
->name_space
, klass
->name
, klass
->image
->name
);
969 ves_icall_string_alloc (int length
)
972 MonoString
*str
= mono_string_new_size_checked (mono_domain_get (), length
, &error
);
973 mono_error_set_pending_exception (&error
);
978 /* LOCKING: Acquires the loader lock */
980 mono_class_compute_gc_descriptor (MonoClass
*klass
)
982 MONO_REQ_GC_NEUTRAL_MODE
;
986 gsize default_bitmap
[4] = {0};
987 static gboolean gcj_inited
= FALSE
;
988 MonoGCDescriptor gc_descr
;
993 mono_register_jit_icall (ves_icall_object_new_fast
, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE
);
994 mono_register_jit_icall (ves_icall_string_alloc
, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE
);
997 mono_loader_unlock ();
1001 mono_class_init (klass
);
1003 if (klass
->gc_descr_inited
)
1006 bitmap
= default_bitmap
;
1007 if (klass
== mono_defaults
.string_class
) {
1008 gc_descr
= mono_gc_make_descr_for_string (bitmap
, 2);
1009 } else if (klass
->rank
) {
1010 mono_class_compute_gc_descriptor (klass
->element_class
);
1011 if (MONO_TYPE_IS_REFERENCE (&klass
->element_class
->byval_arg
)) {
1013 gc_descr
= mono_gc_make_descr_for_array (klass
->byval_arg
.type
== MONO_TYPE_SZARRAY
, &abm
, 1, sizeof (gpointer
));
1014 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1015 class->name_space, class->name);*/
1017 /* remove the object header */
1018 bitmap
= compute_class_bitmap (klass
->element_class
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(sizeof (MonoObject
) / sizeof (gpointer
)), &max_set
, FALSE
);
1019 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
));
1020 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1021 class->name_space, class->name);*/
1022 if (bitmap
!= default_bitmap
)
1026 /*static int count = 0;
1029 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
1030 gc_descr
= mono_gc_make_descr_for_object (bitmap
, max_set
+ 1, klass
->instance_size
);
1032 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1033 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1035 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1036 if (bitmap
!= default_bitmap
)
1040 /* Publish the data */
1041 mono_loader_lock ();
1042 klass
->gc_descr
= gc_descr
;
1043 mono_memory_barrier ();
1044 klass
->gc_descr_inited
= TRUE
;
1045 mono_loader_unlock ();
1049 * field_is_special_static:
1050 * @fklass: The MonoClass to look up.
1051 * @field: The MonoClassField describing the field.
1053 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1054 * SPECIAL_STATIC_NONE otherwise.
1057 field_is_special_static (MonoClass
*fklass
, MonoClassField
*field
)
1059 MONO_REQ_GC_NEUTRAL_MODE
;
1062 MonoCustomAttrInfo
*ainfo
;
1064 ainfo
= mono_custom_attrs_from_field_checked (fklass
, field
, &error
);
1065 mono_error_cleanup (&error
); /* FIXME don't swallow the error? */
1068 for (i
= 0; i
< ainfo
->num_attrs
; ++i
) {
1069 MonoClass
*klass
= ainfo
->attrs
[i
].ctor
->klass
;
1070 if (klass
->image
== mono_defaults
.corlib
) {
1071 if (strcmp (klass
->name
, "ThreadStaticAttribute") == 0) {
1072 mono_custom_attrs_free (ainfo
);
1073 return SPECIAL_STATIC_THREAD
;
1075 else if (strcmp (klass
->name
, "ContextStaticAttribute") == 0) {
1076 mono_custom_attrs_free (ainfo
);
1077 return SPECIAL_STATIC_CONTEXT
;
1081 mono_custom_attrs_free (ainfo
);
1082 return SPECIAL_STATIC_NONE
;
1085 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1086 #define mix(a,b,c) { \
1087 a -= c; a ^= rot(c, 4); c += b; \
1088 b -= a; b ^= rot(a, 6); a += c; \
1089 c -= b; c ^= rot(b, 8); b += a; \
1090 a -= c; a ^= rot(c,16); c += b; \
1091 b -= a; b ^= rot(a,19); a += c; \
1092 c -= b; c ^= rot(b, 4); b += a; \
1094 #define final(a,b,c) { \
1095 c ^= b; c -= rot(b,14); \
1096 a ^= c; a -= rot(c,11); \
1097 b ^= a; b -= rot(a,25); \
1098 c ^= b; c -= rot(b,16); \
1099 a ^= c; a -= rot(c,4); \
1100 b ^= a; b -= rot(a,14); \
1101 c ^= b; c -= rot(b,24); \
1105 * mono_method_get_imt_slot:
1107 * The IMT slot is embedded into AOTed code, so this must return the same value
1108 * for the same method across all executions. This means:
1109 * - pointers shouldn't be used as hash values.
1110 * - mono_metadata_str_hash () should be used for hashing strings.
1113 mono_method_get_imt_slot (MonoMethod
*method
)
1115 MONO_REQ_GC_NEUTRAL_MODE
;
1117 MonoMethodSignature
*sig
;
1119 guint32
*hashes_start
, *hashes
;
1123 /* This can be used to stress tests the collision code */
1127 * We do this to simplify generic sharing. It will hurt
1128 * performance in cases where a class implements two different
1129 * instantiations of the same generic interface.
1130 * The code in build_imt_slots () depends on this.
1132 if (method
->is_inflated
)
1133 method
= ((MonoMethodInflated
*)method
)->declaring
;
1135 sig
= mono_method_signature (method
);
1136 hashes_count
= sig
->param_count
+ 4;
1137 hashes_start
= (guint32
*)malloc (hashes_count
* sizeof (guint32
));
1138 hashes
= hashes_start
;
1140 if (! MONO_CLASS_IS_INTERFACE (method
->klass
)) {
1141 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1142 method
->klass
->name_space
, method
->klass
->name
, method
->name
);
1145 /* Initialize hashes */
1146 hashes
[0] = mono_metadata_str_hash (method
->klass
->name
);
1147 hashes
[1] = mono_metadata_str_hash (method
->klass
->name_space
);
1148 hashes
[2] = mono_metadata_str_hash (method
->name
);
1149 hashes
[3] = mono_metadata_type_hash (sig
->ret
);
1150 for (i
= 0; i
< sig
->param_count
; i
++) {
1151 hashes
[4 + i
] = mono_metadata_type_hash (sig
->params
[i
]);
1154 /* Setup internal state */
1155 a
= b
= c
= 0xdeadbeef + (((guint32
)hashes_count
)<<2);
1157 /* Handle most of the hashes */
1158 while (hashes_count
> 3) {
1167 /* Handle the last 3 hashes (all the case statements fall through) */
1168 switch (hashes_count
) {
1169 case 3 : c
+= hashes
[2];
1170 case 2 : b
+= hashes
[1];
1171 case 1 : a
+= hashes
[0];
1173 case 0: /* nothing left to add */
1177 g_free (hashes_start
);
1178 /* Report the result */
1179 return c
% MONO_IMT_SIZE
;
1188 add_imt_builder_entry (MonoImtBuilderEntry
**imt_builder
, MonoMethod
*method
, guint32
*imt_collisions_bitmap
, int vtable_slot
, int slot_num
) {
1189 MONO_REQ_GC_NEUTRAL_MODE
;
1191 guint32 imt_slot
= mono_method_get_imt_slot (method
);
1192 MonoImtBuilderEntry
*entry
;
1194 if (slot_num
>= 0 && imt_slot
!= slot_num
) {
1195 /* we build just a single imt slot and this is not it */
1199 entry
= (MonoImtBuilderEntry
*)g_malloc0 (sizeof (MonoImtBuilderEntry
));
1200 entry
->key
= method
;
1201 entry
->value
.vtable_slot
= vtable_slot
;
1202 entry
->next
= imt_builder
[imt_slot
];
1203 if (imt_builder
[imt_slot
] != NULL
) {
1204 entry
->children
= imt_builder
[imt_slot
]->children
+ 1;
1205 if (entry
->children
== 1) {
1206 mono_stats
.imt_slots_with_collisions
++;
1207 *imt_collisions_bitmap
|= (1 << imt_slot
);
1210 entry
->children
= 0;
1211 mono_stats
.imt_used_slots
++;
1213 imt_builder
[imt_slot
] = entry
;
1216 char *method_name
= mono_method_full_name (method
, TRUE
);
1217 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1218 method
, method_name
, imt_slot
, vtable_slot
, entry
->children
);
1219 g_free (method_name
);
1226 print_imt_entry (const char* message
, MonoImtBuilderEntry
*e
, int num
) {
1228 MonoMethod
*method
= e
->key
;
1229 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1233 method
->klass
->name_space
,
1234 method
->klass
->name
,
1237 printf (" * %s: NULL\n", message
);
1243 compare_imt_builder_entries (const void *p1
, const void *p2
) {
1244 MonoImtBuilderEntry
*e1
= *(MonoImtBuilderEntry
**) p1
;
1245 MonoImtBuilderEntry
*e2
= *(MonoImtBuilderEntry
**) p2
;
1247 return (e1
->key
< e2
->key
) ? -1 : ((e1
->key
> e2
->key
) ? 1 : 0);
1251 imt_emit_ir (MonoImtBuilderEntry
**sorted_array
, int start
, int end
, GPtrArray
*out_array
)
1253 MONO_REQ_GC_NEUTRAL_MODE
;
1255 int count
= end
- start
;
1256 int chunk_start
= out_array
->len
;
1259 for (i
= start
; i
< end
; ++i
) {
1260 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1261 item
->key
= sorted_array
[i
]->key
;
1262 item
->value
= sorted_array
[i
]->value
;
1263 item
->has_target_code
= sorted_array
[i
]->has_target_code
;
1264 item
->is_equals
= TRUE
;
1266 item
->check_target_idx
= out_array
->len
+ 1;
1268 item
->check_target_idx
= 0;
1269 g_ptr_array_add (out_array
, item
);
1272 int middle
= start
+ count
/ 2;
1273 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1275 item
->key
= sorted_array
[middle
]->key
;
1276 item
->is_equals
= FALSE
;
1277 g_ptr_array_add (out_array
, item
);
1278 imt_emit_ir (sorted_array
, start
, middle
, out_array
);
1279 item
->check_target_idx
= imt_emit_ir (sorted_array
, middle
, end
, out_array
);
1285 imt_sort_slot_entries (MonoImtBuilderEntry
*entries
) {
1286 MONO_REQ_GC_NEUTRAL_MODE
;
1288 int number_of_entries
= entries
->children
+ 1;
1289 MonoImtBuilderEntry
**sorted_array
= (MonoImtBuilderEntry
**)malloc (sizeof (MonoImtBuilderEntry
*) * number_of_entries
);
1290 GPtrArray
*result
= g_ptr_array_new ();
1291 MonoImtBuilderEntry
*current_entry
;
1294 for (current_entry
= entries
, i
= 0; current_entry
!= NULL
; current_entry
= current_entry
->next
, i
++) {
1295 sorted_array
[i
] = current_entry
;
1297 qsort (sorted_array
, number_of_entries
, sizeof (MonoImtBuilderEntry
*), compare_imt_builder_entries
);
1299 /*for (i = 0; i < number_of_entries; i++) {
1300 print_imt_entry (" sorted array:", sorted_array [i], i);
1303 imt_emit_ir (sorted_array
, 0, number_of_entries
, result
);
1305 g_free (sorted_array
);
1310 initialize_imt_slot (MonoVTable
*vtable
, MonoDomain
*domain
, MonoImtBuilderEntry
*imt_builder_entry
, gpointer fail_tramp
)
1312 MONO_REQ_GC_NEUTRAL_MODE
;
1314 if (imt_builder_entry
!= NULL
) {
1315 if (imt_builder_entry
->children
== 0 && !fail_tramp
&& !always_build_imt_trampolines
) {
1316 /* No collision, return the vtable slot contents */
1317 return vtable
->vtable
[imt_builder_entry
->value
.vtable_slot
];
1319 /* Collision, build the trampoline */
1320 GPtrArray
*imt_ir
= imt_sort_slot_entries (imt_builder_entry
);
1323 result
= imt_trampoline_builder (vtable
, domain
,
1324 (MonoIMTCheckItem
**)imt_ir
->pdata
, imt_ir
->len
, fail_tramp
);
1325 for (i
= 0; i
< imt_ir
->len
; ++i
)
1326 g_free (g_ptr_array_index (imt_ir
, i
));
1327 g_ptr_array_free (imt_ir
, TRUE
);
1339 static MonoImtBuilderEntry
*
1340 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
);
1343 * LOCKING: requires the loader and domain locks.
1347 build_imt_slots (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
, int slot_num
)
1349 MONO_REQ_GC_NEUTRAL_MODE
;
1353 guint32 imt_collisions_bitmap
= 0;
1354 MonoImtBuilderEntry
**imt_builder
= (MonoImtBuilderEntry
**)calloc (MONO_IMT_SIZE
, sizeof (MonoImtBuilderEntry
*));
1355 int method_count
= 0;
1356 gboolean record_method_count_for_max_collisions
= FALSE
;
1357 gboolean has_generic_virtual
= FALSE
, has_variant_iface
= FALSE
;
1360 printf ("Building IMT for class %s.%s slot %d\n", klass
->name_space
, klass
->name
, slot_num
);
1362 for (i
= 0; i
< klass
->interface_offsets_count
; ++i
) {
1363 MonoClass
*iface
= klass
->interfaces_packed
[i
];
1364 int interface_offset
= klass
->interface_offsets_packed
[i
];
1365 int method_slot_in_interface
, vt_slot
;
1367 if (mono_class_has_variant_generic_params (iface
))
1368 has_variant_iface
= TRUE
;
1370 mono_class_setup_methods (iface
);
1371 vt_slot
= interface_offset
;
1372 int mcount
= mono_class_get_method_count (iface
);
1373 for (method_slot_in_interface
= 0; method_slot_in_interface
< mcount
; method_slot_in_interface
++) {
1376 if (slot_num
>= 0 && mono_class_is_ginst (iface
)) {
1378 * The imt slot of the method is the same as for its declaring method,
1379 * see the comment in mono_method_get_imt_slot (), so we can
1380 * avoid inflating methods which will be discarded by
1381 * add_imt_builder_entry anyway.
1383 method
= mono_class_get_method_by_index (mono_class_get_generic_class (iface
)->container_class
, method_slot_in_interface
);
1384 if (mono_method_get_imt_slot (method
) != slot_num
) {
1389 method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1390 if (method
->is_generic
) {
1391 has_generic_virtual
= TRUE
;
1396 if (!(method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1397 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, vt_slot
, slot_num
);
1402 if (extra_interfaces
) {
1403 int interface_offset
= klass
->vtable_size
;
1405 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
1406 MonoClass
* iface
= (MonoClass
*)list_item
->data
;
1407 int method_slot_in_interface
;
1408 int mcount
= mono_class_get_method_count (iface
);
1409 for (method_slot_in_interface
= 0; method_slot_in_interface
< mcount
; method_slot_in_interface
++) {
1410 MonoMethod
*method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1412 if (method
->is_generic
)
1413 has_generic_virtual
= TRUE
;
1414 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, interface_offset
+ method_slot_in_interface
, slot_num
);
1416 interface_offset
+= mcount
;
1419 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
) {
1420 /* overwrite the imt slot only if we're building all the entries or if
1421 * we're building this specific one
1423 if (slot_num
< 0 || i
== slot_num
) {
1424 MonoImtBuilderEntry
*entries
= get_generic_virtual_entries (domain
, &imt
[i
]);
1427 if (imt_builder
[i
]) {
1428 MonoImtBuilderEntry
*entry
;
1430 /* Link entries with imt_builder [i] */
1431 for (entry
= entries
; entry
->next
; entry
= entry
->next
) {
1433 MonoMethod
*method
= (MonoMethod
*)entry
->key
;
1434 char *method_name
= mono_method_full_name (method
, TRUE
);
1435 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method
, method_name
, i
);
1436 g_free (method_name
);
1439 entry
->next
= imt_builder
[i
];
1440 entries
->children
+= imt_builder
[i
]->children
+ 1;
1442 imt_builder
[i
] = entries
;
1445 if (has_generic_virtual
|| has_variant_iface
) {
1447 * There might be collisions later when the the trampoline is expanded.
1449 imt_collisions_bitmap
|= (1 << i
);
1452 * The IMT trampoline might be called with an instance of one of the
1453 * generic virtual methods, so has to fallback to the IMT trampoline.
1455 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], callbacks
.get_imt_trampoline (vt
, i
));
1457 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], NULL
);
1460 printf ("initialize_imt_slot[%d]: %p methods %d\n", i
, imt
[i
], imt_builder
[i
]->children
+ 1);
1464 if (imt_builder
[i
] != NULL
) {
1465 int methods_in_slot
= imt_builder
[i
]->children
+ 1;
1466 if (methods_in_slot
> mono_stats
.imt_max_collisions_in_slot
) {
1467 mono_stats
.imt_max_collisions_in_slot
= methods_in_slot
;
1468 record_method_count_for_max_collisions
= TRUE
;
1470 method_count
+= methods_in_slot
;
1474 mono_stats
.imt_number_of_methods
+= method_count
;
1475 if (record_method_count_for_max_collisions
) {
1476 mono_stats
.imt_method_count_when_max_collisions
= method_count
;
1479 for (i
= 0; i
< MONO_IMT_SIZE
; i
++) {
1480 MonoImtBuilderEntry
* entry
= imt_builder
[i
];
1481 while (entry
!= NULL
) {
1482 MonoImtBuilderEntry
* next
= entry
->next
;
1487 g_free (imt_builder
);
1488 /* we OR the bitmap since we may build just a single imt slot at a time */
1489 vt
->imt_collisions_bitmap
|= imt_collisions_bitmap
;
1493 build_imt (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
) {
1494 MONO_REQ_GC_NEUTRAL_MODE
;
1496 build_imt_slots (klass
, vt
, domain
, imt
, extra_interfaces
, -1);
1500 * mono_vtable_build_imt_slot:
1501 * @vtable: virtual object table struct
1502 * @imt_slot: slot in the IMT table
1504 * Fill the given @imt_slot in the IMT table of @vtable with
1505 * a trampoline or a trampoline for the case of collisions.
1506 * This is part of the internal mono API.
1508 * LOCKING: Take the domain lock.
1511 mono_vtable_build_imt_slot (MonoVTable
* vtable
, int imt_slot
)
1513 MONO_REQ_GC_NEUTRAL_MODE
;
1515 gpointer
*imt
= (gpointer
*)vtable
;
1516 imt
-= MONO_IMT_SIZE
;
1517 g_assert (imt_slot
>= 0 && imt_slot
< MONO_IMT_SIZE
);
1519 /* no support for extra interfaces: the proxy objects will need
1520 * to build the complete IMT
1521 * Update and heck needs to ahppen inside the proper domain lock, as all
1522 * the changes made to a MonoVTable.
1524 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1525 mono_domain_lock (vtable
->domain
);
1526 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1527 if (!callbacks
.imt_entry_inited (vtable
, imt_slot
))
1528 build_imt_slots (vtable
->klass
, vtable
, vtable
->domain
, imt
, NULL
, imt_slot
);
1529 mono_domain_unlock (vtable
->domain
);
1530 mono_loader_unlock ();
1533 #define THUNK_THRESHOLD 10
1536 * mono_method_alloc_generic_virtual_trampoline:
1538 * @size: size in bytes
1540 * Allocs size bytes to be used for the code of a generic virtual
1541 * trampoline. It's either allocated from the domain's code manager or
1542 * reused from a previously invalidated piece.
1544 * LOCKING: The domain lock must be held.
1547 mono_method_alloc_generic_virtual_trampoline (MonoDomain
*domain
, int size
)
1549 MONO_REQ_GC_NEUTRAL_MODE
;
1551 static gboolean inited
= FALSE
;
1552 static int generic_virtual_trampolines_size
= 0;
1555 mono_counters_register ("Generic virtual trampoline bytes",
1556 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &generic_virtual_trampolines_size
);
1559 generic_virtual_trampolines_size
+= size
;
1561 return mono_domain_code_reserve (domain
, size
);
1564 typedef struct _GenericVirtualCase
{
1568 struct _GenericVirtualCase
*next
;
1569 } GenericVirtualCase
;
1572 * get_generic_virtual_entries:
1574 * Return IMT entries for the generic virtual method instances and
1575 * variant interface methods for vtable slot
1578 static MonoImtBuilderEntry
*
1579 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
)
1581 MONO_REQ_GC_NEUTRAL_MODE
;
1583 GenericVirtualCase
*list
;
1584 MonoImtBuilderEntry
*entries
;
1586 mono_domain_lock (domain
);
1587 if (!domain
->generic_virtual_cases
)
1588 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1590 list
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1593 for (; list
; list
= list
->next
) {
1594 MonoImtBuilderEntry
*entry
;
1596 if (list
->count
< THUNK_THRESHOLD
)
1599 entry
= g_new0 (MonoImtBuilderEntry
, 1);
1600 entry
->key
= list
->method
;
1601 entry
->value
.target_code
= mono_get_addr_from_ftnptr (list
->code
);
1602 entry
->has_target_code
= 1;
1604 entry
->children
= entries
->children
+ 1;
1605 entry
->next
= entries
;
1609 mono_domain_unlock (domain
);
1611 /* FIXME: Leaking memory ? */
1616 * mono_method_add_generic_virtual_invocation:
1618 * @vtable_slot: pointer to the vtable slot
1619 * @method: the inflated generic virtual method
1620 * @code: the method's code
1622 * Registers a call via unmanaged code to a generic virtual method
1623 * instantiation or variant interface method. If the number of calls reaches a threshold
1624 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1625 * virtual method trampoline.
1628 mono_method_add_generic_virtual_invocation (MonoDomain
*domain
, MonoVTable
*vtable
,
1629 gpointer
*vtable_slot
,
1630 MonoMethod
*method
, gpointer code
)
1632 MONO_REQ_GC_NEUTRAL_MODE
;
1634 static gboolean inited
= FALSE
;
1635 static int num_added
= 0;
1636 static int num_freed
= 0;
1638 GenericVirtualCase
*gvc
, *list
;
1639 MonoImtBuilderEntry
*entries
;
1643 mono_domain_lock (domain
);
1644 if (!domain
->generic_virtual_cases
)
1645 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1648 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_added
);
1649 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_freed
);
1653 /* Check whether the case was already added */
1654 list
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1657 if (gvc
->method
== method
)
1662 /* If not found, make a new one */
1664 gvc
= (GenericVirtualCase
*)mono_domain_alloc (domain
, sizeof (GenericVirtualCase
));
1665 gvc
->method
= method
;
1668 gvc
->next
= (GenericVirtualCase
*)g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1670 g_hash_table_insert (domain
->generic_virtual_cases
, vtable_slot
, gvc
);
1675 if (++gvc
->count
== THUNK_THRESHOLD
) {
1676 gpointer
*old_thunk
= (void **)*vtable_slot
;
1677 gpointer vtable_trampoline
= NULL
;
1678 gpointer imt_trampoline
= NULL
;
1680 if ((gpointer
)vtable_slot
< (gpointer
)vtable
) {
1681 int displacement
= (gpointer
*)vtable_slot
- (gpointer
*)vtable
;
1682 int imt_slot
= MONO_IMT_SIZE
+ displacement
;
1684 /* Force the rebuild of the trampoline at the next call */
1685 imt_trampoline
= callbacks
.get_imt_trampoline (vtable
, imt_slot
);
1686 *vtable_slot
= imt_trampoline
;
1688 vtable_trampoline
= callbacks
.get_vtable_trampoline
? callbacks
.get_vtable_trampoline (vtable
, (gpointer
*)vtable_slot
- (gpointer
*)vtable
->vtable
) : NULL
;
1690 entries
= get_generic_virtual_entries (domain
, vtable_slot
);
1692 sorted
= imt_sort_slot_entries (entries
);
1694 *vtable_slot
= imt_trampoline_builder (NULL
, domain
, (MonoIMTCheckItem
**)sorted
->pdata
, sorted
->len
,
1698 MonoImtBuilderEntry
*next
= entries
->next
;
1703 for (i
= 0; i
< sorted
->len
; ++i
)
1704 g_free (g_ptr_array_index (sorted
, i
));
1705 g_ptr_array_free (sorted
, TRUE
);
1707 if (old_thunk
!= vtable_trampoline
&& old_thunk
!= imt_trampoline
)
1712 mono_domain_unlock (domain
);
1715 static MonoVTable
*mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
);
1718 * mono_class_vtable:
1719 * @domain: the application domain
1720 * @class: the class to initialize
1722 * VTables are domain specific because we create domain specific code, and
1723 * they contain the domain specific static class data.
1724 * On failure, NULL is returned, and class->exception_type is set.
1727 mono_class_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1730 MonoVTable
* vtable
= mono_class_vtable_full (domain
, klass
, &error
);
1731 mono_error_cleanup (&error
);
1736 * mono_class_vtable_full:
1737 * @domain: the application domain
1738 * @class: the class to initialize
1739 * @error set on failure.
1741 * VTables are domain specific because we create domain specific code, and
1742 * they contain the domain specific static class data.
1745 mono_class_vtable_full (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
1747 MONO_REQ_GC_UNSAFE_MODE
;
1749 MonoClassRuntimeInfo
*runtime_info
;
1751 mono_error_init (error
);
1755 if (mono_class_has_failure (klass
)) {
1756 mono_error_set_for_class_failure (error
, klass
);
1760 /* this check can be inlined in jitted code, too */
1761 runtime_info
= klass
->runtime_info
;
1762 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1763 return runtime_info
->domain_vtables
[domain
->domain_id
];
1764 return mono_class_create_runtime_vtable (domain
, klass
, error
);
1768 * mono_class_try_get_vtable:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1772 * This function tries to get the associated vtable from @class if
1773 * it was already created.
1776 mono_class_try_get_vtable (MonoDomain
*domain
, MonoClass
*klass
)
1778 MONO_REQ_GC_NEUTRAL_MODE
;
1780 MonoClassRuntimeInfo
*runtime_info
;
1784 runtime_info
= klass
->runtime_info
;
1785 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1786 return runtime_info
->domain_vtables
[domain
->domain_id
];
1791 alloc_vtable (MonoDomain
*domain
, size_t vtable_size
, size_t imt_table_bytes
)
1793 MONO_REQ_GC_NEUTRAL_MODE
;
1795 size_t alloc_offset
;
1798 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1799 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1800 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1802 if (sizeof (gpointer
) == 4 && (imt_table_bytes
& 7)) {
1803 g_assert ((imt_table_bytes
& 7) == 4);
1810 return (gpointer
*) ((char*)mono_domain_alloc0 (domain
, vtable_size
) + alloc_offset
);
1814 mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
1816 MONO_REQ_GC_UNSAFE_MODE
;
1819 MonoClassRuntimeInfo
*runtime_info
, *old_info
;
1820 MonoClassField
*field
;
1822 int i
, vtable_slots
;
1823 size_t imt_table_bytes
;
1825 guint32 vtable_size
, class_size
;
1827 gpointer
*interface_offsets
;
1829 mono_error_init (error
);
1831 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1832 mono_domain_lock (domain
);
1833 runtime_info
= klass
->runtime_info
;
1834 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
]) {
1835 mono_domain_unlock (domain
);
1836 mono_loader_unlock ();
1837 return runtime_info
->domain_vtables
[domain
->domain_id
];
1839 if (!klass
->inited
|| mono_class_has_failure (klass
)) {
1840 if (!mono_class_init (klass
) || mono_class_has_failure (klass
)) {
1841 mono_domain_unlock (domain
);
1842 mono_loader_unlock ();
1843 mono_error_set_for_class_failure (error
, klass
);
1848 /* Array types require that their element type be valid*/
1849 if (klass
->byval_arg
.type
== MONO_TYPE_ARRAY
|| klass
->byval_arg
.type
== MONO_TYPE_SZARRAY
) {
1850 MonoClass
*element_class
= klass
->element_class
;
1851 if (!element_class
->inited
)
1852 mono_class_init (element_class
);
1854 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1855 if (!mono_class_has_failure (element_class
) && !element_class
->vtable_size
)
1856 mono_class_setup_vtable (element_class
);
1858 if (mono_class_has_failure (element_class
)) {
1859 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1860 if (!mono_class_has_failure (klass
))
1861 mono_class_set_type_load_failure (klass
, "");
1862 mono_domain_unlock (domain
);
1863 mono_loader_unlock ();
1864 mono_error_set_for_class_failure (error
, klass
);
1870 * For some classes, mono_class_init () already computed klass->vtable_size, and
1871 * that is all that is needed because of the vtable trampolines.
1873 if (!klass
->vtable_size
)
1874 mono_class_setup_vtable (klass
);
1876 if (mono_class_is_ginst (klass
) && !klass
->vtable
)
1877 mono_class_check_vtable_constraints (klass
, NULL
);
1879 /* Initialize klass->has_finalize */
1880 mono_class_has_finalizer (klass
);
1882 if (mono_class_has_failure (klass
)) {
1883 mono_domain_unlock (domain
);
1884 mono_loader_unlock ();
1885 mono_error_set_for_class_failure (error
, klass
);
1889 vtable_slots
= klass
->vtable_size
;
1890 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1891 class_size
= mono_class_data_size (klass
);
1895 if (klass
->interface_offsets_count
) {
1896 imt_table_bytes
= sizeof (gpointer
) * (MONO_IMT_SIZE
);
1897 mono_stats
.imt_number_of_tables
++;
1898 mono_stats
.imt_tables_size
+= imt_table_bytes
;
1900 imt_table_bytes
= 0;
1903 vtable_size
= imt_table_bytes
+ MONO_SIZEOF_VTABLE
+ vtable_slots
* sizeof (gpointer
);
1905 mono_stats
.used_class_count
++;
1906 mono_stats
.class_vtable_size
+= vtable_size
;
1908 interface_offsets
= alloc_vtable (domain
, vtable_size
, imt_table_bytes
);
1909 vt
= (MonoVTable
*) ((char*)interface_offsets
+ imt_table_bytes
);
1910 g_assert (!((gsize
)vt
& 7));
1913 vt
->rank
= klass
->rank
;
1914 vt
->domain
= domain
;
1916 mono_class_compute_gc_descriptor (klass
);
1918 * We can't use typed allocation in the non-root domains, since the
1919 * collector needs the GC descriptor stored in the vtable even after
1920 * the mempool containing the vtable is destroyed when the domain is
1921 * unloaded. An alternative might be to allocate vtables in the GC
1922 * heap, but this does not seem to work (it leads to crashes inside
1923 * libgc). If that approach is tried, two gc descriptors need to be
1924 * allocated for each class: one for the root domain, and one for all
1925 * other domains. The second descriptor should contain a bit for the
1926 * vtable field in MonoObject, since we can no longer assume the
1927 * vtable is reachable by other roots after the appdomain is unloaded.
1929 #ifdef HAVE_BOEHM_GC
1930 if (domain
!= mono_get_root_domain () && !mono_dont_free_domains
)
1931 vt
->gc_descr
= MONO_GC_DESCRIPTOR_NULL
;
1934 vt
->gc_descr
= klass
->gc_descr
;
1936 gc_bits
= mono_gc_get_vtable_bits (klass
);
1937 g_assert (!(gc_bits
& ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS
) - 1)));
1939 vt
->gc_bits
= gc_bits
;
1942 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1943 if (klass
->has_static_refs
) {
1944 MonoGCDescriptor statics_gc_descr
;
1946 gsize default_bitmap
[4] = {0};
1949 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, TRUE
);
1950 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1951 statics_gc_descr
= mono_gc_make_descr_from_bitmap (bitmap
, max_set
+ 1);
1952 vt
->vtable
[klass
->vtable_size
] = mono_gc_alloc_fixed (class_size
, statics_gc_descr
, MONO_ROOT_SOURCE_STATIC
, "managed static variables");
1953 mono_domain_add_class_static_data (domain
, klass
, vt
->vtable
[klass
->vtable_size
], NULL
);
1954 if (bitmap
!= default_bitmap
)
1957 vt
->vtable
[klass
->vtable_size
] = mono_domain_alloc0 (domain
, class_size
);
1959 vt
->has_static_fields
= TRUE
;
1960 mono_stats
.class_static_data_size
+= class_size
;
1964 while ((field
= mono_class_get_fields (klass
, &iter
))) {
1965 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
1967 if (mono_field_is_deleted (field
))
1969 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
1970 gint32 special_static
= klass
->no_special_static_fields
? SPECIAL_STATIC_NONE
: field_is_special_static (klass
, field
);
1971 if (special_static
!= SPECIAL_STATIC_NONE
) {
1972 guint32 size
, offset
;
1974 gsize default_bitmap
[4] = {0};
1979 if (mono_type_is_reference (field
->type
)) {
1980 default_bitmap
[0] = 1;
1982 bitmap
= default_bitmap
;
1983 } else if (mono_type_is_struct (field
->type
)) {
1984 fclass
= mono_class_from_mono_type (field
->type
);
1985 bitmap
= compute_class_bitmap (fclass
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(sizeof (MonoObject
) / sizeof (gpointer
)), &max_set
, FALSE
);
1986 numbits
= max_set
+ 1;
1988 default_bitmap
[0] = 0;
1990 bitmap
= default_bitmap
;
1992 size
= mono_type_size (field
->type
, &align
);
1993 offset
= mono_alloc_special_static_data (special_static
, size
, align
, (uintptr_t*)bitmap
, numbits
);
1994 if (!domain
->special_static_fields
)
1995 domain
->special_static_fields
= g_hash_table_new (NULL
, NULL
);
1996 g_hash_table_insert (domain
->special_static_fields
, field
, GUINT_TO_POINTER (offset
));
1997 if (bitmap
!= default_bitmap
)
2000 * This marks the field as special static to speed up the
2001 * checks in mono_field_static_get/set_value ().
2007 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_RVA
)) {
2008 MonoClass
*fklass
= mono_class_from_mono_type (field
->type
);
2009 const char *data
= mono_field_get_data (field
);
2011 g_assert (!(field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_DEFAULT
));
2012 t
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
2013 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2016 if (fklass
->valuetype
) {
2017 memcpy (t
, data
, mono_class_value_size (fklass
, NULL
));
2019 /* it's a pointer type: add check */
2020 g_assert ((fklass
->byval_arg
.type
== MONO_TYPE_PTR
) || (fklass
->byval_arg
.type
== MONO_TYPE_FNPTR
));
2027 vt
->max_interface_id
= klass
->max_interface_id
;
2028 vt
->interface_bitmap
= klass
->interface_bitmap
;
2030 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2031 // class->name, klass->interface_offsets_count);
2033 /* Initialize vtable */
2034 if (callbacks
.get_vtable_trampoline
) {
2035 // This also covers the AOT case
2036 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2037 vt
->vtable
[i
] = callbacks
.get_vtable_trampoline (vt
, i
);
2040 mono_class_setup_vtable (klass
);
2042 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2045 cm
= klass
->vtable
[i
];
2047 vt
->vtable
[i
] = callbacks
.create_jit_trampoline (domain
, cm
, error
);
2048 if (!is_ok (error
)) {
2049 mono_domain_unlock (domain
);
2050 mono_loader_unlock ();
2057 if (imt_table_bytes
) {
2058 /* Now that the vtable is full, we can actually fill up the IMT */
2059 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
)
2060 interface_offsets
[i
] = callbacks
.get_imt_trampoline (vt
, i
);
2064 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2065 * re-acquire them and check if another thread has created the vtable in the meantime.
2067 /* Special case System.MonoType to avoid infinite recursion */
2068 if (klass
!= mono_defaults
.runtimetype_class
) {
2069 vt
->type
= mono_type_get_object_checked (domain
, &klass
->byval_arg
, error
);
2070 if (!is_ok (error
)) {
2071 mono_domain_unlock (domain
);
2072 mono_loader_unlock ();
2076 if (mono_object_get_class ((MonoObject
*)vt
->type
) != mono_defaults
.runtimetype_class
)
2077 /* This is unregistered in
2078 unregister_vtable_reflection_type() in
2080 MONO_GC_REGISTER_ROOT_IF_MOVING(vt
->type
, MONO_ROOT_SOURCE_REFLECTION
, "vtable reflection type");
2083 mono_vtable_set_is_remote (vt
, mono_class_is_contextbound (klass
));
2085 /* class_vtable_array keeps an array of created vtables
2087 g_ptr_array_add (domain
->class_vtable_array
, vt
);
2088 /* klass->runtime_info is protected by the loader lock, both when
2089 * it it enlarged and when it is stored info.
2093 * Store the vtable in klass->runtime_info.
2094 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2096 mono_memory_barrier ();
2098 old_info
= klass
->runtime_info
;
2099 if (old_info
&& old_info
->max_domain
>= domain
->domain_id
) {
2100 /* someone already created a large enough runtime info */
2101 old_info
->domain_vtables
[domain
->domain_id
] = vt
;
2103 int new_size
= domain
->domain_id
;
2105 new_size
= MAX (new_size
, old_info
->max_domain
);
2107 /* make the new size a power of two */
2109 while (new_size
> i
)
2112 /* this is a bounded memory retention issue: may want to
2113 * handle it differently when we'll have a rcu-like system.
2115 runtime_info
= (MonoClassRuntimeInfo
*)mono_image_alloc0 (klass
->image
, MONO_SIZEOF_CLASS_RUNTIME_INFO
+ new_size
* sizeof (gpointer
));
2116 runtime_info
->max_domain
= new_size
- 1;
2117 /* copy the stuff from the older info */
2119 memcpy (runtime_info
->domain_vtables
, old_info
->domain_vtables
, (old_info
->max_domain
+ 1) * sizeof (gpointer
));
2121 runtime_info
->domain_vtables
[domain
->domain_id
] = vt
;
2123 mono_memory_barrier ();
2124 klass
->runtime_info
= runtime_info
;
2127 if (klass
== mono_defaults
.runtimetype_class
) {
2128 vt
->type
= mono_type_get_object_checked (domain
, &klass
->byval_arg
, error
);
2129 if (!is_ok (error
)) {
2130 mono_domain_unlock (domain
);
2131 mono_loader_unlock ();
2135 if (mono_object_get_class ((MonoObject
*)vt
->type
) != mono_defaults
.runtimetype_class
)
2136 /* This is unregistered in
2137 unregister_vtable_reflection_type() in
2139 MONO_GC_REGISTER_ROOT_IF_MOVING(vt
->type
, MONO_ROOT_SOURCE_REFLECTION
, "vtable reflection type");
2142 mono_domain_unlock (domain
);
2143 mono_loader_unlock ();
2145 /* make sure the parent is initialized */
2146 /*FIXME shouldn't this fail the current type?*/
2148 mono_class_vtable_full (domain
, klass
->parent
, error
);
2153 #ifndef DISABLE_REMOTING
2155 * mono_class_proxy_vtable:
2156 * @domain: the application domain
2157 * @remove_class: the remote class
2158 * @error: set on error
2160 * Creates a vtable for transparent proxies. It is basically
2161 * a copy of the real vtable of the class wrapped in @remote_class,
2162 * but all function pointers invoke the remoting functions, and
2163 * vtable->klass points to the transparent proxy class, and not to @class.
2165 * On failure returns NULL and sets @error
2168 mono_class_proxy_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRemotingTarget target_type
, MonoError
*error
)
2170 MONO_REQ_GC_UNSAFE_MODE
;
2172 MonoVTable
*vt
, *pvt
;
2173 int i
, j
, vtsize
, extra_interface_vtsize
= 0;
2174 guint32 max_interface_id
;
2176 GSList
*extra_interfaces
= NULL
;
2177 MonoClass
*klass
= remote_class
->proxy_class
;
2178 gpointer
*interface_offsets
;
2179 uint8_t *bitmap
= NULL
;
2181 size_t imt_table_bytes
;
2183 #ifdef COMPRESSED_INTERFACE_BITMAP
2187 mono_error_init (error
);
2189 vt
= mono_class_vtable (domain
, klass
);
2190 g_assert (vt
); /*FIXME property handle failure*/
2191 max_interface_id
= vt
->max_interface_id
;
2193 /* Calculate vtable space for extra interfaces */
2194 for (j
= 0; j
< remote_class
->interface_count
; j
++) {
2195 MonoClass
* iclass
= remote_class
->interfaces
[j
];
2199 /*FIXME test for interfaces with variant generic arguments*/
2200 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, iclass
->interface_id
))
2201 continue; /* interface implemented by the class */
2202 if (g_slist_find (extra_interfaces
, iclass
))
2205 extra_interfaces
= g_slist_prepend (extra_interfaces
, iclass
);
2207 method_count
= mono_class_num_methods (iclass
);
2209 ifaces
= mono_class_get_implemented_interfaces (iclass
, error
);
2213 for (i
= 0; i
< ifaces
->len
; ++i
) {
2214 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2215 /*FIXME test for interfaces with variant generic arguments*/
2216 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, ic
->interface_id
))
2217 continue; /* interface implemented by the class */
2218 if (g_slist_find (extra_interfaces
, ic
))
2220 extra_interfaces
= g_slist_prepend (extra_interfaces
, ic
);
2221 method_count
+= mono_class_num_methods (ic
);
2223 g_ptr_array_free (ifaces
, TRUE
);
2227 extra_interface_vtsize
+= method_count
* sizeof (gpointer
);
2228 if (iclass
->max_interface_id
> max_interface_id
) max_interface_id
= iclass
->max_interface_id
;
2231 imt_table_bytes
= sizeof (gpointer
) * MONO_IMT_SIZE
;
2232 mono_stats
.imt_number_of_tables
++;
2233 mono_stats
.imt_tables_size
+= imt_table_bytes
;
2235 vtsize
= imt_table_bytes
+ MONO_SIZEOF_VTABLE
+ klass
->vtable_size
* sizeof (gpointer
);
2237 mono_stats
.class_vtable_size
+= vtsize
+ extra_interface_vtsize
;
2239 interface_offsets
= alloc_vtable (domain
, vtsize
+ extra_interface_vtsize
, imt_table_bytes
);
2240 pvt
= (MonoVTable
*) ((char*)interface_offsets
+ imt_table_bytes
);
2241 g_assert (!((gsize
)pvt
& 7));
2243 memcpy (pvt
, vt
, MONO_SIZEOF_VTABLE
+ klass
->vtable_size
* sizeof (gpointer
));
2245 pvt
->klass
= mono_defaults
.transparent_proxy_class
;
2246 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2247 pvt
->gc_descr
= mono_defaults
.transparent_proxy_class
->gc_descr
;
2249 /* initialize vtable */
2250 mono_class_setup_vtable (klass
);
2251 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2254 if ((cm
= klass
->vtable
[i
])) {
2255 pvt
->vtable
[i
] = create_remoting_trampoline (domain
, cm
, target_type
, error
);
2259 pvt
->vtable
[i
] = NULL
;
2262 if (mono_class_is_abstract (klass
)) {
2263 /* create trampolines for abstract methods */
2264 for (k
= klass
; k
; k
= k
->parent
) {
2266 gpointer iter
= NULL
;
2267 while ((m
= mono_class_get_methods (k
, &iter
)))
2268 if (!pvt
->vtable
[m
->slot
]) {
2269 pvt
->vtable
[m
->slot
] = create_remoting_trampoline (domain
, m
, target_type
, error
);
2276 pvt
->max_interface_id
= max_interface_id
;
2277 bsize
= sizeof (guint8
) * (max_interface_id
/8 + 1 );
2278 #ifdef COMPRESSED_INTERFACE_BITMAP
2279 bitmap
= (uint8_t *)g_malloc0 (bsize
);
2281 bitmap
= (uint8_t *)mono_domain_alloc0 (domain
, bsize
);
2284 for (i
= 0; i
< klass
->interface_offsets_count
; ++i
) {
2285 int interface_id
= klass
->interfaces_packed
[i
]->interface_id
;
2286 bitmap
[interface_id
>> 3] |= (1 << (interface_id
& 7));
2289 if (extra_interfaces
) {
2290 int slot
= klass
->vtable_size
;
2296 /* Create trampolines for the methods of the interfaces */
2297 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
2298 interf
= (MonoClass
*)list_item
->data
;
2300 bitmap
[interf
->interface_id
>> 3] |= (1 << (interf
->interface_id
& 7));
2304 while ((cm
= mono_class_get_methods (interf
, &iter
))) {
2305 pvt
->vtable
[slot
+ j
++] = create_remoting_trampoline (domain
, cm
, target_type
, error
);
2310 slot
+= mono_class_num_methods (interf
);
2314 /* Now that the vtable is full, we can actually fill up the IMT */
2315 build_imt (klass
, pvt
, domain
, interface_offsets
, extra_interfaces
);
2316 if (extra_interfaces
) {
2317 g_slist_free (extra_interfaces
);
2320 #ifdef COMPRESSED_INTERFACE_BITMAP
2321 bcsize
= mono_compress_bitmap (NULL
, bitmap
, bsize
);
2322 pvt
->interface_bitmap
= mono_domain_alloc0 (domain
, bcsize
);
2323 mono_compress_bitmap (pvt
->interface_bitmap
, bitmap
, bsize
);
2326 pvt
->interface_bitmap
= bitmap
;
2330 if (extra_interfaces
)
2331 g_slist_free (extra_interfaces
);
2332 #ifdef COMPRESSED_INTERFACE_BITMAP
2338 #endif /* DISABLE_REMOTING */
2341 * mono_class_field_is_special_static:
2343 * Returns whether @field is a thread/context static field.
2346 mono_class_field_is_special_static (MonoClassField
*field
)
2348 MONO_REQ_GC_NEUTRAL_MODE
2350 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2352 if (mono_field_is_deleted (field
))
2354 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
2355 if (field_is_special_static (field
->parent
, field
) != SPECIAL_STATIC_NONE
)
2362 * mono_class_field_get_special_static_type:
2363 * @field: The MonoClassField describing the field.
2365 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2366 * SPECIAL_STATIC_NONE otherwise.
2369 mono_class_field_get_special_static_type (MonoClassField
*field
)
2371 MONO_REQ_GC_NEUTRAL_MODE
2373 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2374 return SPECIAL_STATIC_NONE
;
2375 if (mono_field_is_deleted (field
))
2376 return SPECIAL_STATIC_NONE
;
2377 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
2378 return field_is_special_static (field
->parent
, field
);
2379 return SPECIAL_STATIC_NONE
;
2383 * mono_class_has_special_static_fields:
2385 * Returns whenever @klass has any thread/context static fields.
2388 mono_class_has_special_static_fields (MonoClass
*klass
)
2390 MONO_REQ_GC_NEUTRAL_MODE
2392 MonoClassField
*field
;
2396 while ((field
= mono_class_get_fields (klass
, &iter
))) {
2397 g_assert (field
->parent
== klass
);
2398 if (mono_class_field_is_special_static (field
))
2405 #ifndef DISABLE_REMOTING
2407 * create_remote_class_key:
2408 * Creates an array of pointers that can be used as a hash key for a remote class.
2409 * The first element of the array is the number of pointers.
2412 create_remote_class_key (MonoRemoteClass
*remote_class
, MonoClass
*extra_class
)
2414 MONO_REQ_GC_NEUTRAL_MODE
;
2419 if (remote_class
== NULL
) {
2420 if (mono_class_is_interface (extra_class
)) {
2421 key
= (void **)g_malloc (sizeof(gpointer
) * 3);
2422 key
[0] = GINT_TO_POINTER (2);
2423 key
[1] = mono_defaults
.marshalbyrefobject_class
;
2424 key
[2] = extra_class
;
2426 key
= (void **)g_malloc (sizeof(gpointer
) * 2);
2427 key
[0] = GINT_TO_POINTER (1);
2428 key
[1] = extra_class
;
2431 if (extra_class
!= NULL
&& mono_class_is_interface (extra_class
)) {
2432 key
= (void **)g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 3));
2433 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 2);
2434 key
[1] = remote_class
->proxy_class
;
2436 // Keep the list of interfaces sorted
2437 for (i
= 0, j
= 2; i
< remote_class
->interface_count
; i
++, j
++) {
2438 if (extra_class
&& remote_class
->interfaces
[i
] > extra_class
) {
2439 key
[j
++] = extra_class
;
2442 key
[j
] = remote_class
->interfaces
[i
];
2445 key
[j
] = extra_class
;
2447 // Replace the old class. The interface list is the same
2448 key
= (void **)g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 2));
2449 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 1);
2450 key
[1] = extra_class
!= NULL
? extra_class
: remote_class
->proxy_class
;
2451 for (i
= 0; i
< remote_class
->interface_count
; i
++)
2452 key
[2 + i
] = remote_class
->interfaces
[i
];
2460 * copy_remote_class_key:
2462 * Make a copy of KEY in the domain and return the copy.
2465 copy_remote_class_key (MonoDomain
*domain
, gpointer
*key
)
2467 MONO_REQ_GC_NEUTRAL_MODE
2469 int key_size
= (GPOINTER_TO_UINT (key
[0]) + 1) * sizeof (gpointer
);
2470 gpointer
*mp_key
= (gpointer
*)mono_domain_alloc (domain
, key_size
);
2472 memcpy (mp_key
, key
, key_size
);
2478 * mono_remote_class:
2479 * @domain: the application domain
2480 * @class_name: name of the remote class
2481 * @error: set on error
2483 * Creates and initializes a MonoRemoteClass object for a remote type.
2485 * On failure returns NULL and sets @error
2488 mono_remote_class (MonoDomain
*domain
, MonoString
*class_name
, MonoClass
*proxy_class
, MonoError
*error
)
2490 MONO_REQ_GC_UNSAFE_MODE
;
2492 MonoRemoteClass
*rc
;
2493 gpointer
* key
, *mp_key
;
2496 mono_error_init (error
);
2498 key
= create_remote_class_key (NULL
, proxy_class
);
2500 mono_domain_lock (domain
);
2501 rc
= (MonoRemoteClass
*)g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2505 mono_domain_unlock (domain
);
2509 name
= mono_string_to_utf8_mp (domain
->mp
, class_name
, error
);
2510 if (!is_ok (error
)) {
2512 mono_domain_unlock (domain
);
2516 mp_key
= copy_remote_class_key (domain
, key
);
2520 if (mono_class_is_interface (proxy_class
)) {
2521 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*));
2522 rc
->interface_count
= 1;
2523 rc
->interfaces
[0] = proxy_class
;
2524 rc
->proxy_class
= mono_defaults
.marshalbyrefobject_class
;
2526 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
);
2527 rc
->interface_count
= 0;
2528 rc
->proxy_class
= proxy_class
;
2531 rc
->default_vtable
= NULL
;
2532 rc
->xdomain_vtable
= NULL
;
2533 rc
->proxy_class_name
= name
;
2534 #ifndef DISABLE_PERFCOUNTERS
2535 mono_perfcounters
->loader_bytes
+= mono_string_length (class_name
) + 1;
2538 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2540 mono_domain_unlock (domain
);
2545 * clone_remote_class:
2546 * Creates a copy of the remote_class, adding the provided class or interface
2548 static MonoRemoteClass
*
2549 clone_remote_class (MonoDomain
*domain
, MonoRemoteClass
* remote_class
, MonoClass
*extra_class
)
2551 MONO_REQ_GC_NEUTRAL_MODE
;
2553 MonoRemoteClass
*rc
;
2554 gpointer
* key
, *mp_key
;
2556 key
= create_remote_class_key (remote_class
, extra_class
);
2557 rc
= (MonoRemoteClass
*)g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2563 mp_key
= copy_remote_class_key (domain
, key
);
2567 if (mono_class_is_interface (extra_class
)) {
2569 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * (remote_class
->interface_count
+ 1));
2570 rc
->proxy_class
= remote_class
->proxy_class
;
2571 rc
->interface_count
= remote_class
->interface_count
+ 1;
2573 // Keep the list of interfaces sorted, since the hash key of
2574 // the remote class depends on this
2575 for (i
= 0, j
= 0; i
< remote_class
->interface_count
; i
++, j
++) {
2576 if (remote_class
->interfaces
[i
] > extra_class
&& i
== j
)
2577 rc
->interfaces
[j
++] = extra_class
;
2578 rc
->interfaces
[j
] = remote_class
->interfaces
[i
];
2581 rc
->interfaces
[j
] = extra_class
;
2583 // Replace the old class. The interface array is the same
2584 rc
= (MonoRemoteClass
*)mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * remote_class
->interface_count
);
2585 rc
->proxy_class
= extra_class
;
2586 rc
->interface_count
= remote_class
->interface_count
;
2587 if (rc
->interface_count
> 0)
2588 memcpy (rc
->interfaces
, remote_class
->interfaces
, rc
->interface_count
* sizeof (MonoClass
*));
2591 rc
->default_vtable
= NULL
;
2592 rc
->xdomain_vtable
= NULL
;
2593 rc
->proxy_class_name
= remote_class
->proxy_class_name
;
2595 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2601 mono_remote_class_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRealProxy
*rp
, MonoError
*error
)
2603 MONO_REQ_GC_UNSAFE_MODE
;
2605 mono_error_init (error
);
2607 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2608 mono_domain_lock (domain
);
2609 if (rp
->target_domain_id
!= -1) {
2610 if (remote_class
->xdomain_vtable
== NULL
)
2611 remote_class
->xdomain_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_APPDOMAIN
, error
);
2612 mono_domain_unlock (domain
);
2613 mono_loader_unlock ();
2614 return_val_if_nok (error
, NULL
);
2615 return remote_class
->xdomain_vtable
;
2617 if (remote_class
->default_vtable
== NULL
) {
2620 type
= ((MonoReflectionType
*)rp
->class_to_proxy
)->type
;
2621 klass
= mono_class_from_mono_type (type
);
2623 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
)))
2624 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_COMINTEROP
, error
);
2627 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_UNKNOWN
, error
);
2628 /* N.B. both branches of the if modify error */
2629 if (!is_ok (error
)) {
2630 mono_domain_unlock (domain
);
2631 mono_loader_unlock ();
2636 mono_domain_unlock (domain
);
2637 mono_loader_unlock ();
2638 return remote_class
->default_vtable
;
2642 * mono_upgrade_remote_class:
2643 * @domain: the application domain
2644 * @tproxy: the proxy whose remote class has to be upgraded.
2645 * @klass: class to which the remote class can be casted.
2646 * @error: set on error
2648 * Updates the vtable of the remote class by adding the necessary method slots
2649 * and interface offsets so it can be safely casted to klass. klass can be a
2650 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2653 mono_upgrade_remote_class (MonoDomain
*domain
, MonoObject
*proxy_object
, MonoClass
*klass
, MonoError
*error
)
2655 MONO_REQ_GC_UNSAFE_MODE
;
2657 MonoTransparentProxy
*tproxy
;
2658 MonoRemoteClass
*remote_class
;
2659 gboolean redo_vtable
;
2661 mono_error_init (error
);
2662 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2663 mono_domain_lock (domain
);
2665 tproxy
= (MonoTransparentProxy
*) proxy_object
;
2666 remote_class
= tproxy
->remote_class
;
2668 if (mono_class_is_interface (klass
)) {
2671 for (i
= 0; i
< remote_class
->interface_count
&& redo_vtable
; i
++)
2672 if (remote_class
->interfaces
[i
] == klass
)
2673 redo_vtable
= FALSE
;
2676 redo_vtable
= (remote_class
->proxy_class
!= klass
);
2680 tproxy
->remote_class
= clone_remote_class (domain
, remote_class
, klass
);
2681 proxy_object
->vtable
= (MonoVTable
*)mono_remote_class_vtable (domain
, tproxy
->remote_class
, tproxy
->rp
, error
);
2687 mono_domain_unlock (domain
);
2688 mono_loader_unlock ();
2689 return is_ok (error
);
2691 #endif /* DISABLE_REMOTING */
2695 * mono_object_get_virtual_method:
2696 * @obj: object to operate on.
2699 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2700 * the instance of a callvirt of method.
2703 mono_object_get_virtual_method (MonoObject
*obj
, MonoMethod
*method
)
2705 MONO_REQ_GC_UNSAFE_MODE
;
2708 MonoMethod
**vtable
;
2709 gboolean is_proxy
= FALSE
;
2710 MonoMethod
*res
= NULL
;
2712 klass
= mono_object_class (obj
);
2713 #ifndef DISABLE_REMOTING
2714 if (klass
== mono_defaults
.transparent_proxy_class
) {
2715 klass
= ((MonoTransparentProxy
*)obj
)->remote_class
->proxy_class
;
2720 if (!is_proxy
&& ((method
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)))
2723 mono_class_setup_vtable (klass
);
2724 vtable
= klass
->vtable
;
2726 if (method
->slot
== -1) {
2727 /* method->slot might not be set for instances of generic methods */
2728 if (method
->is_inflated
) {
2729 g_assert (((MonoMethodInflated
*)method
)->declaring
->slot
!= -1);
2730 method
->slot
= ((MonoMethodInflated
*)method
)->declaring
->slot
;
2733 g_assert_not_reached ();
2737 /* check method->slot is a valid index: perform isinstance? */
2738 if (method
->slot
!= -1) {
2739 if (mono_class_is_interface (method
->klass
)) {
2741 gboolean variance_used
= FALSE
;
2742 int iface_offset
= mono_class_interface_offset_with_variance (klass
, method
->klass
, &variance_used
);
2743 g_assert (iface_offset
> 0);
2744 res
= vtable
[iface_offset
+ method
->slot
];
2747 res
= vtable
[method
->slot
];
2751 #ifndef DISABLE_REMOTING
2753 /* It may be an interface, abstract class method or generic method */
2754 if (!res
|| mono_method_signature (res
)->generic_param_count
)
2757 /* generic methods demand invoke_with_check */
2758 if (mono_method_signature (res
)->generic_param_count
)
2759 res
= mono_marshal_get_remoting_invoke_with_check (res
);
2762 if (klass
== mono_class_get_com_object_class () || mono_class_is_com_object (klass
))
2763 res
= mono_cominterop_get_invoke (res
);
2766 res
= mono_marshal_get_remoting_invoke (res
);
2771 if (method
->is_inflated
) {
2773 /* Have to inflate the result */
2774 res
= mono_class_inflate_generic_method_checked (res
, &((MonoMethodInflated
*)method
)->context
, &error
);
2775 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2785 do_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
*error
)
2787 MONO_REQ_GC_UNSAFE_MODE
;
2789 MonoObject
*result
= NULL
;
2791 g_assert (callbacks
.runtime_invoke
);
2793 mono_error_init (error
);
2795 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS
)
2796 mono_profiler_method_start_invoke (method
);
2798 result
= callbacks
.runtime_invoke (method
, obj
, params
, exc
, error
);
2800 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS
)
2801 mono_profiler_method_end_invoke (method
);
2803 if (!mono_error_ok (error
))
2810 * mono_runtime_invoke:
2811 * @method: method to invoke
2812 * @obJ: object instance
2813 * @params: arguments to the method
2814 * @exc: exception information.
2816 * Invokes the method represented by @method on the object @obj.
2818 * obj is the 'this' pointer, it should be NULL for static
2819 * methods, a MonoObject* for object instances and a pointer to
2820 * the value type for value types.
2822 * The params array contains the arguments to the method with the
2823 * same convention: MonoObject* pointers for object instances and
2824 * pointers to the value type otherwise.
2826 * From unmanaged code you'll usually use the
2827 * mono_runtime_invoke() variant.
2829 * Note that this function doesn't handle virtual methods for
2830 * you, it will exec the exact method you pass: we still need to
2831 * expose a function to lookup the derived class implementation
2832 * of a virtual method (there are examples of this in the code,
2835 * You can pass NULL as the exc argument if you don't want to
2836 * catch exceptions, otherwise, *exc will be set to the exception
2837 * thrown, if any. if an exception is thrown, you can't use the
2838 * MonoObject* result from the function.
2840 * If the method returns a value type, it is boxed in an object
2844 mono_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
2849 res
= mono_runtime_try_invoke (method
, obj
, params
, exc
, &error
);
2850 if (*exc
== NULL
&& !mono_error_ok(&error
)) {
2851 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
2853 mono_error_cleanup (&error
);
2855 res
= mono_runtime_invoke_checked (method
, obj
, params
, &error
);
2856 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
2862 * mono_runtime_try_invoke:
2863 * @method: method to invoke
2864 * @obJ: object instance
2865 * @params: arguments to the method
2866 * @exc: exception information.
2867 * @error: set on error
2869 * Invokes the method represented by @method on the object @obj.
2871 * obj is the 'this' pointer, it should be NULL for static
2872 * methods, a MonoObject* for object instances and a pointer to
2873 * the value type for value types.
2875 * The params array contains the arguments to the method with the
2876 * same convention: MonoObject* pointers for object instances and
2877 * pointers to the value type otherwise.
2879 * From unmanaged code you'll usually use the
2880 * mono_runtime_invoke() variant.
2882 * Note that this function doesn't handle virtual methods for
2883 * you, it will exec the exact method you pass: we still need to
2884 * expose a function to lookup the derived class implementation
2885 * of a virtual method (there are examples of this in the code,
2888 * For this function, you must not pass NULL as the exc argument if
2889 * you don't want to catch exceptions, use
2890 * mono_runtime_invoke_checked(). If an exception is thrown, you
2891 * can't use the MonoObject* result from the function.
2893 * If this method cannot be invoked, @error will be set and @exc and
2894 * the return value must not be used.
2896 * If the method returns a value type, it is boxed in an object
2900 mono_runtime_try_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
, MonoError
* error
)
2902 MONO_REQ_GC_UNSAFE_MODE
;
2904 g_assert (exc
!= NULL
);
2906 if (mono_runtime_get_no_exec ())
2907 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method
, TRUE
));
2909 return do_runtime_invoke (method
, obj
, params
, exc
, error
);
2913 * mono_runtime_invoke_checked:
2914 * @method: method to invoke
2915 * @obJ: object instance
2916 * @params: arguments to the method
2917 * @error: set on error
2919 * Invokes the method represented by @method on the object @obj.
2921 * obj is the 'this' pointer, it should be NULL for static
2922 * methods, a MonoObject* for object instances and a pointer to
2923 * the value type for value types.
2925 * The params array contains the arguments to the method with the
2926 * same convention: MonoObject* pointers for object instances and
2927 * pointers to the value type otherwise.
2929 * From unmanaged code you'll usually use the
2930 * mono_runtime_invoke() variant.
2932 * Note that this function doesn't handle virtual methods for
2933 * you, it will exec the exact method you pass: we still need to
2934 * expose a function to lookup the derived class implementation
2935 * of a virtual method (there are examples of this in the code,
2938 * If an exception is thrown, you can't use the MonoObject* result
2939 * from the function.
2941 * If this method cannot be invoked, @error will be set. If the
2942 * method throws an exception (and we're in coop mode) the exception
2943 * will be set in @error.
2945 * If the method returns a value type, it is boxed in an object
2949 mono_runtime_invoke_checked (MonoMethod
*method
, void *obj
, void **params
, MonoError
* error
)
2951 MONO_REQ_GC_UNSAFE_MODE
;
2953 if (mono_runtime_get_no_exec ())
2954 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method
, TRUE
));
2956 return do_runtime_invoke (method
, obj
, params
, NULL
, error
);
2960 * mono_method_get_unmanaged_thunk:
2961 * @method: method to generate a thunk for.
2963 * Returns an unmanaged->managed thunk that can be used to call
2964 * a managed method directly from C.
2966 * The thunk's C signature closely matches the managed signature:
2968 * C#: public bool Equals (object obj);
2969 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2970 * MonoObject*, MonoException**);
2972 * The 1st ("this") parameter must not be used with static methods:
2974 * C#: public static bool ReferenceEquals (object a, object b);
2975 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2978 * The last argument must be a non-null pointer of a MonoException* pointer.
2979 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2980 * exception has been thrown in managed code. Otherwise it will point
2981 * to the MonoException* caught by the thunk. In this case, the result of
2982 * the thunk is undefined:
2984 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2985 * MonoException *ex = NULL;
2986 * Equals func = mono_method_get_unmanaged_thunk (method);
2987 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2989 * // handle exception
2992 * The calling convention of the thunk matches the platform's default
2993 * convention. This means that under Windows, C declarations must
2994 * contain the __stdcall attribute:
2996 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2997 * MonoObject*, MonoException**);
3001 * Value type arguments and return values are treated as they were objects:
3003 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3004 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3006 * Arguments must be properly boxed upon trunk's invocation, while return
3007 * values must be unboxed.
3010 mono_method_get_unmanaged_thunk (MonoMethod
*method
)
3012 MONO_REQ_GC_NEUTRAL_MODE
;
3013 MONO_REQ_API_ENTRYPOINT
;
3018 g_assert (!mono_threads_is_coop_enabled ());
3020 MONO_ENTER_GC_UNSAFE
;
3021 method
= mono_marshal_get_thunk_invoke_wrapper (method
);
3022 res
= mono_compile_method_checked (method
, &error
);
3023 mono_error_cleanup (&error
);
3024 MONO_EXIT_GC_UNSAFE
;
3030 mono_copy_value (MonoType
*type
, void *dest
, void *value
, int deref_pointer
)
3032 MONO_REQ_GC_UNSAFE_MODE
;
3036 /* object fields cannot be byref, so we don't need a
3038 gpointer
*p
= (gpointer
*)dest
;
3045 case MONO_TYPE_BOOLEAN
:
3047 case MONO_TYPE_U1
: {
3048 guint8
*p
= (guint8
*)dest
;
3049 *p
= value
? *(guint8
*)value
: 0;
3054 case MONO_TYPE_CHAR
: {
3055 guint16
*p
= (guint16
*)dest
;
3056 *p
= value
? *(guint16
*)value
: 0;
3059 #if SIZEOF_VOID_P == 4
3064 case MONO_TYPE_U4
: {
3065 gint32
*p
= (gint32
*)dest
;
3066 *p
= value
? *(gint32
*)value
: 0;
3069 #if SIZEOF_VOID_P == 8
3074 case MONO_TYPE_U8
: {
3075 gint64
*p
= (gint64
*)dest
;
3076 *p
= value
? *(gint64
*)value
: 0;
3079 case MONO_TYPE_R4
: {
3080 float *p
= (float*)dest
;
3081 *p
= value
? *(float*)value
: 0;
3084 case MONO_TYPE_R8
: {
3085 double *p
= (double*)dest
;
3086 *p
= value
? *(double*)value
: 0;
3089 case MONO_TYPE_STRING
:
3090 case MONO_TYPE_SZARRAY
:
3091 case MONO_TYPE_CLASS
:
3092 case MONO_TYPE_OBJECT
:
3093 case MONO_TYPE_ARRAY
:
3094 mono_gc_wbarrier_generic_store (dest
, deref_pointer
? *(MonoObject
**)value
: (MonoObject
*)value
);
3096 case MONO_TYPE_FNPTR
:
3097 case MONO_TYPE_PTR
: {
3098 gpointer
*p
= (gpointer
*)dest
;
3099 *p
= deref_pointer
? *(gpointer
*)value
: value
;
3102 case MONO_TYPE_VALUETYPE
:
3103 /* note that 't' and 'type->type' can be different */
3104 if (type
->type
== MONO_TYPE_VALUETYPE
&& type
->data
.klass
->enumtype
) {
3105 t
= mono_class_enum_basetype (type
->data
.klass
)->type
;
3108 MonoClass
*klass
= mono_class_from_mono_type (type
);
3109 int size
= mono_class_value_size (klass
, NULL
);
3111 mono_gc_bzero_atomic (dest
, size
);
3113 mono_gc_wbarrier_value_copy (dest
, value
, 1, klass
);
3116 case MONO_TYPE_GENERICINST
:
3117 t
= type
->data
.generic_class
->container_class
->byval_arg
.type
;
3120 g_error ("got type %x", type
->type
);
3125 * mono_field_set_value:
3126 * @obj: Instance object
3127 * @field: MonoClassField describing the field to set
3128 * @value: The value to be set
3130 * Sets the value of the field described by @field in the object instance @obj
3131 * to the value passed in @value. This method should only be used for instance
3132 * fields. For static fields, use mono_field_static_set_value.
3134 * The value must be on the native format of the field type.
3137 mono_field_set_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3139 MONO_REQ_GC_UNSAFE_MODE
;
3143 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
));
3145 dest
= (char*)obj
+ field
->offset
;
3146 mono_copy_value (field
->type
, dest
, value
, FALSE
);
3150 * mono_field_static_set_value:
3151 * @field: MonoClassField describing the field to set
3152 * @value: The value to be set
3154 * Sets the value of the static field described by @field
3155 * to the value passed in @value.
3157 * The value must be on the native format of the field type.
3160 mono_field_static_set_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3162 MONO_REQ_GC_UNSAFE_MODE
;
3166 g_return_if_fail (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3167 /* you cant set a constant! */
3168 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
));
3170 if (field
->offset
== -1) {
3171 /* Special static */
3174 mono_domain_lock (vt
->domain
);
3175 addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3176 mono_domain_unlock (vt
->domain
);
3177 dest
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
3179 dest
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3181 mono_copy_value (field
->type
, dest
, value
, FALSE
);
3185 * mono_vtable_get_static_field_data:
3187 * Internal use function: return a pointer to the memory holding the static fields
3188 * for a class or NULL if there are no static fields.
3189 * This is exported only for use by the debugger.
3192 mono_vtable_get_static_field_data (MonoVTable
*vt
)
3194 MONO_REQ_GC_NEUTRAL_MODE
3196 if (!vt
->has_static_fields
)
3198 return vt
->vtable
[vt
->klass
->vtable_size
];
3202 mono_field_get_addr (MonoObject
*obj
, MonoVTable
*vt
, MonoClassField
*field
)
3204 MONO_REQ_GC_UNSAFE_MODE
;
3208 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3209 if (field
->offset
== -1) {
3210 /* Special static */
3213 mono_domain_lock (vt
->domain
);
3214 addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3215 mono_domain_unlock (vt
->domain
);
3216 src
= (guint8
*)mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
3218 src
= (guint8
*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3221 src
= (guint8
*)obj
+ field
->offset
;
3228 * mono_field_get_value:
3229 * @obj: Object instance
3230 * @field: MonoClassField describing the field to fetch information from
3231 * @value: pointer to the location where the value will be stored
3233 * Use this routine to get the value of the field @field in the object
3236 * The pointer provided by value must be of the field type, for reference
3237 * types this is a MonoObject*, for value types its the actual pointer to
3242 * mono_field_get_value (obj, int_field, &i);
3245 mono_field_get_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
3247 MONO_REQ_GC_UNSAFE_MODE
;
3253 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
));
3255 src
= (char*)obj
+ field
->offset
;
3256 mono_copy_value (field
->type
, value
, src
, TRUE
);
3260 * mono_field_get_value_object:
3261 * @domain: domain where the object will be created (if boxing)
3262 * @field: MonoClassField describing the field to fetch information from
3263 * @obj: The object instance for the field.
3265 * Returns: a new MonoObject with the value from the given field. If the
3266 * field represents a value type, the value is boxed.
3270 mono_field_get_value_object (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
)
3273 MonoObject
* result
= mono_field_get_value_object_checked (domain
, field
, obj
, &error
);
3274 mono_error_assert_ok (&error
);
3279 * mono_field_get_value_object_checked:
3280 * @domain: domain where the object will be created (if boxing)
3281 * @field: MonoClassField describing the field to fetch information from
3282 * @obj: The object instance for the field.
3283 * @error: Set on error.
3285 * Returns: a new MonoObject with the value from the given field. If the
3286 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3290 mono_field_get_value_object_checked (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
, MonoError
*error
)
3292 MONO_REQ_GC_UNSAFE_MODE
;
3294 mono_error_init (error
);
3298 MonoVTable
*vtable
= NULL
;
3300 gboolean is_static
= FALSE
;
3301 gboolean is_ref
= FALSE
;
3302 gboolean is_literal
= FALSE
;
3303 gboolean is_ptr
= FALSE
;
3304 MonoType
*type
= mono_field_get_type_checked (field
, error
);
3306 return_val_if_nok (error
, NULL
);
3308 switch (type
->type
) {
3309 case MONO_TYPE_STRING
:
3310 case MONO_TYPE_OBJECT
:
3311 case MONO_TYPE_CLASS
:
3312 case MONO_TYPE_ARRAY
:
3313 case MONO_TYPE_SZARRAY
:
3318 case MONO_TYPE_BOOLEAN
:
3321 case MONO_TYPE_CHAR
:
3330 case MONO_TYPE_VALUETYPE
:
3331 is_ref
= type
->byref
;
3333 case MONO_TYPE_GENERICINST
:
3334 is_ref
= !mono_type_generic_inst_is_valuetype (type
);
3340 g_error ("type 0x%x not handled in "
3341 "mono_field_get_value_object", type
->type
);
3345 if (type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
3348 if (type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3352 vtable
= mono_class_vtable_full (domain
, field
->parent
, error
);
3353 return_val_if_nok (error
, NULL
);
3355 if (!vtable
->initialized
) {
3356 mono_runtime_class_init_full (vtable
, error
);
3357 return_val_if_nok (error
, NULL
);
3366 get_default_field_value (domain
, field
, &o
, error
);
3367 return_val_if_nok (error
, NULL
);
3368 } else if (is_static
) {
3369 mono_field_static_get_value_checked (vtable
, field
, &o
, error
);
3370 return_val_if_nok (error
, NULL
);
3372 mono_field_get_value (obj
, field
, &o
);
3378 static MonoMethod
*m
;
3384 MonoClass
*ptr_klass
= mono_class_get_pointer_class ();
3385 m
= mono_class_get_method_from_name_flags (ptr_klass
, "Box", 2, METHOD_ATTRIBUTE_STATIC
);
3391 get_default_field_value (domain
, field
, v
, error
);
3392 return_val_if_nok (error
, NULL
);
3393 } else if (is_static
) {
3394 mono_field_static_get_value_checked (vtable
, field
, v
, error
);
3395 return_val_if_nok (error
, NULL
);
3397 mono_field_get_value (obj
, field
, v
);
3400 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3401 args
[0] = ptr
? *ptr
: NULL
;
3402 args
[1] = mono_type_get_object_checked (mono_domain_get (), type
, error
);
3403 return_val_if_nok (error
, NULL
);
3405 o
= mono_runtime_invoke_checked (m
, NULL
, args
, error
);
3406 return_val_if_nok (error
, NULL
);
3411 /* boxed value type */
3412 klass
= mono_class_from_mono_type (type
);
3414 if (mono_class_is_nullable (klass
))
3415 return mono_nullable_box (mono_field_get_addr (obj
, vtable
, field
), klass
, error
);
3417 o
= mono_object_new_checked (domain
, klass
, error
);
3418 return_val_if_nok (error
, NULL
);
3419 v
= ((gchar
*) o
) + sizeof (MonoObject
);
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
);
3435 mono_get_constant_value_from_blob (MonoDomain
* domain
, MonoTypeEnum type
, const char *blob
, void *value
, MonoError
*error
)
3437 MONO_REQ_GC_UNSAFE_MODE
;
3439 mono_error_init (error
);
3441 const char *p
= blob
;
3442 mono_metadata_decode_blob_size (p
, &p
);
3445 case MONO_TYPE_BOOLEAN
:
3448 *(guint8
*) value
= *p
;
3450 case MONO_TYPE_CHAR
:
3453 *(guint16
*) value
= read16 (p
);
3457 *(guint32
*) value
= read32 (p
);
3461 *(guint64
*) value
= read64 (p
);
3464 readr4 (p
, (float*) value
);
3467 readr8 (p
, (double*) value
);
3469 case MONO_TYPE_STRING
:
3470 *(gpointer
*) value
= mono_ldstr_metadata_sig (domain
, blob
, error
);
3472 case MONO_TYPE_CLASS
:
3473 *(gpointer
*) value
= NULL
;
3477 g_warning ("type 0x%02x should not be in constant table", type
);
3483 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
, MonoError
*error
)
3485 MONO_REQ_GC_NEUTRAL_MODE
;
3487 MonoTypeEnum def_type
;
3490 mono_error_init (error
);
3492 data
= mono_class_get_field_default_value (field
, &def_type
);
3493 mono_get_constant_value_from_blob (domain
, def_type
, data
, value
, error
);
3497 mono_field_static_get_value_for_thread (MonoInternalThread
*thread
, MonoVTable
*vt
, MonoClassField
*field
, void *value
, MonoError
*error
)
3499 MONO_REQ_GC_UNSAFE_MODE
;
3503 mono_error_init (error
);
3505 g_return_if_fail (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3507 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
) {
3508 get_default_field_value (vt
->domain
, field
, value
, error
);
3512 if (field
->offset
== -1) {
3513 /* Special static */
3514 gpointer addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3515 src
= mono_get_special_static_data_for_thread (thread
, GPOINTER_TO_UINT (addr
));
3517 src
= (char*)mono_vtable_get_static_field_data (vt
) + field
->offset
;
3519 mono_copy_value (field
->type
, value
, src
, TRUE
);
3523 * mono_field_static_get_value:
3524 * @vt: vtable to the object
3525 * @field: MonoClassField describing the field to fetch information from
3526 * @value: where the value is returned
3528 * Use this routine to get the value of the static field @field value.
3530 * The pointer provided by value must be of the field type, for reference
3531 * types this is a MonoObject*, for value types its the actual pointer to
3536 * mono_field_static_get_value (vt, int_field, &i);
3539 mono_field_static_get_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3541 MONO_REQ_GC_NEUTRAL_MODE
;
3544 mono_field_static_get_value_checked (vt
, field
, value
, &error
);
3545 mono_error_cleanup (&error
);
3549 * mono_field_static_get_value_checked:
3550 * @vt: vtable to the object
3551 * @field: MonoClassField describing the field to fetch information from
3552 * @value: where the value is returned
3553 * @error: set on error
3555 * Use this routine to get the value of the static field @field value.
3557 * The pointer provided by value must be of the field type, for reference
3558 * types this is a MonoObject*, for value types its the actual pointer to
3563 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3564 * if (!is_ok (error)) { ... }
3566 * On failure sets @error.
3569 mono_field_static_get_value_checked (MonoVTable
*vt
, MonoClassField
*field
, void *value
, MonoError
*error
)
3571 MONO_REQ_GC_NEUTRAL_MODE
;
3573 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt
, field
, value
, error
);
3577 * mono_property_set_value:
3578 * @prop: MonoProperty to set
3579 * @obj: instance object on which to act
3580 * @params: parameters to pass to the propery
3581 * @exc: optional exception
3583 * Invokes the property's set method with the given arguments on the
3584 * object instance obj (or NULL for static properties).
3586 * You can pass NULL as the exc argument if you don't want to
3587 * catch exceptions, otherwise, *exc will be set to the exception
3588 * thrown, if any. if an exception is thrown, you can't use the
3589 * MonoObject* result from the function.
3592 mono_property_set_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3594 MONO_REQ_GC_UNSAFE_MODE
;
3597 do_runtime_invoke (prop
->set
, obj
, params
, exc
, &error
);
3598 if (exc
&& *exc
== NULL
&& !mono_error_ok (&error
)) {
3599 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
3601 mono_error_cleanup (&error
);
3606 * mono_property_set_value_checked:
3607 * @prop: MonoProperty to set
3608 * @obj: instance object on which to act
3609 * @params: parameters to pass to the propery
3610 * @error: set on error
3612 * Invokes the property's set method with the given arguments on the
3613 * object instance obj (or NULL for static properties).
3615 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3616 * If an exception is thrown, it will be caught and returned via @error.
3619 mono_property_set_value_checked (MonoProperty
*prop
, void *obj
, void **params
, MonoError
*error
)
3621 MONO_REQ_GC_UNSAFE_MODE
;
3625 mono_error_init (error
);
3626 do_runtime_invoke (prop
->set
, obj
, params
, &exc
, error
);
3627 if (exc
!= NULL
&& is_ok (error
))
3628 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
3629 return is_ok (error
);
3633 * mono_property_get_value:
3634 * @prop: MonoProperty to fetch
3635 * @obj: instance object on which to act
3636 * @params: parameters to pass to the propery
3637 * @exc: optional exception
3639 * Invokes the property's get method with the given arguments on the
3640 * object instance obj (or NULL for static properties).
3642 * You can pass NULL as the exc argument if you don't want to
3643 * catch exceptions, otherwise, *exc will be set to the exception
3644 * thrown, if any. if an exception is thrown, you can't use the
3645 * MonoObject* result from the function.
3647 * Returns: the value from invoking the get method on the property.
3650 mono_property_get_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3652 MONO_REQ_GC_UNSAFE_MODE
;
3655 MonoObject
*val
= do_runtime_invoke (prop
->get
, obj
, params
, exc
, &error
);
3656 if (exc
&& *exc
== NULL
&& !mono_error_ok (&error
)) {
3657 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
3659 mono_error_cleanup (&error
); /* FIXME don't raise here */
3666 * mono_property_get_value_checked:
3667 * @prop: MonoProperty to fetch
3668 * @obj: instance object on which to act
3669 * @params: parameters to pass to the propery
3670 * @error: set on error
3672 * Invokes the property's get method with the given arguments on the
3673 * object instance obj (or NULL for static properties).
3675 * If an exception is thrown, you can't use the
3676 * MonoObject* result from the function. The exception will be propagated via @error.
3678 * Returns: the value from invoking the get method on the property. On
3679 * failure returns NULL and sets @error.
3682 mono_property_get_value_checked (MonoProperty
*prop
, void *obj
, void **params
, MonoError
*error
)
3684 MONO_REQ_GC_UNSAFE_MODE
;
3687 MonoObject
*val
= do_runtime_invoke (prop
->get
, obj
, params
, &exc
, error
);
3688 if (exc
!= NULL
&& !is_ok (error
))
3689 mono_error_set_exception_instance (error
, (MonoException
*) exc
);
3697 * mono_nullable_init:
3698 * @buf: The nullable structure to initialize.
3699 * @value: the value to initialize from
3700 * @klass: the type for the object
3702 * Initialize the nullable structure pointed to by @buf from @value which
3703 * should be a boxed value type. The size of @buf should be able to hold
3704 * as much data as the @klass->instance_size (which is the number of bytes
3705 * that will be copies).
3707 * Since Nullables have variable structure, we can not define a C
3708 * structure for them.
3711 mono_nullable_init (guint8
*buf
, MonoObject
*value
, MonoClass
*klass
)
3713 MONO_REQ_GC_UNSAFE_MODE
;
3715 MonoClass
*param_class
= klass
->cast_class
;
3717 mono_class_setup_fields (klass
);
3718 g_assert (klass
->fields_inited
);
3720 g_assert (mono_class_from_mono_type (klass
->fields
[0].type
) == param_class
);
3721 g_assert (mono_class_from_mono_type (klass
->fields
[1].type
) == mono_defaults
.boolean_class
);
3723 *(guint8
*)(buf
+ klass
->fields
[1].offset
- sizeof (MonoObject
)) = value
? 1 : 0;
3725 if (param_class
->has_references
)
3726 mono_gc_wbarrier_value_copy (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_object_unbox (value
), 1, param_class
);
3728 mono_gc_memmove_atomic (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_object_unbox (value
), mono_class_value_size (param_class
, NULL
));
3730 mono_gc_bzero_atomic (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_class_value_size (param_class
, NULL
));
3735 * mono_nullable_box:
3736 * @buf: The buffer representing the data to be boxed
3737 * @klass: the type to box it as.
3738 * @error: set on oerr
3740 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3741 * @buf. On failure returns NULL and sets @error
3744 mono_nullable_box (guint8
*buf
, MonoClass
*klass
, MonoError
*error
)
3746 MONO_REQ_GC_UNSAFE_MODE
;
3748 mono_error_init (error
);
3749 MonoClass
*param_class
= klass
->cast_class
;
3751 mono_class_setup_fields (klass
);
3752 g_assert (klass
->fields_inited
);
3754 g_assert (mono_class_from_mono_type (klass
->fields
[0].type
) == param_class
);
3755 g_assert (mono_class_from_mono_type (klass
->fields
[1].type
) == mono_defaults
.boolean_class
);
3757 if (*(guint8
*)(buf
+ klass
->fields
[1].offset
- sizeof (MonoObject
))) {
3758 MonoObject
*o
= mono_object_new_checked (mono_domain_get (), param_class
, error
);
3759 return_val_if_nok (error
, NULL
);
3760 if (param_class
->has_references
)
3761 mono_gc_wbarrier_value_copy (mono_object_unbox (o
), buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), 1, param_class
);
3763 mono_gc_memmove_atomic (mono_object_unbox (o
), buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_class_value_size (param_class
, NULL
));
3771 * mono_get_delegate_invoke:
3772 * @klass: The delegate class
3774 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3777 mono_get_delegate_invoke (MonoClass
*klass
)
3779 MONO_REQ_GC_NEUTRAL_MODE
;
3783 /* This is called at runtime, so avoid the slower search in metadata */
3784 mono_class_setup_methods (klass
);
3785 if (mono_class_has_failure (klass
))
3787 im
= mono_class_get_method_from_name (klass
, "Invoke", -1);
3792 * mono_get_delegate_begin_invoke:
3793 * @klass: The delegate class
3795 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3798 mono_get_delegate_begin_invoke (MonoClass
*klass
)
3800 MONO_REQ_GC_NEUTRAL_MODE
;
3804 /* This is called at runtime, so avoid the slower search in metadata */
3805 mono_class_setup_methods (klass
);
3806 if (mono_class_has_failure (klass
))
3808 im
= mono_class_get_method_from_name (klass
, "BeginInvoke", -1);
3813 * mono_get_delegate_end_invoke:
3814 * @klass: The delegate class
3816 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3819 mono_get_delegate_end_invoke (MonoClass
*klass
)
3821 MONO_REQ_GC_NEUTRAL_MODE
;
3825 /* This is called at runtime, so avoid the slower search in metadata */
3826 mono_class_setup_methods (klass
);
3827 if (mono_class_has_failure (klass
))
3829 im
= mono_class_get_method_from_name (klass
, "EndInvoke", -1);
3834 * mono_runtime_delegate_invoke:
3835 * @delegate: pointer to a delegate object.
3836 * @params: parameters for the delegate.
3837 * @exc: Pointer to the exception result.
3839 * Invokes the delegate method @delegate with the parameters provided.
3841 * You can pass NULL as the exc argument if you don't want to
3842 * catch exceptions, otherwise, *exc will be set to the exception
3843 * thrown, if any. if an exception is thrown, you can't use the
3844 * MonoObject* result from the function.
3847 mono_runtime_delegate_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
)
3849 MONO_REQ_GC_UNSAFE_MODE
;
3853 MonoObject
*result
= mono_runtime_delegate_try_invoke (delegate
, params
, exc
, &error
);
3855 mono_error_cleanup (&error
);
3858 if (!is_ok (&error
))
3859 *exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
3863 MonoObject
*result
= mono_runtime_delegate_invoke_checked (delegate
, params
, &error
);
3864 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
3870 * mono_runtime_delegate_try_invoke:
3871 * @delegate: pointer to a delegate object.
3872 * @params: parameters for the delegate.
3873 * @exc: Pointer to the exception result.
3874 * @error: set on error
3876 * Invokes the delegate method @delegate with the parameters provided.
3878 * You can pass NULL as the exc argument if you don't want to
3879 * catch exceptions, otherwise, *exc will be set to the exception
3880 * thrown, if any. On failure to execute, @error will be set.
3881 * if an exception is thrown, you can't use the
3882 * MonoObject* result from the function.
3885 mono_runtime_delegate_try_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
, MonoError
*error
)
3887 MONO_REQ_GC_UNSAFE_MODE
;
3889 mono_error_init (error
);
3891 MonoClass
*klass
= delegate
->vtable
->klass
;
3894 im
= mono_get_delegate_invoke (klass
);
3896 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass
));
3899 o
= mono_runtime_try_invoke (im
, delegate
, params
, exc
, error
);
3901 o
= mono_runtime_invoke_checked (im
, delegate
, params
, error
);
3908 * mono_runtime_delegate_invoke_checked:
3909 * @delegate: pointer to a delegate object.
3910 * @params: parameters for the delegate.
3911 * @error: set on error
3913 * Invokes the delegate method @delegate with the parameters provided.
3915 * On failure @error will be set and you can't use the MonoObject*
3916 * result from the function.
3919 mono_runtime_delegate_invoke_checked (MonoObject
*delegate
, void **params
, MonoError
*error
)
3921 mono_error_init (error
);
3922 return mono_runtime_delegate_try_invoke (delegate
, params
, NULL
, error
);
3925 static char **main_args
= NULL
;
3926 static int num_main_args
= 0;
3929 * mono_runtime_get_main_args:
3931 * Returns: a MonoArray with the arguments passed to the main program
3934 mono_runtime_get_main_args (void)
3936 MONO_REQ_GC_UNSAFE_MODE
;
3938 MonoArray
*result
= mono_runtime_get_main_args_checked (&error
);
3939 mono_error_assert_ok (&error
);
3944 * mono_runtime_get_main_args:
3945 * @error: set on error
3947 * Returns: a MonoArray with the arguments passed to the main
3948 * program. On failure returns NULL and sets @error.
3951 mono_runtime_get_main_args_checked (MonoError
*error
)
3955 MonoDomain
*domain
= mono_domain_get ();
3957 mono_error_init (error
);
3959 res
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, num_main_args
, error
);
3960 return_val_if_nok (error
, NULL
);
3962 for (i
= 0; i
< num_main_args
; ++i
)
3963 mono_array_setref (res
, i
, mono_string_new (domain
, main_args
[i
]));
3969 free_main_args (void)
3971 MONO_REQ_GC_NEUTRAL_MODE
;
3975 for (i
= 0; i
< num_main_args
; ++i
)
3976 g_free (main_args
[i
]);
3983 * mono_runtime_set_main_args:
3984 * @argc: number of arguments from the command line
3985 * @argv: array of strings from the command line
3987 * Set the command line arguments from an embedding application that doesn't otherwise call
3988 * mono_runtime_run_main ().
3991 mono_runtime_set_main_args (int argc
, char* argv
[])
3993 MONO_REQ_GC_NEUTRAL_MODE
;
3998 main_args
= g_new0 (char*, argc
);
3999 num_main_args
= argc
;
4001 for (i
= 0; i
< argc
; ++i
) {
4004 utf8_arg
= mono_utf8_from_external (argv
[i
]);
4005 if (utf8_arg
== NULL
) {
4006 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i
, argv
[i
]);
4007 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4011 main_args
[i
] = utf8_arg
;
4018 * Prepare an array of arguments in order to execute a standard Main()
4019 * method (argc/argv contains the executable name). This method also
4020 * sets the command line argument value needed by System.Environment.
4024 prepare_run_main (MonoMethod
*method
, int argc
, char *argv
[])
4026 MONO_REQ_GC_UNSAFE_MODE
;
4030 MonoArray
*args
= NULL
;
4031 MonoDomain
*domain
= mono_domain_get ();
4032 gchar
*utf8_fullpath
;
4033 MonoMethodSignature
*sig
;
4035 g_assert (method
!= NULL
);
4037 mono_thread_set_main (mono_thread_current ());
4039 main_args
= g_new0 (char*, argc
);
4040 num_main_args
= argc
;
4042 if (!g_path_is_absolute (argv
[0])) {
4043 gchar
*basename
= g_path_get_basename (argv
[0]);
4044 gchar
*fullpath
= g_build_filename (method
->klass
->image
->assembly
->basedir
,
4048 utf8_fullpath
= mono_utf8_from_external (fullpath
);
4049 if(utf8_fullpath
== NULL
) {
4050 /* Printing the arg text will cause glib to
4051 * whinge about "Invalid UTF-8", but at least
4052 * its relevant, and shows the problem text
4055 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath
);
4056 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4063 utf8_fullpath
= mono_utf8_from_external (argv
[0]);
4064 if(utf8_fullpath
== NULL
) {
4065 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv
[0]);
4066 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4071 main_args
[0] = utf8_fullpath
;
4073 for (i
= 1; i
< argc
; ++i
) {
4076 utf8_arg
=mono_utf8_from_external (argv
[i
]);
4077 if(utf8_arg
==NULL
) {
4078 /* Ditto the comment about Invalid UTF-8 here */
4079 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i
, argv
[i
]);
4080 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4084 main_args
[i
] = utf8_arg
;
4089 sig
= mono_method_signature (method
);
4091 g_print ("Unable to load Main method.\n");
4095 if (sig
->param_count
) {
4096 args
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, argc
, &error
);
4097 mono_error_assert_ok (&error
);
4098 for (i
= 0; i
< argc
; ++i
) {
4099 /* The encodings should all work, given that
4100 * we've checked all these args for the
4103 gchar
*str
= mono_utf8_from_external (argv
[i
]);
4104 MonoString
*arg
= mono_string_new (domain
, str
);
4105 mono_array_setref (args
, i
, arg
);
4109 args
= (MonoArray
*)mono_array_new_checked (domain
, mono_defaults
.string_class
, 0, &error
);
4110 mono_error_assert_ok (&error
);
4113 mono_assembly_set_main (method
->klass
->image
->assembly
);
4119 * mono_runtime_run_main:
4120 * @method: the method to start the application with (usually Main)
4121 * @argc: number of arguments from the command line
4122 * @argv: array of strings from the command line
4123 * @exc: excetption results
4125 * Execute a standard Main() method (argc/argv contains the
4126 * executable name). This method also sets the command line argument value
4127 * needed by System.Environment.
4132 mono_runtime_run_main (MonoMethod
*method
, int argc
, char* argv
[],
4135 MONO_REQ_GC_UNSAFE_MODE
;
4138 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4141 res
= mono_runtime_try_exec_main (method
, args
, exc
);
4143 res
= mono_runtime_exec_main_checked (method
, args
, &error
);
4144 mono_error_raise_exception (&error
); /* OK to throw, external only without a better alternative */
4150 * mono_runtime_run_main_checked:
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 * @error: set on error
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. On failure sets @error.
4163 mono_runtime_run_main_checked (MonoMethod
*method
, int argc
, char* argv
[],
4166 mono_error_init (error
);
4167 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4168 return mono_runtime_exec_main_checked (method
, args
, error
);
4172 * mono_runtime_try_run_main:
4173 * @method: the method to start the application with (usually Main)
4174 * @argc: number of arguments from the command line
4175 * @argv: array of strings from the command line
4176 * @exc: set if Main throws an exception
4177 * @error: set if Main can't be executed
4179 * Execute a standard Main() method (argc/argv contains the executable
4180 * name). This method also sets the command line argument value needed
4181 * by System.Environment. On failure sets @error if Main can't be
4182 * executed or @exc if it threw and exception.
4187 mono_runtime_try_run_main (MonoMethod
*method
, int argc
, char* argv
[],
4191 MonoArray
*args
= prepare_run_main (method
, argc
, argv
);
4192 return mono_runtime_try_exec_main (method
, args
, exc
);
4197 serialize_object (MonoObject
*obj
, gboolean
*failure
, MonoObject
**exc
)
4199 static MonoMethod
*serialize_method
;
4205 if (!serialize_method
) {
4206 MonoClass
*klass
= mono_class_get_remoting_services_class ();
4207 serialize_method
= mono_class_get_method_from_name (klass
, "SerializeCallData", -1);
4210 if (!serialize_method
) {
4215 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj
)));
4220 array
= mono_runtime_try_invoke (serialize_method
, NULL
, params
, exc
, &error
);
4221 if (*exc
== NULL
&& !mono_error_ok (&error
))
4222 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
); /* FIXME convert serialize_object to MonoError */
4224 mono_error_cleanup (&error
);
4233 deserialize_object (MonoObject
*obj
, gboolean
*failure
, MonoObject
**exc
)
4235 MONO_REQ_GC_UNSAFE_MODE
;
4237 static MonoMethod
*deserialize_method
;
4243 if (!deserialize_method
) {
4244 MonoClass
*klass
= mono_class_get_remoting_services_class ();
4245 deserialize_method
= mono_class_get_method_from_name (klass
, "DeserializeCallData", -1);
4247 if (!deserialize_method
) {
4255 result
= mono_runtime_try_invoke (deserialize_method
, NULL
, params
, exc
, &error
);
4256 if (*exc
== NULL
&& !mono_error_ok (&error
))
4257 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
); /* FIXME convert deserialize_object to MonoError */
4259 mono_error_cleanup (&error
);
4267 #ifndef DISABLE_REMOTING
4269 make_transparent_proxy (MonoObject
*obj
, MonoError
*error
)
4271 MONO_REQ_GC_UNSAFE_MODE
;
4273 static MonoMethod
*get_proxy_method
;
4275 MonoDomain
*domain
= mono_domain_get ();
4276 MonoRealProxy
*real_proxy
;
4277 MonoReflectionType
*reflection_type
;
4278 MonoTransparentProxy
*transparent_proxy
;
4280 mono_error_init (error
);
4282 if (!get_proxy_method
)
4283 get_proxy_method
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0);
4285 g_assert (mono_class_is_marshalbyref (obj
->vtable
->klass
));
4287 real_proxy
= (MonoRealProxy
*) mono_object_new_checked (domain
, mono_defaults
.real_proxy_class
, error
);
4288 return_val_if_nok (error
, NULL
);
4289 reflection_type
= mono_type_get_object_checked (domain
, &obj
->vtable
->klass
->byval_arg
, error
);
4290 return_val_if_nok (error
, NULL
);
4292 MONO_OBJECT_SETREF (real_proxy
, class_to_proxy
, reflection_type
);
4293 MONO_OBJECT_SETREF (real_proxy
, unwrapped_server
, obj
);
4295 MonoObject
*exc
= NULL
;
4297 transparent_proxy
= (MonoTransparentProxy
*) mono_runtime_try_invoke (get_proxy_method
, real_proxy
, NULL
, &exc
, error
);
4298 if (exc
!= NULL
&& is_ok (error
))
4299 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
4301 return (MonoObject
*) transparent_proxy
;
4303 #endif /* DISABLE_REMOTING */
4306 * mono_object_xdomain_representation
4308 * @target_domain: a domain
4309 * @error: set on error.
4311 * Creates a representation of obj in the domain target_domain. This
4312 * is either a copy of obj arrived through via serialization and
4313 * deserialization or a proxy, depending on whether the object is
4314 * serializable or marshal by ref. obj must not be in target_domain.
4316 * If the object cannot be represented in target_domain, NULL is
4317 * returned and @error is set appropriately.
4320 mono_object_xdomain_representation (MonoObject
*obj
, MonoDomain
*target_domain
, MonoError
*error
)
4322 MONO_REQ_GC_UNSAFE_MODE
;
4324 mono_error_init (error
);
4325 MonoObject
*deserialized
= NULL
;
4327 #ifndef DISABLE_REMOTING
4328 if (mono_class_is_marshalbyref (mono_object_class (obj
))) {
4329 deserialized
= make_transparent_proxy (obj
, error
);
4334 gboolean failure
= FALSE
;
4335 MonoDomain
*domain
= mono_domain_get ();
4336 MonoObject
*serialized
;
4337 MonoObject
*exc
= NULL
;
4339 mono_domain_set_internal_with_options (mono_object_domain (obj
), FALSE
);
4340 serialized
= serialize_object (obj
, &failure
, &exc
);
4341 mono_domain_set_internal_with_options (target_domain
, FALSE
);
4343 deserialized
= deserialize_object (serialized
, &failure
, &exc
);
4344 if (domain
!= target_domain
)
4345 mono_domain_set_internal_with_options (domain
, FALSE
);
4347 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
4350 return deserialized
;
4353 /* Used in call_unhandled_exception_delegate */
4355 create_unhandled_exception_eventargs (MonoObject
*exc
, MonoError
*error
)
4357 MONO_REQ_GC_UNSAFE_MODE
;
4359 mono_error_init (error
);
4362 MonoMethod
*method
= NULL
;
4363 MonoBoolean is_terminating
= TRUE
;
4366 klass
= mono_class_get_unhandled_exception_event_args_class ();
4367 mono_class_init (klass
);
4369 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4370 method
= mono_class_get_method_from_name_flags (klass
, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC
);
4374 args
[1] = &is_terminating
;
4376 obj
= mono_object_new_checked (mono_domain_get (), klass
, error
);
4377 return_val_if_nok (error
, NULL
);
4379 mono_runtime_invoke_checked (method
, obj
, args
, error
);
4380 return_val_if_nok (error
, NULL
);
4385 /* Used in mono_unhandled_exception */
4387 call_unhandled_exception_delegate (MonoDomain
*domain
, MonoObject
*delegate
, MonoObject
*exc
) {
4388 MONO_REQ_GC_UNSAFE_MODE
;
4391 MonoObject
*e
= NULL
;
4393 MonoDomain
*current_domain
= mono_domain_get ();
4395 if (domain
!= current_domain
)
4396 mono_domain_set_internal_with_options (domain
, FALSE
);
4398 g_assert (domain
== mono_object_domain (domain
->domain
));
4400 if (mono_object_domain (exc
) != domain
) {
4402 exc
= mono_object_xdomain_representation (exc
, domain
, &error
);
4404 if (!is_ok (&error
)) {
4405 MonoError inner_error
;
4406 MonoException
*serialization_exc
= mono_error_convert_to_exception (&error
);
4407 exc
= mono_object_xdomain_representation ((MonoObject
*)serialization_exc
, domain
, &inner_error
);
4408 mono_error_assert_ok (&inner_error
);
4410 exc
= (MonoObject
*) mono_exception_from_name_msg (mono_get_corlib (),
4411 "System.Runtime.Serialization", "SerializationException",
4412 "Could not serialize unhandled exception.");
4416 g_assert (mono_object_domain (exc
) == domain
);
4418 pa
[0] = domain
->domain
;
4419 pa
[1] = create_unhandled_exception_eventargs (exc
, &error
);
4420 mono_error_assert_ok (&error
);
4421 mono_runtime_delegate_try_invoke (delegate
, pa
, &e
, &error
);
4422 if (!is_ok (&error
)) {
4424 e
= (MonoObject
*)mono_error_convert_to_exception (&error
);
4426 mono_error_cleanup (&error
);
4429 if (domain
!= current_domain
)
4430 mono_domain_set_internal_with_options (current_domain
, FALSE
);
4433 gchar
*msg
= mono_string_to_utf8_checked (((MonoException
*) e
)->message
, &error
);
4434 if (!mono_error_ok (&error
)) {
4435 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4436 mono_error_cleanup (&error
);
4438 g_warning ("exception inside UnhandledException handler: %s\n", msg
);
4444 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy
= MONO_UNHANDLED_POLICY_CURRENT
;
4447 * mono_runtime_unhandled_exception_policy_set:
4448 * @policy: the new policy
4450 * This is a VM internal routine.
4452 * Sets the runtime policy for handling unhandled exceptions.
4455 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy
) {
4456 runtime_unhandled_exception_policy
= policy
;
4460 * mono_runtime_unhandled_exception_policy_get:
4462 * This is a VM internal routine.
4464 * Gets the runtime policy for handling unhandled exceptions.
4466 MonoRuntimeUnhandledExceptionPolicy
4467 mono_runtime_unhandled_exception_policy_get (void) {
4468 return runtime_unhandled_exception_policy
;
4472 * mono_unhandled_exception:
4473 * @exc: exception thrown
4475 * This is a VM internal routine.
4477 * We call this function when we detect an unhandled exception
4478 * in the default domain.
4480 * It invokes the * UnhandledException event in AppDomain or prints
4481 * a warning to the console
4484 mono_unhandled_exception (MonoObject
*exc
)
4486 MONO_REQ_GC_UNSAFE_MODE
;
4489 MonoClassField
*field
;
4490 MonoDomain
*current_domain
, *root_domain
;
4491 MonoObject
*current_appdomain_delegate
= NULL
, *root_appdomain_delegate
= NULL
;
4493 if (mono_class_has_parent (exc
->vtable
->klass
, mono_defaults
.threadabortexception_class
))
4496 field
= mono_class_get_field_from_name (mono_defaults
.appdomain_class
, "UnhandledException");
4499 current_domain
= mono_domain_get ();
4500 root_domain
= mono_get_root_domain ();
4502 root_appdomain_delegate
= mono_field_get_value_object_checked (root_domain
, field
, (MonoObject
*) root_domain
->domain
, &error
);
4503 mono_error_assert_ok (&error
);
4504 if (current_domain
!= root_domain
) {
4505 current_appdomain_delegate
= mono_field_get_value_object_checked (current_domain
, field
, (MonoObject
*) current_domain
->domain
, &error
);
4506 mono_error_assert_ok (&error
);
4509 if (!current_appdomain_delegate
&& !root_appdomain_delegate
) {
4510 mono_print_unhandled_exception (exc
);
4512 /* unhandled exception callbacks must not be aborted */
4513 mono_threads_begin_abort_protected_block ();
4514 if (root_appdomain_delegate
)
4515 call_unhandled_exception_delegate (root_domain
, root_appdomain_delegate
, exc
);
4516 if (current_appdomain_delegate
)
4517 call_unhandled_exception_delegate (current_domain
, current_appdomain_delegate
, exc
);
4518 mono_threads_end_abort_protected_block ();
4521 /* set exitcode only if we will abort the process */
4522 if ((main_thread
&& mono_thread_internal_current () == main_thread
->internal_thread
)
4523 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
)
4525 mono_environment_exitcode_set (1);
4530 * mono_runtime_exec_managed_code:
4531 * @domain: Application domain
4532 * @main_func: function to invoke from the execution thread
4533 * @main_args: parameter to the main_func
4535 * Launch a new thread to execute a function
4537 * main_func is called back from the thread with main_args as the
4538 * parameter. The callback function is expected to start Main()
4539 * eventually. This function then waits for all managed threads to
4541 * It is not necesseray anymore to execute managed code in a subthread,
4542 * so this function should not be used anymore by default: just
4543 * execute the code and then call mono_thread_manage ().
4546 mono_runtime_exec_managed_code (MonoDomain
*domain
,
4547 MonoMainThreadFunc main_func
,
4551 mono_thread_create_checked (domain
, main_func
, main_args
, &error
);
4552 mono_error_assert_ok (&error
);
4554 mono_thread_manage ();
4558 prepare_thread_to_exec_main (MonoDomain
*domain
, MonoMethod
*method
)
4560 MonoInternalThread
* thread
= mono_thread_internal_current ();
4561 MonoCustomAttrInfo
* cinfo
;
4562 gboolean has_stathread_attribute
;
4564 if (!domain
->entry_assembly
) {
4566 MonoAssembly
*assembly
;
4568 assembly
= method
->klass
->image
->assembly
;
4569 domain
->entry_assembly
= assembly
;
4570 /* Domains created from another domain already have application_base and configuration_file set */
4571 if (domain
->setup
->application_base
== NULL
) {
4572 MONO_OBJECT_SETREF (domain
->setup
, application_base
, mono_string_new (domain
, assembly
->basedir
));
4575 if (domain
->setup
->configuration_file
== NULL
) {
4576 str
= g_strconcat (assembly
->image
->name
, ".config", NULL
);
4577 MONO_OBJECT_SETREF (domain
->setup
, configuration_file
, mono_string_new (domain
, str
));
4579 mono_domain_set_options_from_config (domain
);
4583 MonoError cattr_error
;
4584 cinfo
= mono_custom_attrs_from_method_checked (method
, &cattr_error
);
4585 mono_error_cleanup (&cattr_error
); /* FIXME warn here? */
4587 has_stathread_attribute
= mono_custom_attrs_has_attr (cinfo
, mono_class_get_sta_thread_attribute_class ());
4589 mono_custom_attrs_free (cinfo
);
4591 has_stathread_attribute
= FALSE
;
4593 if (has_stathread_attribute
) {
4594 thread
->apartment_state
= ThreadApartmentState_STA
;
4596 thread
->apartment_state
= ThreadApartmentState_MTA
;
4598 mono_thread_init_apartment_state ();
4603 do_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*error
)
4605 MONO_REQ_GC_UNSAFE_MODE
;
4610 mono_error_init (error
);
4615 /* FIXME: check signature of method */
4616 if (mono_method_signature (method
)->ret
->type
== MONO_TYPE_I4
) {
4618 res
= mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
4620 rval
= *(guint32
*)((char *)res
+ sizeof (MonoObject
));
4623 mono_environment_exitcode_set (rval
);
4625 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
4637 do_try_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
4639 MONO_REQ_GC_UNSAFE_MODE
;
4649 /* FIXME: check signature of method */
4650 if (mono_method_signature (method
)->ret
->type
== MONO_TYPE_I4
) {
4651 MonoError inner_error
;
4653 res
= mono_runtime_try_invoke (method
, NULL
, pa
, exc
, &inner_error
);
4654 if (*exc
== NULL
&& !mono_error_ok (&inner_error
))
4655 *exc
= (MonoObject
*) mono_error_convert_to_exception (&inner_error
);
4657 mono_error_cleanup (&inner_error
);
4660 rval
= *(guint32
*)((char *)res
+ sizeof (MonoObject
));
4664 mono_environment_exitcode_set (rval
);
4666 MonoError inner_error
;
4667 mono_runtime_try_invoke (method
, NULL
, pa
, exc
, &inner_error
);
4668 if (*exc
== NULL
&& !mono_error_ok (&inner_error
))
4669 *exc
= (MonoObject
*) mono_error_convert_to_exception (&inner_error
);
4671 mono_error_cleanup (&inner_error
);
4676 /* If the return type of Main is void, only
4677 * set the exitcode if an exception was thrown
4678 * (we don't want to blow away an
4679 * explicitly-set exit code)
4682 mono_environment_exitcode_set (rval
);
4690 * Execute a standard Main() method (args doesn't contain the
4694 mono_runtime_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
4697 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
4699 int rval
= do_try_exec_main (method
, args
, exc
);
4702 int rval
= do_exec_main_checked (method
, args
, &error
);
4703 mono_error_raise_exception (&error
); /* OK to throw, external only with no better option */
4709 * Execute a standard Main() method (args doesn't contain the
4712 * On failure sets @error
4715 mono_runtime_exec_main_checked (MonoMethod
*method
, MonoArray
*args
, MonoError
*error
)
4717 mono_error_init (error
);
4718 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
4719 return do_exec_main_checked (method
, args
, error
);
4723 * Execute a standard Main() method (args doesn't contain the
4726 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4729 mono_runtime_try_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
4731 prepare_thread_to_exec_main (mono_object_domain (args
), method
);
4732 return do_try_exec_main (method
, args
, exc
);
4737 /** invoke_array_extract_argument:
4738 * @params: array of arguments to the method.
4739 * @i: the index of the argument to extract.
4740 * @t: ith type from the method signature.
4741 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4742 * @error: set on error.
4744 * Given an array of method arguments, return the ith one using the corresponding type
4745 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4747 * On failure sets @error and returns NULL.
4750 invoke_array_extract_argument (MonoArray
*params
, int i
, MonoType
*t
, gboolean
* has_byref_nullables
, MonoError
*error
)
4752 MonoType
*t_orig
= t
;
4753 gpointer result
= NULL
;
4754 mono_error_init (error
);
4759 case MONO_TYPE_BOOLEAN
:
4762 case MONO_TYPE_CHAR
:
4771 case MONO_TYPE_VALUETYPE
:
4772 if (t
->type
== MONO_TYPE_VALUETYPE
&& mono_class_is_nullable (mono_class_from_mono_type (t_orig
))) {
4773 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4774 result
= mono_array_get (params
, MonoObject
*, i
);
4776 *has_byref_nullables
= TRUE
;
4778 /* MS seems to create the objects if a null is passed in */
4779 if (!mono_array_get (params
, MonoObject
*, i
)) {
4780 MonoObject
*o
= mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig
), error
);
4781 return_val_if_nok (error
, NULL
);
4782 mono_array_setref (params
, i
, o
);
4787 * We can't pass the unboxed vtype byref to the callee, since
4788 * that would mean the callee would be able to modify boxed
4789 * primitive types. So we (and MS) make a copy of the boxed
4790 * object, pass that to the callee, and replace the original
4791 * boxed object in the arg array with the copy.
4793 MonoObject
*orig
= mono_array_get (params
, MonoObject
*, i
);
4794 MonoObject
*copy
= mono_value_box_checked (mono_domain_get (), orig
->vtable
->klass
, mono_object_unbox (orig
), error
);
4795 return_val_if_nok (error
, NULL
);
4796 mono_array_setref (params
, i
, copy
);
4799 result
= mono_object_unbox (mono_array_get (params
, MonoObject
*, i
));
4802 case MONO_TYPE_STRING
:
4803 case MONO_TYPE_OBJECT
:
4804 case MONO_TYPE_CLASS
:
4805 case MONO_TYPE_ARRAY
:
4806 case MONO_TYPE_SZARRAY
:
4808 result
= mono_array_addr (params
, MonoObject
*, i
);
4809 // FIXME: I need to check this code path
4811 result
= mono_array_get (params
, MonoObject
*, i
);
4813 case MONO_TYPE_GENERICINST
:
4815 t
= &t
->data
.generic_class
->container_class
->this_arg
;
4817 t
= &t
->data
.generic_class
->container_class
->byval_arg
;
4819 case MONO_TYPE_PTR
: {
4822 /* The argument should be an IntPtr */
4823 arg
= mono_array_get (params
, MonoObject
*, i
);
4827 g_assert (arg
->vtable
->klass
== mono_defaults
.int_class
);
4828 result
= ((MonoIntPtr
*)arg
)->m_value
;
4833 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig
->type
);
4838 * mono_runtime_invoke_array:
4839 * @method: method to invoke
4840 * @obJ: object instance
4841 * @params: arguments to the method
4842 * @exc: exception information.
4844 * Invokes the method represented by @method on the object @obj.
4846 * obj is the 'this' pointer, it should be NULL for static
4847 * methods, a MonoObject* for object instances and a pointer to
4848 * the value type for value types.
4850 * The params array contains the arguments to the method with the
4851 * same convention: MonoObject* pointers for object instances and
4852 * pointers to the value type otherwise. The _invoke_array
4853 * variant takes a C# object[] as the params argument (MonoArray
4854 * *params): in this case the value types are boxed inside the
4855 * respective reference representation.
4857 * From unmanaged code you'll usually use the
4858 * mono_runtime_invoke_checked() variant.
4860 * Note that this function doesn't handle virtual methods for
4861 * you, it will exec the exact method you pass: we still need to
4862 * expose a function to lookup the derived class implementation
4863 * of a virtual method (there are examples of this in the code,
4866 * You can pass NULL as the exc argument if you don't want to
4867 * catch exceptions, otherwise, *exc will be set to the exception
4868 * thrown, if any. if an exception is thrown, you can't use the
4869 * MonoObject* result from the function.
4871 * If the method returns a value type, it is boxed in an object
4875 mono_runtime_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
4880 MonoObject
*result
= mono_runtime_try_invoke_array (method
, obj
, params
, exc
, &error
);
4882 mono_error_cleanup (&error
);
4885 if (!is_ok (&error
))
4886 *exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
4890 MonoObject
*result
= mono_runtime_try_invoke_array (method
, obj
, params
, NULL
, &error
);
4891 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
4897 * mono_runtime_invoke_array_checked:
4898 * @method: method to invoke
4899 * @obJ: object instance
4900 * @params: arguments to the method
4901 * @error: set on failure.
4903 * Invokes the method represented by @method on the object @obj.
4905 * obj is the 'this' pointer, it should be NULL for static
4906 * methods, a MonoObject* for object instances and a pointer to
4907 * the value type for value types.
4909 * The params array contains the arguments to the method with the
4910 * same convention: MonoObject* pointers for object instances and
4911 * pointers to the value type otherwise. The _invoke_array
4912 * variant takes a C# object[] as the params argument (MonoArray
4913 * *params): in this case the value types are boxed inside the
4914 * respective reference representation.
4916 * From unmanaged code you'll usually use the
4917 * mono_runtime_invoke_checked() variant.
4919 * Note that this function doesn't handle virtual methods for
4920 * you, it will exec the exact method you pass: we still need to
4921 * expose a function to lookup the derived class implementation
4922 * of a virtual method (there are examples of this in the code,
4925 * On failure or exception, @error will be set. In that case, you
4926 * can't use the MonoObject* result from the function.
4928 * If the method returns a value type, it is boxed in an object
4932 mono_runtime_invoke_array_checked (MonoMethod
*method
, void *obj
, MonoArray
*params
,
4935 mono_error_init (error
);
4936 return mono_runtime_try_invoke_array (method
, obj
, params
, NULL
, error
);
4940 * mono_runtime_try_invoke_array:
4941 * @method: method to invoke
4942 * @obJ: object instance
4943 * @params: arguments to the method
4944 * @exc: exception information.
4945 * @error: set on failure.
4947 * Invokes the method represented by @method on the object @obj.
4949 * obj is the 'this' pointer, it should be NULL for static
4950 * methods, a MonoObject* for object instances and a pointer to
4951 * the value type for value types.
4953 * The params array contains the arguments to the method with the
4954 * same convention: MonoObject* pointers for object instances and
4955 * pointers to the value type otherwise. The _invoke_array
4956 * variant takes a C# object[] as the params argument (MonoArray
4957 * *params): in this case the value types are boxed inside the
4958 * respective reference representation.
4960 * From unmanaged code you'll usually use the
4961 * mono_runtime_invoke_checked() variant.
4963 * Note that this function doesn't handle virtual methods for
4964 * you, it will exec the exact method you pass: we still need to
4965 * expose a function to lookup the derived class implementation
4966 * of a virtual method (there are examples of this in the code,
4969 * You can pass NULL as the exc argument if you don't want to catch
4970 * exceptions, otherwise, *exc will be set to the exception thrown, if
4971 * any. On other failures, @error will be set. If an exception is
4972 * thrown or there's an error, you can't use the MonoObject* result
4973 * from the function.
4975 * If the method returns a value type, it is boxed in an object
4979 mono_runtime_try_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
4980 MonoObject
**exc
, MonoError
*error
)
4982 MONO_REQ_GC_UNSAFE_MODE
;
4984 mono_error_init (error
);
4986 MonoMethodSignature
*sig
= mono_method_signature (method
);
4987 gpointer
*pa
= NULL
;
4990 gboolean has_byref_nullables
= FALSE
;
4992 if (NULL
!= params
) {
4993 pa
= (void **)alloca (sizeof (gpointer
) * mono_array_length (params
));
4994 for (i
= 0; i
< mono_array_length (params
); i
++) {
4995 MonoType
*t
= sig
->params
[i
];
4996 pa
[i
] = invoke_array_extract_argument (params
, i
, t
, &has_byref_nullables
, error
);
4997 return_val_if_nok (error
, NULL
);
5001 if (!strcmp (method
->name
, ".ctor") && method
->klass
!= mono_defaults
.string_class
) {
5004 if (mono_class_is_nullable (method
->klass
)) {
5005 /* Need to create a boxed vtype instead */
5011 return mono_value_box_checked (mono_domain_get (), method
->klass
->cast_class
, pa
[0], error
);
5016 obj
= mono_object_new_checked (mono_domain_get (), method
->klass
, error
);
5017 mono_error_assert_ok (error
);
5018 g_assert (obj
); /*maybe we should raise a TLE instead?*/
5019 #ifndef DISABLE_REMOTING
5020 if (mono_object_class(obj
) == mono_defaults
.transparent_proxy_class
) {
5021 method
= mono_marshal_get_remoting_invoke (method
->slot
== -1 ? method
: method
->klass
->vtable
[method
->slot
]);
5024 if (method
->klass
->valuetype
)
5025 o
= (MonoObject
*)mono_object_unbox ((MonoObject
*)obj
);
5028 } else if (method
->klass
->valuetype
) {
5029 obj
= mono_value_box_checked (mono_domain_get (), method
->klass
, obj
, error
);
5030 return_val_if_nok (error
, NULL
);
5034 mono_runtime_try_invoke (method
, o
, pa
, exc
, error
);
5036 mono_runtime_invoke_checked (method
, o
, pa
, error
);
5039 return (MonoObject
*)obj
;
5041 if (mono_class_is_nullable (method
->klass
)) {
5042 MonoObject
*nullable
;
5044 /* Convert the unboxed vtype into a Nullable structure */
5045 nullable
= mono_object_new_checked (mono_domain_get (), method
->klass
, error
);
5046 return_val_if_nok (error
, NULL
);
5048 MonoObject
*boxed
= mono_value_box_checked (mono_domain_get (), method
->klass
->cast_class
, obj
, error
);
5049 return_val_if_nok (error
, NULL
);
5050 mono_nullable_init ((guint8
*)mono_object_unbox (nullable
), boxed
, method
->klass
);
5051 obj
= mono_object_unbox (nullable
);
5054 /* obj must be already unboxed if needed */
5056 res
= mono_runtime_try_invoke (method
, obj
, pa
, exc
, error
);
5058 res
= mono_runtime_invoke_checked (method
, obj
, pa
, error
);
5060 return_val_if_nok (error
, NULL
);
5062 if (sig
->ret
->type
== MONO_TYPE_PTR
) {
5063 MonoClass
*pointer_class
;
5064 static MonoMethod
*box_method
;
5066 MonoObject
*box_exc
;
5069 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5070 * convert it to a Pointer object.
5072 pointer_class
= mono_class_get_pointer_class ();
5074 box_method
= mono_class_get_method_from_name (pointer_class
, "Box", -1);
5076 g_assert (res
->vtable
->klass
== mono_defaults
.int_class
);
5077 box_args
[0] = ((MonoIntPtr
*)res
)->m_value
;
5078 box_args
[1] = mono_type_get_object_checked (mono_domain_get (), sig
->ret
, error
);
5079 return_val_if_nok (error
, NULL
);
5081 res
= mono_runtime_try_invoke (box_method
, NULL
, box_args
, &box_exc
, error
);
5082 g_assert (box_exc
== NULL
);
5083 mono_error_assert_ok (error
);
5086 if (has_byref_nullables
) {
5088 * The runtime invoke wrapper already converted byref nullables back,
5089 * and stored them in pa, we just need to copy them back to the
5092 for (i
= 0; i
< mono_array_length (params
); i
++) {
5093 MonoType
*t
= sig
->params
[i
];
5095 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
5096 mono_array_setref (params
, i
, pa
[i
]);
5106 * @klass: the class of the object that we want to create
5108 * Returns: a newly created object whose definition is
5109 * looked up using @klass. This will not invoke any constructors,
5110 * so the consumer of this routine has to invoke any constructors on
5111 * its own to initialize the object.
5113 * It returns NULL on failure.
5116 mono_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5118 MONO_REQ_GC_UNSAFE_MODE
;
5122 MonoObject
* result
= mono_object_new_checked (domain
, klass
, &error
);
5124 mono_error_cleanup (&error
);
5129 ves_icall_object_new (MonoDomain
*domain
, MonoClass
*klass
)
5131 MONO_REQ_GC_UNSAFE_MODE
;
5135 MonoObject
* result
= mono_object_new_checked (domain
, klass
, &error
);
5137 mono_error_set_pending_exception (&error
);
5142 * mono_object_new_checked:
5143 * @klass: the class of the object that we want to create
5144 * @error: set on error
5146 * Returns: a newly created object whose definition is
5147 * looked up using @klass. This will not invoke any constructors,
5148 * so the consumer of this routine has to invoke any constructors on
5149 * its own to initialize the object.
5151 * It returns NULL on failure and sets @error.
5154 mono_object_new_checked (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5156 MONO_REQ_GC_UNSAFE_MODE
;
5160 vtable
= mono_class_vtable (domain
, klass
);
5161 g_assert (vtable
); /* FIXME don't swallow the error */
5163 MonoObject
*o
= mono_object_new_specific_checked (vtable
, error
);
5168 * mono_object_new_pinned:
5170 * Same as mono_object_new, but the returned object will be pinned.
5171 * For SGEN, these objects will only be freed at appdomain unload.
5174 mono_object_new_pinned (MonoDomain
*domain
, MonoClass
*klass
, MonoError
*error
)
5176 MONO_REQ_GC_UNSAFE_MODE
;
5180 mono_error_init (error
);
5182 vtable
= mono_class_vtable (domain
, klass
);
5183 g_assert (vtable
); /* FIXME don't swallow the error */
5185 MonoObject
*o
= (MonoObject
*)mono_gc_alloc_pinned_obj (vtable
, mono_class_instance_size (klass
));
5187 if (G_UNLIKELY (!o
))
5188 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", mono_class_instance_size (klass
));
5189 else if (G_UNLIKELY (vtable
->klass
->has_finalize
))
5190 mono_object_register_finalizer (o
);
5196 * mono_object_new_specific:
5197 * @vtable: the vtable of the object that we want to create
5199 * Returns: A newly created object with class and domain specified
5203 mono_object_new_specific (MonoVTable
*vtable
)
5206 MonoObject
*o
= mono_object_new_specific_checked (vtable
, &error
);
5207 mono_error_cleanup (&error
);
5213 mono_object_new_specific_checked (MonoVTable
*vtable
, MonoError
*error
)
5215 MONO_REQ_GC_UNSAFE_MODE
;
5219 mono_error_init (error
);
5221 /* check for is_com_object for COM Interop */
5222 if (mono_vtable_is_remote (vtable
) || mono_class_is_com_object (vtable
->klass
))
5225 MonoMethod
*im
= vtable
->domain
->create_proxy_for_type_method
;
5228 MonoClass
*klass
= mono_class_get_activation_services_class ();
5231 mono_class_init (klass
);
5233 im
= mono_class_get_method_from_name (klass
, "CreateProxyForType", 1);
5235 mono_error_set_not_supported (error
, "Linked away.");
5238 vtable
->domain
->create_proxy_for_type_method
= im
;
5241 pa
[0] = mono_type_get_object_checked (mono_domain_get (), &vtable
->klass
->byval_arg
, error
);
5242 if (!mono_error_ok (error
))
5245 o
= mono_runtime_invoke_checked (im
, NULL
, pa
, error
);
5246 if (!mono_error_ok (error
))
5253 return mono_object_new_alloc_specific_checked (vtable
, error
);
5257 ves_icall_object_new_specific (MonoVTable
*vtable
)
5260 MonoObject
*o
= mono_object_new_specific_checked (vtable
, &error
);
5261 mono_error_set_pending_exception (&error
);
5267 * mono_object_new_alloc_specific:
5268 * @vtable: virtual table for the object.
5270 * This function allocates a new `MonoObject` with the type derived
5271 * from the @vtable information. If the class of this object has a
5272 * finalizer, then the object will be tracked for finalization.
5274 * This method might raise an exception on errors. Use the
5275 * `mono_object_new_fast_checked` method if you want to manually raise
5278 * Returns: the allocated object.
5281 mono_object_new_alloc_specific (MonoVTable
*vtable
)
5284 MonoObject
*o
= mono_object_new_alloc_specific_checked (vtable
, &error
);
5285 mono_error_cleanup (&error
);
5291 * mono_object_new_alloc_specific_checked:
5292 * @vtable: virtual table for the object.
5293 * @error: holds the error return value.
5295 * This function allocates a new `MonoObject` with the type derived
5296 * from the @vtable information. If the class of this object has a
5297 * finalizer, then the object will be tracked for finalization.
5299 * If there is not enough memory, the @error parameter will be set
5300 * and will contain a user-visible message with the amount of bytes
5301 * that were requested.
5303 * Returns: the allocated object, or NULL if there is not enough memory
5307 mono_object_new_alloc_specific_checked (MonoVTable
*vtable
, MonoError
*error
)
5309 MONO_REQ_GC_UNSAFE_MODE
;
5313 mono_error_init (error
);
5315 o
= (MonoObject
*)mono_gc_alloc_obj (vtable
, vtable
->klass
->instance_size
);
5317 if (G_UNLIKELY (!o
))
5318 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", vtable
->klass
->instance_size
);
5319 else if (G_UNLIKELY (vtable
->klass
->has_finalize
))
5320 mono_object_register_finalizer (o
);
5326 * mono_object_new_fast:
5327 * @vtable: virtual table for the object.
5329 * This function allocates a new `MonoObject` with the type derived
5330 * from the @vtable information. The returned object is not tracked
5331 * for finalization. If your object implements a finalizer, you should
5332 * use `mono_object_new_alloc_specific` instead.
5334 * This method might raise an exception on errors. Use the
5335 * `mono_object_new_fast_checked` method if you want to manually raise
5338 * Returns: the allocated object.
5341 mono_object_new_fast (MonoVTable
*vtable
)
5344 MonoObject
*o
= mono_object_new_fast_checked (vtable
, &error
);
5345 mono_error_cleanup (&error
);
5351 * mono_object_new_fast_checked:
5352 * @vtable: virtual table for the object.
5353 * @error: holds the error return value.
5355 * This function allocates a new `MonoObject` with the type derived
5356 * from the @vtable information. The returned object is not tracked
5357 * for finalization. If your object implements a finalizer, you should
5358 * use `mono_object_new_alloc_specific_checked` instead.
5360 * If there is not enough memory, the @error parameter will be set
5361 * and will contain a user-visible message with the amount of bytes
5362 * that were requested.
5364 * Returns: the allocated object, or NULL if there is not enough memory
5368 mono_object_new_fast_checked (MonoVTable
*vtable
, MonoError
*error
)
5370 MONO_REQ_GC_UNSAFE_MODE
;
5374 mono_error_init (error
);
5376 o
= mono_gc_alloc_obj (vtable
, vtable
->klass
->instance_size
);
5378 if (G_UNLIKELY (!o
))
5379 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", vtable
->klass
->instance_size
);
5385 ves_icall_object_new_fast (MonoVTable
*vtable
)
5388 MonoObject
*o
= mono_object_new_fast_checked (vtable
, &error
);
5389 mono_error_set_pending_exception (&error
);
5395 mono_object_new_mature (MonoVTable
*vtable
, MonoError
*error
)
5397 MONO_REQ_GC_UNSAFE_MODE
;
5401 mono_error_init (error
);
5403 o
= mono_gc_alloc_mature (vtable
, vtable
->klass
->instance_size
);
5405 if (G_UNLIKELY (!o
))
5406 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", vtable
->klass
->instance_size
);
5407 else if (G_UNLIKELY (vtable
->klass
->has_finalize
))
5408 mono_object_register_finalizer (o
);
5414 * mono_class_get_allocation_ftn:
5416 * @for_box: the object will be used for boxing
5417 * @pass_size_in_words:
5419 * Return the allocation function appropriate for the given class.
5423 mono_class_get_allocation_ftn (MonoVTable
*vtable
, gboolean for_box
, gboolean
*pass_size_in_words
)
5425 MONO_REQ_GC_NEUTRAL_MODE
;
5427 *pass_size_in_words
= FALSE
;
5429 if (mono_class_has_finalizer (vtable
->klass
) || mono_class_is_marshalbyref (vtable
->klass
))
5430 return ves_icall_object_new_specific
;
5432 if (vtable
->gc_descr
!= MONO_GC_DESCRIPTOR_NULL
) {
5434 return ves_icall_object_new_fast
;
5437 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5438 * of the overhead of parameter passing.
5441 *pass_size_in_words = TRUE;
5442 #ifdef GC_REDIRECT_TO_LOCAL
5443 return GC_local_gcj_fast_malloc;
5445 return GC_gcj_fast_malloc;
5450 return ves_icall_object_new_specific
;
5454 * mono_object_new_from_token:
5455 * @image: Context where the type_token is hosted
5456 * @token: a token of the type that we want to create
5458 * Returns: A newly created object whose definition is
5459 * looked up using @token in the @image image
5462 mono_object_new_from_token (MonoDomain
*domain
, MonoImage
*image
, guint32 token
)
5464 MONO_REQ_GC_UNSAFE_MODE
;
5470 klass
= mono_class_get_checked (image
, token
, &error
);
5471 mono_error_assert_ok (&error
);
5473 result
= mono_object_new_checked (domain
, klass
, &error
);
5475 mono_error_cleanup (&error
);
5482 * mono_object_clone:
5483 * @obj: the object to clone
5485 * Returns: A newly created object who is a shallow copy of @obj
5488 mono_object_clone (MonoObject
*obj
)
5491 MonoObject
*o
= mono_object_clone_checked (obj
, &error
);
5492 mono_error_cleanup (&error
);
5498 mono_object_clone_checked (MonoObject
*obj
, MonoError
*error
)
5500 MONO_REQ_GC_UNSAFE_MODE
;
5505 mono_error_init (error
);
5507 size
= obj
->vtable
->klass
->instance_size
;
5509 if (obj
->vtable
->klass
->rank
)
5510 return (MonoObject
*)mono_array_clone_checked ((MonoArray
*)obj
, error
);
5512 o
= (MonoObject
*)mono_gc_alloc_obj (obj
->vtable
, size
);
5514 if (G_UNLIKELY (!o
)) {
5515 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", size
);
5519 /* If the object doesn't contain references this will do a simple memmove. */
5520 mono_gc_wbarrier_object_copy (o
, obj
);
5522 if (obj
->vtable
->klass
->has_finalize
)
5523 mono_object_register_finalizer (o
);
5528 * mono_array_full_copy:
5529 * @src: source array to copy
5530 * @dest: destination array
5532 * Copies the content of one array to another with exactly the same type and size.
5535 mono_array_full_copy (MonoArray
*src
, MonoArray
*dest
)
5537 MONO_REQ_GC_UNSAFE_MODE
;
5540 MonoClass
*klass
= src
->obj
.vtable
->klass
;
5542 g_assert (klass
== dest
->obj
.vtable
->klass
);
5544 size
= mono_array_length (src
);
5545 g_assert (size
== mono_array_length (dest
));
5546 size
*= mono_array_element_size (klass
);
5548 if (klass
->element_class
->valuetype
) {
5549 if (klass
->element_class
->has_references
)
5550 mono_value_copy_array (dest
, 0, mono_array_addr_with_size_fast (src
, 0, 0), mono_array_length (src
));
5552 mono_gc_memmove_atomic (&dest
->vector
, &src
->vector
, size
);
5554 mono_array_memcpy_refs (dest
, 0, src
, 0, mono_array_length (src
));
5557 mono_gc_memmove_atomic (&dest
->vector
, &src
->vector
, size
);
5562 * mono_array_clone_in_domain:
5563 * @domain: the domain in which the array will be cloned into
5564 * @array: the array to clone
5565 * @error: set on error
5567 * This routine returns a copy of the array that is hosted on the
5568 * specified MonoDomain. On failure returns NULL and sets @error.
5571 mono_array_clone_in_domain (MonoDomain
*domain
, MonoArray
*array
, MonoError
*error
)
5573 MONO_REQ_GC_UNSAFE_MODE
;
5578 MonoClass
*klass
= array
->obj
.vtable
->klass
;
5580 mono_error_init (error
);
5582 if (array
->bounds
== NULL
) {
5583 size
= mono_array_length (array
);
5584 o
= mono_array_new_full_checked (domain
, klass
, &size
, NULL
, error
);
5585 return_val_if_nok (error
, NULL
);
5587 size
*= mono_array_element_size (klass
);
5589 if (klass
->element_class
->valuetype
) {
5590 if (klass
->element_class
->has_references
)
5591 mono_value_copy_array (o
, 0, mono_array_addr_with_size_fast (array
, 0, 0), mono_array_length (array
));
5593 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5595 mono_array_memcpy_refs (o
, 0, array
, 0, mono_array_length (array
));
5598 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5603 sizes
= (uintptr_t *)alloca (klass
->rank
* sizeof(intptr_t) * 2);
5604 size
= mono_array_element_size (klass
);
5605 for (i
= 0; i
< klass
->rank
; ++i
) {
5606 sizes
[i
] = array
->bounds
[i
].length
;
5607 size
*= array
->bounds
[i
].length
;
5608 sizes
[i
+ klass
->rank
] = array
->bounds
[i
].lower_bound
;
5610 o
= mono_array_new_full_checked (domain
, klass
, sizes
, (intptr_t*)sizes
+ klass
->rank
, error
);
5611 return_val_if_nok (error
, NULL
);
5613 if (klass
->element_class
->valuetype
) {
5614 if (klass
->element_class
->has_references
)
5615 mono_value_copy_array (o
, 0, mono_array_addr_with_size_fast (array
, 0, 0), mono_array_length (array
));
5617 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5619 mono_array_memcpy_refs (o
, 0, array
, 0, mono_array_length (array
));
5622 mono_gc_memmove_atomic (&o
->vector
, &array
->vector
, size
);
5630 * @array: the array to clone
5632 * Returns: A newly created array who is a shallow copy of @array
5635 mono_array_clone (MonoArray
*array
)
5637 MONO_REQ_GC_UNSAFE_MODE
;
5640 MonoArray
*result
= mono_array_clone_checked (array
, &error
);
5641 mono_error_cleanup (&error
);
5646 * mono_array_clone_checked:
5647 * @array: the array to clone
5648 * @error: set on error
5650 * Returns: A newly created array who is a shallow copy of @array. On
5651 * failure returns NULL and sets @error.
5654 mono_array_clone_checked (MonoArray
*array
, MonoError
*error
)
5657 MONO_REQ_GC_UNSAFE_MODE
;
5658 return mono_array_clone_in_domain (((MonoObject
*)array
)->vtable
->domain
, array
, error
);
5661 /* helper macros to check for overflow when calculating the size of arrays */
5662 #ifdef MONO_BIG_ARRAYS
5663 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5664 #define MYGUINT_MAX MYGUINT64_MAX
5665 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5666 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5667 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5668 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5669 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5671 #define MYGUINT32_MAX 4294967295U
5672 #define MYGUINT_MAX MYGUINT32_MAX
5673 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5674 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5675 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5676 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5677 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5681 mono_array_calc_byte_len (MonoClass
*klass
, uintptr_t len
, uintptr_t *res
)
5683 MONO_REQ_GC_NEUTRAL_MODE
;
5687 byte_len
= mono_array_element_size (klass
);
5688 if (CHECK_MUL_OVERFLOW_UN (byte_len
, len
))
5691 if (CHECK_ADD_OVERFLOW_UN (byte_len
, MONO_SIZEOF_MONO_ARRAY
))
5693 byte_len
+= MONO_SIZEOF_MONO_ARRAY
;
5701 * mono_array_new_full:
5702 * @domain: domain where the object is created
5703 * @array_class: array class
5704 * @lengths: lengths for each dimension in the array
5705 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5707 * This routine creates a new array objects with the given dimensions,
5708 * lower bounds and type.
5711 mono_array_new_full (MonoDomain
*domain
, MonoClass
*array_class
, uintptr_t *lengths
, intptr_t *lower_bounds
)
5714 MonoArray
*array
= mono_array_new_full_checked (domain
, array_class
, lengths
, lower_bounds
, &error
);
5715 mono_error_cleanup (&error
);
5721 mono_array_new_full_checked (MonoDomain
*domain
, MonoClass
*array_class
, uintptr_t *lengths
, intptr_t *lower_bounds
, MonoError
*error
)
5723 MONO_REQ_GC_UNSAFE_MODE
;
5725 uintptr_t byte_len
= 0, len
, bounds_size
;
5728 MonoArrayBounds
*bounds
;
5732 mono_error_init (error
);
5734 if (!array_class
->inited
)
5735 mono_class_init (array_class
);
5739 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5740 if (array_class
->rank
== 1 && ((array_class
->byval_arg
.type
== MONO_TYPE_SZARRAY
) || (lower_bounds
&& lower_bounds
[0] == 0))) {
5742 if (len
> MONO_ARRAY_MAX_INDEX
) {
5743 mono_error_set_generic_error (error
, "System", "OverflowException", "");
5748 bounds_size
= sizeof (MonoArrayBounds
) * array_class
->rank
;
5750 for (i
= 0; i
< array_class
->rank
; ++i
) {
5751 if (lengths
[i
] > MONO_ARRAY_MAX_INDEX
) {
5752 mono_error_set_generic_error (error
, "System", "OverflowException", "");
5755 if (CHECK_MUL_OVERFLOW_UN (len
, lengths
[i
])) {
5756 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5763 if (!mono_array_calc_byte_len (array_class
, len
, &byte_len
)) {
5764 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5770 if (CHECK_ADD_OVERFLOW_UN (byte_len
, 3)) {
5771 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5774 byte_len
= (byte_len
+ 3) & ~3;
5775 if (CHECK_ADD_OVERFLOW_UN (byte_len
, bounds_size
)) {
5776 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5779 byte_len
+= bounds_size
;
5782 * Following three lines almost taken from mono_object_new ():
5783 * they need to be kept in sync.
5785 vtable
= mono_class_vtable_full (domain
, array_class
, error
);
5786 return_val_if_nok (error
, NULL
);
5789 o
= (MonoObject
*)mono_gc_alloc_array (vtable
, byte_len
, len
, bounds_size
);
5791 o
= (MonoObject
*)mono_gc_alloc_vector (vtable
, byte_len
, len
);
5793 if (G_UNLIKELY (!o
)) {
5794 mono_error_set_out_of_memory (error
, "Could not allocate %zd bytes", (gsize
) byte_len
);
5798 array
= (MonoArray
*)o
;
5800 bounds
= array
->bounds
;
5803 for (i
= 0; i
< array_class
->rank
; ++i
) {
5804 bounds
[i
].length
= lengths
[i
];
5806 bounds
[i
].lower_bound
= lower_bounds
[i
];
5815 * @domain: domain where the object is created
5816 * @eclass: element class
5817 * @n: number of array elements
5819 * This routine creates a new szarray with @n elements of type @eclass.
5822 mono_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
5824 MONO_REQ_GC_UNSAFE_MODE
;
5827 MonoArray
*result
= mono_array_new_checked (domain
, eclass
, n
, &error
);
5828 mono_error_cleanup (&error
);
5833 * mono_array_new_checked:
5834 * @domain: domain where the object is created
5835 * @eclass: element class
5836 * @n: number of array elements
5837 * @error: set on error
5839 * This routine creates a new szarray with @n elements of type @eclass.
5840 * On failure returns NULL and sets @error.
5843 mono_array_new_checked (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
, MonoError
*error
)
5847 mono_error_init (error
);
5849 ac
= mono_array_class_get (eclass
, 1);
5852 MonoVTable
*vtable
= mono_class_vtable_full (domain
, ac
, error
);
5853 return_val_if_nok (error
, NULL
);
5855 return mono_array_new_specific_checked (vtable
, n
, error
);
5859 ves_icall_array_new (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
)
5862 MonoArray
*arr
= mono_array_new_checked (domain
, eclass
, n
, &error
);
5863 mono_error_set_pending_exception (&error
);
5869 * mono_array_new_specific:
5870 * @vtable: a vtable in the appropriate domain for an initialized class
5871 * @n: number of array elements
5873 * This routine is a fast alternative to mono_array_new() for code which
5874 * can be sure about the domain it operates in.
5877 mono_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
5880 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, &error
);
5881 mono_error_cleanup (&error
);
5887 mono_array_new_specific_checked (MonoVTable
*vtable
, uintptr_t n
, MonoError
*error
)
5889 MONO_REQ_GC_UNSAFE_MODE
;
5894 mono_error_init (error
);
5896 if (G_UNLIKELY (n
> MONO_ARRAY_MAX_INDEX
)) {
5897 mono_error_set_generic_error (error
, "System", "OverflowException", "");
5901 if (!mono_array_calc_byte_len (vtable
->klass
, n
, &byte_len
)) {
5902 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE
);
5905 o
= (MonoObject
*)mono_gc_alloc_vector (vtable
, byte_len
, n
);
5907 if (G_UNLIKELY (!o
)) {
5908 mono_error_set_out_of_memory (error
, "Could not allocate %zd bytes", (gsize
) byte_len
);
5912 return (MonoArray
*)o
;
5916 ves_icall_array_new_specific (MonoVTable
*vtable
, uintptr_t n
)
5919 MonoArray
*arr
= mono_array_new_specific_checked (vtable
, n
, &error
);
5920 mono_error_set_pending_exception (&error
);
5926 * mono_string_empty_wrapper:
5928 * Returns: The same empty string instance as the managed string.Empty
5931 mono_string_empty_wrapper (void)
5933 MonoDomain
*domain
= mono_domain_get ();
5934 return mono_string_empty (domain
);
5938 * mono_string_empty:
5940 * Returns: The same empty string instance as the managed string.Empty
5943 mono_string_empty (MonoDomain
*domain
)
5946 g_assert (domain
->empty_string
);
5947 return domain
->empty_string
;
5951 * mono_string_new_utf16:
5952 * @text: a pointer to an utf16 string
5953 * @len: the length of the string
5955 * Returns: A newly created string object which contains @text.
5958 mono_string_new_utf16 (MonoDomain
*domain
, const guint16
*text
, gint32 len
)
5960 MONO_REQ_GC_UNSAFE_MODE
;
5963 MonoString
*res
= NULL
;
5964 res
= mono_string_new_utf16_checked (domain
, text
, len
, &error
);
5965 mono_error_cleanup (&error
);
5971 * mono_string_new_utf16_checked:
5972 * @text: a pointer to an utf16 string
5973 * @len: the length of the string
5974 * @error: written on error.
5976 * Returns: A newly created string object which contains @text.
5977 * On error, returns NULL and sets @error.
5980 mono_string_new_utf16_checked (MonoDomain
*domain
, const guint16
*text
, gint32 len
, MonoError
*error
)
5982 MONO_REQ_GC_UNSAFE_MODE
;
5986 mono_error_init (error
);
5988 s
= mono_string_new_size_checked (domain
, len
, error
);
5990 memcpy (mono_string_chars (s
), text
, len
* 2);
5996 * mono_string_new_utf32:
5997 * @text: a pointer to an utf32 string
5998 * @len: the length of the string
5999 * @error: set on failure.
6001 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6004 mono_string_new_utf32_checked (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
, MonoError
*error
)
6006 MONO_REQ_GC_UNSAFE_MODE
;
6009 mono_unichar2
*utf16_output
= NULL
;
6010 gint32 utf16_len
= 0;
6011 GError
*gerror
= NULL
;
6012 glong items_written
;
6014 mono_error_init (error
);
6015 utf16_output
= g_ucs4_to_utf16 (text
, len
, NULL
, &items_written
, &gerror
);
6018 g_error_free (gerror
);
6020 while (utf16_output
[utf16_len
]) utf16_len
++;
6022 s
= mono_string_new_size_checked (domain
, utf16_len
, error
);
6023 return_val_if_nok (error
, NULL
);
6025 memcpy (mono_string_chars (s
), utf16_output
, utf16_len
* 2);
6027 g_free (utf16_output
);
6033 * mono_string_new_utf32:
6034 * @text: a pointer to an utf32 string
6035 * @len: the length of the string
6037 * Returns: A newly created string object which contains @text.
6040 mono_string_new_utf32 (MonoDomain
*domain
, const mono_unichar4
*text
, gint32 len
)
6043 MonoString
*result
= mono_string_new_utf32_checked (domain
, text
, len
, &error
);
6044 mono_error_cleanup (&error
);
6049 * mono_string_new_size:
6050 * @text: a pointer to an utf16 string
6051 * @len: the length of the string
6053 * Returns: A newly created string object of @len
6056 mono_string_new_size (MonoDomain
*domain
, gint32 len
)
6059 MonoString
*str
= mono_string_new_size_checked (domain
, len
, &error
);
6060 mono_error_cleanup (&error
);
6066 mono_string_new_size_checked (MonoDomain
*domain
, gint32 len
, MonoError
*error
)
6068 MONO_REQ_GC_UNSAFE_MODE
;
6074 mono_error_init (error
);
6076 /* check for overflow */
6077 if (len
< 0 || len
> ((SIZE_MAX
- G_STRUCT_OFFSET (MonoString
, chars
) - 8) / 2)) {
6078 mono_error_set_out_of_memory (error
, "Could not allocate %i bytes", -1);
6082 size
= (G_STRUCT_OFFSET (MonoString
, chars
) + (((size_t)len
+ 1) * 2));
6083 g_assert (size
> 0);
6085 vtable
= mono_class_vtable (domain
, mono_defaults
.string_class
);
6088 s
= (MonoString
*)mono_gc_alloc_string (vtable
, size
, len
);
6090 if (G_UNLIKELY (!s
)) {
6091 mono_error_set_out_of_memory (error
, "Could not allocate %zd bytes", size
);
6099 * mono_string_new_len:
6100 * @text: a pointer to an utf8 string
6101 * @length: number of bytes in @text to consider
6103 * Returns: A newly created string object which contains @text.
6106 mono_string_new_len (MonoDomain
*domain
, const char *text
, guint length
)
6108 MONO_REQ_GC_UNSAFE_MODE
;
6111 MonoString
*result
= mono_string_new_len_checked (domain
, text
, length
, &error
);
6112 mono_error_cleanup (&error
);
6117 * mono_string_new_len_checked:
6118 * @text: a pointer to an utf8 string
6119 * @length: number of bytes in @text to consider
6120 * @error: set on error
6122 * Returns: A newly created string object which contains @text. On
6123 * failure returns NULL and sets @error.
6126 mono_string_new_len_checked (MonoDomain
*domain
, const char *text
, guint length
, MonoError
*error
)
6128 MONO_REQ_GC_UNSAFE_MODE
;
6130 mono_error_init (error
);
6132 GError
*eg_error
= NULL
;
6133 MonoString
*o
= NULL
;
6135 glong items_written
;
6137 ut
= eg_utf8_to_utf16_with_nuls (text
, length
, NULL
, &items_written
, &eg_error
);
6140 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6142 g_error_free (eg_error
);
6151 * @text: a pointer to an utf8 string
6153 * Returns: A newly created string object which contains @text.
6155 * This function asserts if it cannot allocate a new string.
6157 * @deprecated Use mono_string_new_checked in new code.
6160 mono_string_new (MonoDomain
*domain
, const char *text
)
6163 MonoString
*res
= NULL
;
6164 res
= mono_string_new_checked (domain
, text
, &error
);
6165 mono_error_assert_ok (&error
);
6170 * mono_string_new_checked:
6171 * @text: a pointer to an utf8 string
6172 * @merror: set on error
6174 * Returns: A newly created string object which contains @text.
6175 * On error returns NULL and sets @merror.
6178 mono_string_new_checked (MonoDomain
*domain
, const char *text
, MonoError
*error
)
6180 MONO_REQ_GC_UNSAFE_MODE
;
6182 GError
*eg_error
= NULL
;
6183 MonoString
*o
= NULL
;
6185 glong items_written
;
6188 mono_error_init (error
);
6192 ut
= g_utf8_to_utf16 (text
, l
, NULL
, &items_written
, &eg_error
);
6195 o
= mono_string_new_utf16_checked (domain
, ut
, items_written
, error
);
6197 g_error_free (eg_error
);
6201 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6206 MonoString
*o
= NULL
;
6208 if (!g_utf8_validate (text
, -1, &end
)) {
6209 mono_error_set_argument (error
, "text", "Not a valid utf8 string");
6213 len
= g_utf8_strlen (text
, -1);
6214 o
= mono_string_new_size_checked (domain
, len
, error
);
6217 str
= mono_string_chars (o
);
6219 while (text
< end
) {
6220 *str
++ = g_utf8_get_char (text
);
6221 text
= g_utf8_next_char (text
);
6230 * mono_string_new_wrapper:
6231 * @text: pointer to utf8 characters.
6233 * Helper function to create a string object from @text in the current domain.
6236 mono_string_new_wrapper (const char *text
)
6238 MONO_REQ_GC_UNSAFE_MODE
;
6240 MonoDomain
*domain
= mono_domain_get ();
6243 return mono_string_new (domain
, text
);
6250 * @class: the class of the value
6251 * @value: a pointer to the unboxed data
6253 * Returns: A newly created object which contains @value.
6256 mono_value_box (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
)
6259 MonoObject
*result
= mono_value_box_checked (domain
, klass
, value
, &error
);
6260 mono_error_cleanup (&error
);
6265 * mono_value_box_checked:
6266 * @domain: the domain of the new object
6267 * @class: the class of the value
6268 * @value: a pointer to the unboxed data
6269 * @error: set on error
6271 * Returns: A newly created object which contains @value. On failure
6272 * returns NULL and sets @error.
6275 mono_value_box_checked (MonoDomain
*domain
, MonoClass
*klass
, gpointer value
, MonoError
*error
)
6277 MONO_REQ_GC_UNSAFE_MODE
;
6282 mono_error_init (error
);
6284 g_assert (klass
->valuetype
);
6285 if (mono_class_is_nullable (klass
))
6286 return mono_nullable_box ((guint8
*)value
, klass
, error
);
6288 vtable
= mono_class_vtable (domain
, klass
);
6291 size
= mono_class_instance_size (klass
);
6292 res
= mono_object_new_alloc_specific_checked (vtable
, error
);
6293 return_val_if_nok (error
, NULL
);
6295 size
= size
- sizeof (MonoObject
);
6298 g_assert (size
== mono_class_value_size (klass
, NULL
));
6299 mono_gc_wbarrier_value_copy ((char *)res
+ sizeof (MonoObject
), value
, 1, klass
);
6301 #if NO_UNALIGNED_ACCESS
6302 mono_gc_memmove_atomic ((char *)res
+ sizeof (MonoObject
), value
, size
);
6306 *((guint8
*) res
+ sizeof (MonoObject
)) = *(guint8
*) value
;
6309 *(guint16
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint16
*) value
;
6312 *(guint32
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint32
*) value
;
6315 *(guint64
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint64
*) value
;
6318 mono_gc_memmove_atomic ((char *)res
+ sizeof (MonoObject
), value
, size
);
6322 if (klass
->has_finalize
) {
6323 mono_object_register_finalizer (res
);
6324 return_val_if_nok (error
, NULL
);
6331 * @dest: destination pointer
6332 * @src: source pointer
6333 * @klass: a valuetype class
6335 * Copy a valuetype from @src to @dest. This function must be used
6336 * when @klass contains references fields.
6339 mono_value_copy (gpointer dest
, gpointer src
, MonoClass
*klass
)
6341 MONO_REQ_GC_UNSAFE_MODE
;
6343 mono_gc_wbarrier_value_copy (dest
, src
, 1, klass
);
6347 * mono_value_copy_array:
6348 * @dest: destination array
6349 * @dest_idx: index in the @dest array
6350 * @src: source pointer
6351 * @count: number of items
6353 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6354 * This function must be used when @klass contains references fields.
6355 * Overlap is handled.
6358 mono_value_copy_array (MonoArray
*dest
, int dest_idx
, gpointer src
, int count
)
6360 MONO_REQ_GC_UNSAFE_MODE
;
6362 int size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
6363 char *d
= mono_array_addr_with_size_fast (dest
, size
, dest_idx
);
6364 g_assert (size
== mono_class_value_size (mono_object_class (dest
)->element_class
, NULL
));
6365 mono_gc_wbarrier_value_copy (d
, src
, count
, mono_object_class (dest
)->element_class
);
6369 * mono_object_get_domain:
6370 * @obj: object to query
6372 * Returns: the MonoDomain where the object is hosted
6375 mono_object_get_domain (MonoObject
*obj
)
6377 MONO_REQ_GC_UNSAFE_MODE
;
6379 return mono_object_domain (obj
);
6383 * mono_object_get_class:
6384 * @obj: object to query
6386 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6388 * Returns: the MonoClass of the object.
6391 mono_object_get_class (MonoObject
*obj
)
6393 MONO_REQ_GC_UNSAFE_MODE
;
6395 return mono_object_class (obj
);
6398 * mono_object_get_size:
6399 * @o: object to query
6401 * Returns: the size, in bytes, of @o
6404 mono_object_get_size (MonoObject
* o
)
6406 MONO_REQ_GC_UNSAFE_MODE
;
6408 MonoClass
* klass
= mono_object_class (o
);
6409 if (klass
== mono_defaults
.string_class
) {
6410 return sizeof (MonoString
) + 2 * mono_string_length ((MonoString
*) o
) + 2;
6411 } else if (o
->vtable
->rank
) {
6412 MonoArray
*array
= (MonoArray
*)o
;
6413 size_t size
= MONO_SIZEOF_MONO_ARRAY
+ mono_array_element_size (klass
) * mono_array_length (array
);
6414 if (array
->bounds
) {
6417 size
+= sizeof (MonoArrayBounds
) * o
->vtable
->rank
;
6421 return mono_class_instance_size (klass
);
6426 * mono_object_unbox:
6427 * @obj: object to unbox
6429 * Returns: a pointer to the start of the valuetype boxed in this
6432 * This method will assert if the object passed is not a valuetype.
6435 mono_object_unbox (MonoObject
*obj
)
6437 MONO_REQ_GC_UNSAFE_MODE
;
6439 /* add assert for valuetypes? */
6440 g_assert (obj
->vtable
->klass
->valuetype
);
6441 return ((char*)obj
) + sizeof (MonoObject
);
6445 * mono_object_isinst:
6447 * @klass: a pointer to a class
6449 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6452 mono_object_isinst (MonoObject
*obj
, MonoClass
*klass
)
6454 MONO_REQ_GC_UNSAFE_MODE
;
6457 MonoObject
*result
= mono_object_isinst_checked (obj
, klass
, &error
);
6458 mono_error_cleanup (&error
);
6464 * mono_object_isinst_checked:
6466 * @klass: a pointer to a class
6467 * @error: set on error
6469 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6470 * On failure returns NULL and sets @error.
6473 mono_object_isinst_checked (MonoObject
*obj
, MonoClass
*klass
, MonoError
*error
)
6475 MONO_REQ_GC_UNSAFE_MODE
;
6477 mono_error_init (error
);
6479 MonoObject
*result
= NULL
;
6482 mono_class_init (klass
);
6484 if (mono_class_is_marshalbyref (klass
) || mono_class_is_interface (klass
)) {
6485 result
= mono_object_isinst_mbyref_checked (obj
, klass
, error
);
6492 return mono_class_is_assignable_from (klass
, obj
->vtable
->klass
) ? obj
: NULL
;
6496 mono_object_isinst_mbyref (MonoObject
*obj
, MonoClass
*klass
)
6498 MONO_REQ_GC_UNSAFE_MODE
;
6501 MonoObject
*result
= mono_object_isinst_mbyref_checked (obj
, klass
, &error
);
6502 mono_error_cleanup (&error
); /* FIXME better API that doesn't swallow the error */
6507 mono_object_isinst_mbyref_checked (MonoObject
*obj
, MonoClass
*klass
, MonoError
*error
)
6509 MONO_REQ_GC_UNSAFE_MODE
;
6513 mono_error_init (error
);
6520 if (mono_class_is_interface (klass
)) {
6521 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt
, klass
->interface_id
)) {
6525 /* casting an array one of the invariant interfaces that must act as such */
6526 if (klass
->is_array_special_interface
) {
6527 if (mono_class_is_assignable_from (klass
, vt
->klass
))
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 else 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_handle_to_utf8 (MonoStringHandle s
, MonoError
*error
)
6957 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s
), error
);
6961 * mono_string_to_utf8_ignore:
6964 * Converts a MonoString to its UTF8 representation. Will ignore
6965 * invalid surrogate pairs.
6966 * The resulting buffer should be freed with mono_free().
6970 mono_string_to_utf8_ignore (MonoString
*s
)
6972 MONO_REQ_GC_UNSAFE_MODE
;
6981 return g_strdup ("");
6983 as
= g_utf16_to_utf8 (mono_string_chars (s
), s
->length
, NULL
, &written
, NULL
);
6985 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6986 if (s
->length
> written
) {
6987 /* allocate the total length and copy the part of the string that has been converted */
6988 char *as2
= (char *)g_malloc0 (s
->length
);
6989 memcpy (as2
, as
, written
);
6998 * mono_string_to_utf8_image_ignore:
6999 * @s: a System.String
7001 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7004 mono_string_to_utf8_image_ignore (MonoImage
*image
, MonoString
*s
)
7006 MONO_REQ_GC_UNSAFE_MODE
;
7008 return mono_string_to_utf8_internal (NULL
, image
, s
, TRUE
, NULL
);
7012 * mono_string_to_utf8_mp_ignore:
7013 * @s: a System.String
7015 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7018 mono_string_to_utf8_mp_ignore (MonoMemPool
*mp
, MonoString
*s
)
7020 MONO_REQ_GC_UNSAFE_MODE
;
7022 return mono_string_to_utf8_internal (mp
, NULL
, s
, TRUE
, NULL
);
7027 * mono_string_to_utf16:
7030 * Return an null-terminated array of the utf-16 chars
7031 * contained in @s. The result must be freed with g_free().
7032 * This is a temporary helper until our string implementation
7033 * is reworked to always include the null terminating char.
7036 mono_string_to_utf16 (MonoString
*s
)
7038 MONO_REQ_GC_UNSAFE_MODE
;
7045 as
= (char *)g_malloc ((s
->length
* 2) + 2);
7046 as
[(s
->length
* 2)] = '\0';
7047 as
[(s
->length
* 2) + 1] = '\0';
7050 return (gunichar2
*)(as
);
7053 memcpy (as
, mono_string_chars(s
), s
->length
* 2);
7054 return (gunichar2
*)(as
);
7058 * mono_string_to_utf32:
7061 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7062 * contained in @s. The result must be freed with g_free().
7065 mono_string_to_utf32 (MonoString
*s
)
7067 MONO_REQ_GC_UNSAFE_MODE
;
7069 mono_unichar4
*utf32_output
= NULL
;
7070 GError
*error
= NULL
;
7071 glong items_written
;
7076 utf32_output
= g_utf16_to_ucs4 (s
->chars
, s
->length
, NULL
, &items_written
, &error
);
7079 g_error_free (error
);
7081 return utf32_output
;
7085 * mono_string_from_utf16:
7086 * @data: the UTF16 string (LPWSTR) to convert
7088 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7090 * Returns: a MonoString.
7093 mono_string_from_utf16 (gunichar2
*data
)
7096 MonoString
*result
= mono_string_from_utf16_checked (data
, &error
);
7097 mono_error_cleanup (&error
);
7102 * mono_string_from_utf16_checked:
7103 * @data: the UTF16 string (LPWSTR) to convert
7104 * @error: set on error
7106 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7108 * Returns: a MonoString. On failure sets @error and returns NULL.
7111 mono_string_from_utf16_checked (gunichar2
*data
, MonoError
*error
)
7114 MONO_REQ_GC_UNSAFE_MODE
;
7116 mono_error_init (error
);
7117 MonoDomain
*domain
= mono_domain_get ();
7123 while (data
[len
]) len
++;
7125 return mono_string_new_utf16_checked (domain
, data
, len
, error
);
7129 * mono_string_from_utf32:
7130 * @data: the UTF32 string (LPWSTR) to convert
7132 * Converts a UTF32 (UCS-4)to a MonoString.
7134 * Returns: a MonoString.
7137 mono_string_from_utf32 (mono_unichar4
*data
)
7140 MonoString
*result
= mono_string_from_utf32_checked (data
, &error
);
7141 mono_error_cleanup (&error
);
7146 * mono_string_from_utf32_checked:
7147 * @data: the UTF32 string (LPWSTR) to convert
7148 * @error: set on error
7150 * Converts a UTF32 (UCS-4)to a MonoString.
7152 * Returns: a MonoString. On failure returns NULL and sets @error.
7155 mono_string_from_utf32_checked (mono_unichar4
*data
, MonoError
*error
)
7157 MONO_REQ_GC_UNSAFE_MODE
;
7159 mono_error_init (error
);
7160 MonoString
* result
= NULL
;
7161 mono_unichar2
*utf16_output
= NULL
;
7162 GError
*gerror
= NULL
;
7163 glong items_written
;
7169 while (data
[len
]) len
++;
7171 utf16_output
= g_ucs4_to_utf16 (data
, len
, NULL
, &items_written
, &gerror
);
7174 g_error_free (gerror
);
7176 result
= mono_string_from_utf16_checked (utf16_output
, error
);
7177 g_free (utf16_output
);
7182 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, gboolean ignore_error
, MonoError
*error
)
7184 MONO_REQ_GC_UNSAFE_MODE
;
7191 r
= mono_string_to_utf8_ignore (s
);
7193 r
= mono_string_to_utf8_checked (s
, error
);
7194 if (!mono_error_ok (error
))
7201 len
= strlen (r
) + 1;
7203 mp_s
= (char *)mono_mempool_alloc (mp
, len
);
7205 mp_s
= (char *)mono_image_alloc (image
, len
);
7207 memcpy (mp_s
, r
, len
);
7215 * mono_string_to_utf8_image:
7216 * @s: a System.String
7218 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7221 mono_string_to_utf8_image (MonoImage
*image
, MonoString
*s
, MonoError
*error
)
7223 MONO_REQ_GC_UNSAFE_MODE
;
7225 return mono_string_to_utf8_internal (NULL
, image
, s
, FALSE
, error
);
7229 * mono_string_to_utf8_mp:
7230 * @s: a System.String
7232 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7235 mono_string_to_utf8_mp (MonoMemPool
*mp
, MonoString
*s
, MonoError
*error
)
7237 MONO_REQ_GC_UNSAFE_MODE
;
7239 return mono_string_to_utf8_internal (mp
, NULL
, s
, FALSE
, error
);
7243 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks
;
7246 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks
*cbs
)
7248 eh_callbacks
= *cbs
;
7251 MonoRuntimeExceptionHandlingCallbacks
*
7252 mono_get_eh_callbacks (void)
7254 return &eh_callbacks
;
7258 * mono_raise_exception:
7259 * @ex: exception object
7261 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7264 mono_raise_exception (MonoException
*ex
)
7266 MONO_REQ_GC_UNSAFE_MODE
;
7269 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7270 * that will cause gcc to omit the function epilog, causing problems when
7271 * the JIT tries to walk the stack, since the return address on the stack
7272 * will point into the next function in the executable, not this one.
7274 eh_callbacks
.mono_raise_exception (ex
);
7278 mono_raise_exception_with_context (MonoException
*ex
, MonoContext
*ctx
)
7280 MONO_REQ_GC_UNSAFE_MODE
;
7282 eh_callbacks
.mono_raise_exception_with_ctx (ex
, ctx
);
7286 * mono_wait_handle_new:
7287 * @domain: Domain where the object will be created
7288 * @handle: Handle for the wait handle
7289 * @error: set on error.
7291 * Returns: A new MonoWaitHandle created in the given domain for the
7292 * given handle. On failure returns NULL and sets @rror.
7295 mono_wait_handle_new (MonoDomain
*domain
, HANDLE handle
, MonoError
*error
)
7297 MONO_REQ_GC_UNSAFE_MODE
;
7299 MonoWaitHandle
*res
;
7300 gpointer params
[1];
7301 static MonoMethod
*handle_set
;
7303 mono_error_init (error
);
7304 res
= (MonoWaitHandle
*)mono_object_new_checked (domain
, mono_defaults
.manualresetevent_class
, error
);
7305 return_val_if_nok (error
, NULL
);
7307 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7309 handle_set
= mono_class_get_property_from_name (mono_defaults
.manualresetevent_class
, "Handle")->set
;
7311 params
[0] = &handle
;
7313 mono_runtime_invoke_checked (handle_set
, res
, params
, error
);
7318 mono_wait_handle_get_handle (MonoWaitHandle
*handle
)
7320 MONO_REQ_GC_UNSAFE_MODE
;
7322 static MonoClassField
*f_safe_handle
= NULL
;
7325 if (!f_safe_handle
) {
7326 f_safe_handle
= mono_class_get_field_from_name (mono_defaults
.manualresetevent_class
, "safeWaitHandle");
7327 g_assert (f_safe_handle
);
7330 mono_field_get_value ((MonoObject
*)handle
, f_safe_handle
, &sh
);
7336 mono_runtime_capture_context (MonoDomain
*domain
, MonoError
*error
)
7338 MONO_REQ_GC_UNSAFE_MODE
;
7340 RuntimeInvokeFunction runtime_invoke
;
7342 mono_error_init (error
);
7344 if (!domain
->capture_context_runtime_invoke
|| !domain
->capture_context_method
) {
7345 MonoMethod
*method
= mono_get_context_capture_method ();
7346 MonoMethod
*wrapper
;
7349 wrapper
= mono_marshal_get_runtime_invoke (method
, FALSE
);
7350 domain
->capture_context_runtime_invoke
= mono_compile_method_checked (wrapper
, error
);
7351 return_val_if_nok (error
, NULL
);
7352 domain
->capture_context_method
= mono_compile_method_checked (method
, error
);
7353 return_val_if_nok (error
, NULL
);
7356 runtime_invoke
= (RuntimeInvokeFunction
)domain
->capture_context_runtime_invoke
;
7358 return runtime_invoke (NULL
, NULL
, NULL
, domain
->capture_context_method
);
7361 * mono_async_result_new:
7362 * @domain:domain where the object will be created.
7363 * @handle: wait handle.
7364 * @state: state to pass to AsyncResult
7365 * @data: C closure data.
7366 * @error: set on error.
7368 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7369 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7370 * On failure returns NULL and sets @error.
7374 mono_async_result_new (MonoDomain
*domain
, HANDLE handle
, MonoObject
*state
, gpointer data
, MonoObject
*object_data
, MonoError
*error
)
7376 MONO_REQ_GC_UNSAFE_MODE
;
7378 mono_error_init (error
);
7379 MonoAsyncResult
*res
= (MonoAsyncResult
*)mono_object_new_checked (domain
, mono_defaults
.asyncresult_class
, error
);
7380 return_val_if_nok (error
, NULL
);
7381 MonoObject
*context
= mono_runtime_capture_context (domain
, error
);
7382 return_val_if_nok (error
, NULL
);
7383 /* we must capture the execution context from the original thread */
7385 MONO_OBJECT_SETREF (res
, execution_context
, context
);
7386 /* note: result may be null if the flow is suppressed */
7389 res
->data
= (void **)data
;
7390 MONO_OBJECT_SETREF (res
, object_data
, object_data
);
7391 MONO_OBJECT_SETREF (res
, async_state
, state
);
7392 MonoWaitHandle
*wait_handle
= mono_wait_handle_new (domain
, handle
, error
);
7393 return_val_if_nok (error
, NULL
);
7395 MONO_OBJECT_SETREF (res
, handle
, (MonoObject
*) wait_handle
);
7397 res
->sync_completed
= FALSE
;
7398 res
->completed
= FALSE
;
7404 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult
*ares
)
7406 MONO_REQ_GC_UNSAFE_MODE
;
7413 g_assert (ares
->async_delegate
);
7415 ac
= (MonoAsyncCall
*) ares
->object_data
;
7417 res
= mono_runtime_delegate_invoke_checked (ares
->async_delegate
, (void**) &ares
->async_state
, &error
);
7418 if (mono_error_set_pending_exception (&error
))
7421 gpointer wait_event
= NULL
;
7423 ac
->msg
->exc
= NULL
;
7425 res
= mono_message_invoke (ares
->async_delegate
, ac
->msg
, &ac
->msg
->exc
, &ac
->out_args
, &error
);
7427 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7428 mono_threads_begin_abort_protected_block ();
7430 if (!ac
->msg
->exc
) {
7431 MonoException
*ex
= mono_error_convert_to_exception (&error
);
7432 ac
->msg
->exc
= (MonoObject
*)ex
;
7434 mono_error_cleanup (&error
);
7437 MONO_OBJECT_SETREF (ac
, res
, res
);
7439 mono_monitor_enter ((MonoObject
*) ares
);
7440 ares
->completed
= 1;
7442 wait_event
= mono_wait_handle_get_handle ((MonoWaitHandle
*) ares
->handle
);
7443 mono_monitor_exit ((MonoObject
*) ares
);
7445 if (wait_event
!= NULL
)
7446 mono_w32event_set (wait_event
);
7448 mono_error_init (&error
); //the else branch would leave it in an undefined state
7450 mono_runtime_invoke_checked (ac
->cb_method
, ac
->cb_target
, (gpointer
*) &ares
, &error
);
7452 mono_threads_end_abort_protected_block ();
7454 if (mono_error_set_pending_exception (&error
))
7462 mono_message_init (MonoDomain
*domain
,
7463 MonoMethodMessage
*this_obj
,
7464 MonoReflectionMethod
*method
,
7465 MonoArray
*out_args
,
7468 MONO_REQ_GC_UNSAFE_MODE
;
7470 static MonoMethod
*init_message_method
= NULL
;
7472 if (!init_message_method
) {
7473 init_message_method
= mono_class_get_method_from_name (mono_defaults
.mono_method_message_class
, "InitMessage", 2);
7474 g_assert (init_message_method
!= NULL
);
7477 mono_error_init (error
);
7478 /* FIXME set domain instead? */
7479 g_assert (domain
== mono_domain_get ());
7486 mono_runtime_invoke_checked (init_message_method
, this_obj
, args
, error
);
7487 return is_ok (error
);
7490 #ifndef DISABLE_REMOTING
7492 * mono_remoting_invoke:
7493 * @real_proxy: pointer to a RealProxy object
7494 * @msg: The MonoMethodMessage to execute
7495 * @exc: used to store exceptions
7496 * @out_args: used to store output arguments
7498 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7499 * IMessage interface and it is not trivial to extract results from there. So
7500 * we call an helper method PrivateInvoke instead of calling
7501 * RealProxy::Invoke() directly.
7503 * Returns: the result object.
7506 mono_remoting_invoke (MonoObject
*real_proxy
, MonoMethodMessage
*msg
, MonoObject
**exc
, MonoArray
**out_args
, MonoError
*error
)
7508 MONO_REQ_GC_UNSAFE_MODE
;
7511 MonoMethod
*im
= real_proxy
->vtable
->domain
->private_invoke_method
;
7516 mono_error_init (error
);
7518 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7521 im
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "PrivateInvoke", 4);
7523 mono_error_set_not_supported (error
, "Linked away.");
7526 real_proxy
->vtable
->domain
->private_invoke_method
= im
;
7529 pa
[0] = real_proxy
;
7534 o
= mono_runtime_try_invoke (im
, NULL
, pa
, exc
, error
);
7535 return_val_if_nok (error
, NULL
);
7542 mono_message_invoke (MonoObject
*target
, MonoMethodMessage
*msg
,
7543 MonoObject
**exc
, MonoArray
**out_args
, MonoError
*error
)
7545 MONO_REQ_GC_UNSAFE_MODE
;
7547 static MonoClass
*object_array_klass
;
7548 mono_error_init (error
);
7552 MonoMethodSignature
*sig
;
7554 int i
, j
, outarg_count
= 0;
7556 #ifndef DISABLE_REMOTING
7557 if (target
&& mono_object_is_transparent_proxy (target
)) {
7558 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)target
;
7559 if (mono_class_is_contextbound (tp
->remote_class
->proxy_class
) && tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
7560 target
= tp
->rp
->unwrapped_server
;
7562 return mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, exc
, out_args
, error
);
7567 domain
= mono_domain_get ();
7568 method
= msg
->method
->method
;
7569 sig
= mono_method_signature (method
);
7571 for (i
= 0; i
< sig
->param_count
; i
++) {
7572 if (sig
->params
[i
]->byref
)
7576 if (!object_array_klass
) {
7579 klass
= mono_array_class_get (mono_defaults
.object_class
, 1);
7582 mono_memory_barrier ();
7583 object_array_klass
= klass
;
7586 arr
= mono_array_new_specific_checked (mono_class_vtable (domain
, object_array_klass
), outarg_count
, error
);
7587 return_val_if_nok (error
, NULL
);
7589 mono_gc_wbarrier_generic_store (out_args
, (MonoObject
*) arr
);
7592 MonoObject
*ret
= mono_runtime_try_invoke_array (method
, method
->klass
->valuetype
? mono_object_unbox (target
): target
, msg
->args
, exc
, error
);
7593 return_val_if_nok (error
, NULL
);
7595 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
7596 if (sig
->params
[i
]->byref
) {
7598 arg
= (MonoObject
*)mono_array_get (msg
->args
, gpointer
, i
);
7599 mono_array_setref (*out_args
, j
, arg
);
7608 * prepare_to_string_method:
7610 * @target: Set to @obj or unboxed value if a valuetype
7612 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7615 prepare_to_string_method (MonoObject
*obj
, void **target
)
7617 MONO_REQ_GC_UNSAFE_MODE
;
7619 static MonoMethod
*to_string
= NULL
;
7627 to_string
= mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL
| METHOD_ATTRIBUTE_PUBLIC
);
7629 method
= mono_object_get_virtual_method (obj
, to_string
);
7631 // Unbox value type if needed
7632 if (mono_class_is_valuetype (mono_method_get_class (method
))) {
7633 *target
= mono_object_unbox (obj
);
7639 * mono_object_to_string:
7641 * @exc: Any exception thrown by ToString (). May be NULL.
7643 * Returns: the result of calling ToString () on an object.
7646 mono_object_to_string (MonoObject
*obj
, MonoObject
**exc
)
7649 MonoString
*s
= NULL
;
7651 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
7653 s
= (MonoString
*) mono_runtime_try_invoke (method
, target
, NULL
, exc
, &error
);
7654 if (*exc
== NULL
&& !mono_error_ok (&error
))
7655 *exc
= (MonoObject
*) mono_error_convert_to_exception (&error
);
7657 mono_error_cleanup (&error
);
7659 s
= (MonoString
*) mono_runtime_invoke_checked (method
, target
, NULL
, &error
);
7660 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
7667 * mono_object_to_string_checked:
7669 * @error: Set on error.
7671 * Returns: the result of calling ToString () on an object. If the
7672 * method cannot be invoked or if it raises an exception, sets @error
7676 mono_object_to_string_checked (MonoObject
*obj
, MonoError
*error
)
7678 mono_error_init (error
);
7680 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
7681 return (MonoString
*) mono_runtime_invoke_checked (method
, target
, NULL
, error
);
7685 * mono_object_try_to_string:
7687 * @exc: Any exception thrown by ToString (). Must not be NULL.
7688 * @error: Set if method cannot be invoked.
7690 * Returns: the result of calling ToString () on an object. If the
7691 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7695 mono_object_try_to_string (MonoObject
*obj
, MonoObject
**exc
, MonoError
*error
)
7698 mono_error_init (error
);
7700 MonoMethod
*method
= prepare_to_string_method (obj
, &target
);
7701 return (MonoString
*) mono_runtime_try_invoke (method
, target
, NULL
, exc
, error
);
7707 get_native_backtrace (MonoException
*exc_raw
)
7709 HANDLE_FUNCTION_ENTER ();
7710 MONO_HANDLE_DCL(MonoException
, exc
);
7711 char * trace
= mono_exception_handle_get_native_backtrace (exc
);
7712 HANDLE_FUNCTION_RETURN_VAL (trace
);
7716 * mono_print_unhandled_exception:
7717 * @exc: The exception
7719 * Prints the unhandled exception.
7722 mono_print_unhandled_exception (MonoObject
*exc
)
7724 MONO_REQ_GC_UNSAFE_MODE
;
7727 char *message
= (char*)"";
7728 gboolean free_message
= FALSE
;
7731 if (exc
== (MonoObject
*)mono_object_domain (exc
)->out_of_memory_ex
) {
7732 message
= g_strdup ("OutOfMemoryException");
7733 free_message
= TRUE
;
7734 } else if (exc
== (MonoObject
*)mono_object_domain (exc
)->stack_overflow_ex
) {
7735 message
= g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7736 free_message
= TRUE
;
7739 if (((MonoException
*)exc
)->native_trace_ips
) {
7740 message
= get_native_backtrace ((MonoException
*)exc
);
7741 free_message
= TRUE
;
7743 MonoObject
*other_exc
= NULL
;
7744 str
= mono_object_try_to_string (exc
, &other_exc
, &error
);
7745 if (other_exc
== NULL
&& !is_ok (&error
))
7746 other_exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
7748 mono_error_cleanup (&error
);
7750 char *original_backtrace
= mono_exception_get_managed_backtrace ((MonoException
*)exc
);
7751 char *nested_backtrace
= mono_exception_get_managed_backtrace ((MonoException
*)other_exc
);
7753 message
= g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7754 original_backtrace
, nested_backtrace
);
7756 g_free (original_backtrace
);
7757 g_free (nested_backtrace
);
7758 free_message
= TRUE
;
7760 message
= mono_string_to_utf8_checked (str
, &error
);
7761 if (!mono_error_ok (&error
)) {
7762 mono_error_cleanup (&error
);
7763 message
= (char *) "";
7765 free_message
= TRUE
;
7772 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7773 * exc->vtable->klass->name, message);
7775 g_printerr ("\nUnhandled Exception:\n%s\n", message
);
7782 * mono_delegate_ctor_with_method:
7783 * @this: pointer to an uninitialized delegate object
7784 * @target: target object
7785 * @addr: pointer to native code
7787 * @error: set on error.
7789 * Initialize a delegate and sets a specific method, not the one
7790 * associated with addr. This is useful when sharing generic code.
7791 * In that case addr will most probably not be associated with the
7792 * correct instantiation of the method.
7793 * On failure returns FALSE and sets @error.
7796 mono_delegate_ctor_with_method (MonoObject
*this_obj
, MonoObject
*target
, gpointer addr
, MonoMethod
*method
, MonoError
*error
)
7798 MONO_REQ_GC_UNSAFE_MODE
;
7800 mono_error_init (error
);
7801 MonoDelegate
*delegate
= (MonoDelegate
*)this_obj
;
7803 g_assert (this_obj
);
7806 g_assert (mono_class_has_parent (mono_object_class (this_obj
), mono_defaults
.multicastdelegate_class
));
7809 delegate
->method
= method
;
7811 mono_stats
.delegate_creations
++;
7813 #ifndef DISABLE_REMOTING
7814 if (target
&& target
->vtable
->klass
== mono_defaults
.transparent_proxy_class
) {
7816 method
= mono_marshal_get_remoting_invoke (method
);
7817 delegate
->method_ptr
= mono_compile_method_checked (method
, error
);
7818 return_val_if_nok (error
, FALSE
);
7819 MONO_OBJECT_SETREF (delegate
, target
, target
);
7823 delegate
->method_ptr
= addr
;
7824 MONO_OBJECT_SETREF (delegate
, target
, target
);
7827 delegate
->invoke_impl
= callbacks
.create_delegate_trampoline (delegate
->object
.vtable
->domain
, delegate
->object
.vtable
->klass
);
7828 if (callbacks
.init_delegate
)
7829 callbacks
.init_delegate (delegate
);
7834 * mono_delegate_ctor:
7835 * @this: pointer to an uninitialized delegate object
7836 * @target: target object
7837 * @addr: pointer to native code
7838 * @error: set on error.
7840 * This is used to initialize a delegate.
7841 * On failure returns FALSE and sets @error.
7844 mono_delegate_ctor (MonoObject
*this_obj
, MonoObject
*target
, gpointer addr
, MonoError
*error
)
7846 MONO_REQ_GC_UNSAFE_MODE
;
7848 mono_error_init (error
);
7849 MonoDomain
*domain
= mono_domain_get ();
7851 MonoMethod
*method
= NULL
;
7855 ji
= mono_jit_info_table_find (domain
, (char *)mono_get_addr_from_ftnptr (addr
));
7857 if (!ji
&& domain
!= mono_get_root_domain ())
7858 ji
= mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr
));
7860 method
= mono_jit_info_get_method (ji
);
7861 g_assert (!mono_class_is_gtd (method
->klass
));
7864 return mono_delegate_ctor_with_method (this_obj
, target
, addr
, method
, error
);
7868 * mono_method_call_message_new:
7869 * @method: method to encapsulate
7870 * @params: parameters to the method
7871 * @invoke: optional, delegate invoke.
7872 * @cb: async callback delegate.
7873 * @state: state passed to the async callback.
7874 * @error: set on error.
7876 * Translates arguments pointers into a MonoMethodMessage.
7877 * On failure returns NULL and sets @error.
7880 mono_method_call_message_new (MonoMethod
*method
, gpointer
*params
, MonoMethod
*invoke
,
7881 MonoDelegate
**cb
, MonoObject
**state
, MonoError
*error
)
7883 MONO_REQ_GC_UNSAFE_MODE
;
7885 mono_error_init (error
);
7887 MonoDomain
*domain
= mono_domain_get ();
7888 MonoMethodSignature
*sig
= mono_method_signature (method
);
7889 MonoMethodMessage
*msg
;
7892 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
7893 return_val_if_nok (error
, NULL
);
7896 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, invoke
, NULL
, error
);
7897 return_val_if_nok (error
, NULL
);
7898 mono_message_init (domain
, msg
, rm
, NULL
, error
);
7899 return_val_if_nok (error
, NULL
);
7900 count
= sig
->param_count
- 2;
7902 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
7903 return_val_if_nok (error
, NULL
);
7904 mono_message_init (domain
, msg
, rm
, NULL
, error
);
7905 return_val_if_nok (error
, NULL
);
7906 count
= sig
->param_count
;
7909 for (i
= 0; i
< count
; i
++) {
7914 if (sig
->params
[i
]->byref
)
7915 vpos
= *((gpointer
*)params
[i
]);
7919 klass
= mono_class_from_mono_type (sig
->params
[i
]);
7921 if (klass
->valuetype
) {
7922 arg
= mono_value_box_checked (domain
, klass
, vpos
, error
);
7923 return_val_if_nok (error
, NULL
);
7925 arg
= *((MonoObject
**)vpos
);
7927 mono_array_setref (msg
->args
, i
, arg
);
7930 if (cb
!= NULL
&& state
!= NULL
) {
7931 *cb
= *((MonoDelegate
**)params
[i
]);
7933 *state
= *((MonoObject
**)params
[i
]);
7940 * mono_method_return_message_restore:
7942 * Restore results from message based processing back to arguments pointers
7945 mono_method_return_message_restore (MonoMethod
*method
, gpointer
*params
, MonoArray
*out_args
, MonoError
*error
)
7947 MONO_REQ_GC_UNSAFE_MODE
;
7949 mono_error_init (error
);
7951 MonoMethodSignature
*sig
= mono_method_signature (method
);
7952 int i
, j
, type
, size
, out_len
;
7954 if (out_args
== NULL
)
7956 out_len
= mono_array_length (out_args
);
7960 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
7961 MonoType
*pt
= sig
->params
[i
];
7966 mono_error_set_execution_engine (error
, "The proxy call returned an incorrect number of output arguments");
7970 arg
= (char *)mono_array_get (out_args
, gpointer
, j
);
7973 g_assert (type
!= MONO_TYPE_VOID
);
7975 if (MONO_TYPE_IS_REFERENCE (pt
)) {
7976 mono_gc_wbarrier_generic_store (*((MonoObject
***)params
[i
]), (MonoObject
*)arg
);
7979 MonoClass
*klass
= ((MonoObject
*)arg
)->vtable
->klass
;
7980 size
= mono_class_value_size (klass
, NULL
);
7981 if (klass
->has_references
)
7982 mono_gc_wbarrier_value_copy (*((gpointer
*)params
[i
]), arg
+ sizeof (MonoObject
), 1, klass
);
7984 mono_gc_memmove_atomic (*((gpointer
*)params
[i
]), arg
+ sizeof (MonoObject
), size
);
7986 size
= mono_class_value_size (mono_class_from_mono_type (pt
), NULL
);
7987 mono_gc_bzero_atomic (*((gpointer
*)params
[i
]), size
);
7996 #ifndef DISABLE_REMOTING
7999 * mono_load_remote_field:
8000 * @this: pointer to an object
8001 * @klass: klass of the object containing @field
8002 * @field: the field to load
8003 * @res: a storage to store the result
8005 * This method is called by the runtime on attempts to load fields of
8006 * transparent proxy objects. @this points to such TP, @klass is the class of
8007 * the object containing @field. @res is a storage location which can be
8008 * used to store the result.
8010 * Returns: an address pointing to the value of field.
8013 mono_load_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
)
8016 gpointer result
= mono_load_remote_field_checked (this_obj
, klass
, field
, res
, &error
);
8017 mono_error_cleanup (&error
);
8022 * mono_load_remote_field_checked:
8023 * @this: pointer to an object
8024 * @klass: klass of the object containing @field
8025 * @field: the field to load
8026 * @res: a storage to store the result
8027 * @error: set on error
8029 * This method is called by the runtime on attempts to load fields of
8030 * transparent proxy objects. @this points to such TP, @klass is the class of
8031 * the object containing @field. @res is a storage location which can be
8032 * used to store the result.
8034 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8037 mono_load_remote_field_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
, MonoError
*error
)
8039 MONO_REQ_GC_UNSAFE_MODE
;
8041 static MonoMethod
*getter
= NULL
;
8043 mono_error_init (error
);
8045 MonoDomain
*domain
= mono_domain_get ();
8046 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this_obj
;
8047 MonoClass
*field_class
;
8048 MonoMethodMessage
*msg
;
8049 MonoArray
*out_args
;
8053 g_assert (mono_object_is_transparent_proxy (this_obj
));
8054 g_assert (res
!= NULL
);
8056 if (mono_class_is_contextbound (tp
->remote_class
->proxy_class
) && tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
8057 mono_field_get_value (tp
->rp
->unwrapped_server
, field
, res
);
8062 getter
= mono_class_get_method_from_name (mono_defaults
.object_class
, "FieldGetter", -1);
8064 mono_error_set_not_supported (error
, "Linked away.");
8069 field_class
= mono_class_from_mono_type (field
->type
);
8071 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
8072 return_val_if_nok (error
, NULL
);
8073 out_args
= mono_array_new_checked (domain
, mono_defaults
.object_class
, 1, error
);
8074 return_val_if_nok (error
, NULL
);
8075 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, getter
, NULL
, error
);
8076 return_val_if_nok (error
, NULL
);
8077 mono_message_init (domain
, msg
, rm
, out_args
, error
);
8078 return_val_if_nok (error
, NULL
);
8080 full_name
= mono_type_get_full_name (klass
);
8081 mono_array_setref (msg
->args
, 0, mono_string_new (domain
, full_name
));
8082 mono_array_setref (msg
->args
, 1, mono_string_new (domain
, mono_field_get_name (field
)));
8085 mono_remoting_invoke ((MonoObject
*)(tp
->rp
), msg
, &exc
, &out_args
, error
);
8086 return_val_if_nok (error
, NULL
);
8089 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
8093 if (mono_array_length (out_args
) == 0)
8096 mono_gc_wbarrier_generic_store (res
, mono_array_get (out_args
, MonoObject
*, 0));
8098 if (field_class
->valuetype
) {
8099 return ((char *)*res
) + sizeof (MonoObject
);
8105 * mono_load_remote_field_new:
8110 * Missing documentation.
8113 mono_load_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
)
8117 MonoObject
*result
= mono_load_remote_field_new_checked (this_obj
, klass
, field
, &error
);
8118 mono_error_cleanup (&error
);
8123 * mono_load_remote_field_new_checked:
8124 * @this: pointer to an object
8125 * @klass: klass of the object containing @field
8126 * @field: the field to load
8127 * @error: set on error.
8129 * This method is called by the runtime on attempts to load fields of
8130 * transparent proxy objects. @this points to such TP, @klass is the class of
8131 * the object containing @field.
8133 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8136 mono_load_remote_field_new_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoError
*error
)
8138 MONO_REQ_GC_UNSAFE_MODE
;
8140 mono_error_init (error
);
8142 static MonoMethod
*tp_load
= NULL
;
8144 g_assert (mono_object_is_transparent_proxy (this_obj
));
8147 tp_load
= mono_class_get_method_from_name (mono_defaults
.transparent_proxy_class
, "LoadRemoteFieldNew", -1);
8149 mono_error_set_not_supported (error
, "Linked away.");
8154 /* MonoType *type = mono_class_get_type (klass); */
8160 return mono_runtime_invoke_checked (tp_load
, this_obj
, args
, error
);
8164 * mono_store_remote_field:
8165 * @this_obj: pointer to an object
8166 * @klass: klass of the object containing @field
8167 * @field: the field to load
8168 * @val: the value/object to store
8170 * This method is called by the runtime on attempts to store fields of
8171 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8172 * the object containing @field. @val is the new value to store in @field.
8175 mono_store_remote_field (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
)
8178 (void) mono_store_remote_field_checked (this_obj
, klass
, field
, val
, &error
);
8179 mono_error_cleanup (&error
);
8183 * mono_store_remote_field_checked:
8184 * @this_obj: pointer to an object
8185 * @klass: klass of the object containing @field
8186 * @field: the field to load
8187 * @val: the value/object to store
8188 * @error: set on error
8190 * This method is called by the runtime on attempts to store fields of
8191 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8192 * the object containing @field. @val is the new value to store in @field.
8194 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8197 mono_store_remote_field_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, gpointer val
, MonoError
*error
)
8200 MONO_REQ_GC_UNSAFE_MODE
;
8202 mono_error_init (error
);
8204 MonoDomain
*domain
= mono_domain_get ();
8205 MonoClass
*field_class
;
8208 g_assert (mono_object_is_transparent_proxy (this_obj
));
8210 field_class
= mono_class_from_mono_type (field
->type
);
8212 if (field_class
->valuetype
) {
8213 arg
= mono_value_box_checked (domain
, field_class
, val
, error
);
8214 return_val_if_nok (error
, FALSE
);
8216 arg
= *((MonoObject
**)val
);
8219 return mono_store_remote_field_new_checked (this_obj
, klass
, field
, arg
, error
);
8223 * mono_store_remote_field_new:
8229 * Missing documentation
8232 mono_store_remote_field_new (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
)
8235 (void) mono_store_remote_field_new_checked (this_obj
, klass
, field
, arg
, &error
);
8236 mono_error_cleanup (&error
);
8240 * mono_store_remote_field_new_checked:
8247 * Missing documentation
8250 mono_store_remote_field_new_checked (MonoObject
*this_obj
, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
, MonoError
*error
)
8252 MONO_REQ_GC_UNSAFE_MODE
;
8254 static MonoMethod
*tp_store
= NULL
;
8256 mono_error_init (error
);
8258 g_assert (mono_object_is_transparent_proxy (this_obj
));
8261 tp_store
= mono_class_get_method_from_name (mono_defaults
.transparent_proxy_class
, "StoreRemoteField", -1);
8263 mono_error_set_not_supported (error
, "Linked away.");
8273 mono_runtime_invoke_checked (tp_store
, this_obj
, args
, error
);
8274 return is_ok (error
);
8279 * mono_create_ftnptr:
8281 * Given a function address, create a function descriptor for it.
8282 * This is only needed on some platforms.
8285 mono_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
8287 return callbacks
.create_ftnptr (domain
, addr
);
8291 * mono_get_addr_from_ftnptr:
8293 * Given a pointer to a function descriptor, return the function address.
8294 * This is only needed on some platforms.
8297 mono_get_addr_from_ftnptr (gpointer descr
)
8299 return callbacks
.get_addr_from_ftnptr (descr
);
8303 * mono_string_chars:
8306 * Returns a pointer to the UCS16 characters stored in the MonoString
8309 mono_string_chars (MonoString
*s
)
8311 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8317 * mono_string_length:
8320 * Returns the lenght in characters of the string
8323 mono_string_length (MonoString
*s
)
8325 MONO_REQ_GC_UNSAFE_MODE
;
8331 * mono_array_length:
8332 * @array: a MonoArray*
8334 * Returns the total number of elements in the array. This works for
8335 * both vectors and multidimensional arrays.
8338 mono_array_length (MonoArray
*array
)
8340 MONO_REQ_GC_UNSAFE_MODE
;
8342 return array
->max_length
;
8346 * mono_array_addr_with_size:
8347 * @array: a MonoArray*
8348 * @size: size of the array elements
8349 * @idx: index into the array
8351 * Use this function to obtain the address for the @idx item on the
8352 * @array containing elements of size @size.
8354 * This method performs no bounds checking or type checking.
8356 * Returns the address of the @idx element in the array.
8359 mono_array_addr_with_size (MonoArray
*array
, int size
, uintptr_t idx
)
8361 MONO_REQ_GC_UNSAFE_MODE
;
8363 return ((char*)(array
)->vector
) + size
* idx
;
8368 mono_glist_to_array (GList
*list
, MonoClass
*eclass
, MonoError
*error
)
8370 MonoDomain
*domain
= mono_domain_get ();
8374 mono_error_init (error
);
8378 len
= g_list_length (list
);
8379 res
= mono_array_new_checked (domain
, eclass
, len
, error
);
8380 return_val_if_nok (error
, NULL
);
8382 for (i
= 0; list
; list
= list
->next
, i
++)
8383 mono_array_set (res
, gpointer
, i
, list
->data
);
8390 * The following section is purely to declare prototypes and
8391 * document the API, as these C files are processed by our
8397 * @array: array to alter
8398 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8399 * @index: index into the array
8400 * @value: value to set
8402 * Value Type version: This sets the @index's element of the @array
8403 * with elements of size sizeof(type) to the provided @value.
8405 * This macro does not attempt to perform type checking or bounds checking.
8407 * Use this to set value types in a `MonoArray`.
8409 void mono_array_set(MonoArray
*array
, Type element_type
, uintptr_t index
, Value value
)
8414 * mono_array_setref:
8415 * @array: array to alter
8416 * @index: index into the array
8417 * @value: value to set
8419 * Reference Type version: This sets the @index's element of the
8420 * @array with elements of size sizeof(type) to the provided @value.
8422 * This macro does not attempt to perform type checking or bounds checking.
8424 * Use this to reference types in a `MonoArray`.
8426 void mono_array_setref(MonoArray
*array
, uintptr_t index
, MonoObject
*object
)
8432 * @array: array on which to operate on
8433 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8434 * @index: index into the array
8436 * Use this macro to retrieve the @index element of an @array and
8437 * extract the value assuming that the elements of the array match
8438 * the provided type value.
8440 * This method can be used with both arrays holding value types and
8441 * reference types. For reference types, the @type parameter should
8442 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8444 * This macro does not attempt to perform type checking or bounds checking.
8446 * Returns: The element at the @index position in the @array.
8448 Type
mono_array_get (MonoArray
*array
, Type element_type
, uintptr_t index
)