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-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
73 static MonoObject
* mono_object_new_ptrfree (MonoVTable
*vtable
);
74 static MonoObject
* mono_object_new_ptrfree_box (MonoVTable
*vtable
);
77 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
);
80 mono_ldstr_metadata_sig (MonoDomain
*domain
, const char* sig
);
82 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
83 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
84 static CRITICAL_SECTION ldstr_section
;
86 static gboolean profile_allocs
= TRUE
;
89 mono_runtime_object_init (MonoObject
*this)
91 MonoMethod
*method
= NULL
;
92 MonoClass
*klass
= this->vtable
->klass
;
94 method
= mono_class_get_method_from_name (klass
, ".ctor", 0);
97 if (method
->klass
->valuetype
)
98 this = mono_object_unbox (this);
99 mono_runtime_invoke (method
, this, NULL
, NULL
);
102 /* The pseudo algorithm for type initialization from the spec
103 Note it doesn't say anything about domains - only threads.
105 2. If the type is initialized you are done.
106 2.1. If the type is not yet initialized, try to take an
108 2.2. If successful, record this thread as responsible for
109 initializing the type and proceed to step 2.3.
110 2.2.1. If not, see whether this thread or any thread
111 waiting for this thread to complete already holds the lock.
112 2.2.2. If so, return since blocking would create a deadlock. This thread
113 will now see an incompletely initialized state for the type,
114 but no deadlock will arise.
115 2.2.3 If not, block until the type is initialized then return.
116 2.3 Initialize the parent type and then all interfaces implemented
118 2.4 Execute the type initialization code for this type.
119 2.5 Mark the type as initialized, release the initialization lock,
120 awaken any threads waiting for this type to be initialized,
127 guint32 initializing_tid
;
128 guint32 waiting_count
;
130 CRITICAL_SECTION initialization_section
;
131 } TypeInitializationLock
;
133 /* for locking access to type_initialization_hash and blocked_thread_hash */
134 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
135 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
136 static CRITICAL_SECTION type_initialization_section
;
138 /* from vtable to lock */
139 static GHashTable
*type_initialization_hash
;
141 /* from thread id to thread id being waited on */
142 static GHashTable
*blocked_thread_hash
;
145 static MonoThread
*main_thread
;
147 /* Functions supplied by the runtime */
148 static MonoRuntimeCallbacks callbacks
;
151 * mono_thread_set_main:
152 * @thread: thread to set as the main thread
154 * This function can be used to instruct the runtime to treat @thread
155 * as the main thread, ie, the thread that would normally execute the Main()
156 * method. This basically means that at the end of @thread, the runtime will
157 * wait for the existing foreground threads to quit and other such details.
160 mono_thread_set_main (MonoThread
*thread
)
162 main_thread
= thread
;
166 mono_thread_get_main (void)
172 mono_type_initialization_init (void)
174 InitializeCriticalSection (&type_initialization_section
);
175 type_initialization_hash
= g_hash_table_new (NULL
, NULL
);
176 blocked_thread_hash
= g_hash_table_new (NULL
, NULL
);
177 InitializeCriticalSection (&ldstr_section
);
181 mono_type_initialization_cleanup (void)
184 /* This is causing race conditions with
185 * mono_release_type_locks
187 DeleteCriticalSection (&type_initialization_section
);
189 DeleteCriticalSection (&ldstr_section
);
193 * get_type_init_exception_for_vtable:
195 * Return the stored type initialization exception for VTABLE.
197 static MonoException
*
198 get_type_init_exception_for_vtable (MonoVTable
*vtable
)
200 MonoDomain
*domain
= vtable
->domain
;
201 MonoClass
*klass
= vtable
->klass
;
205 g_assert (vtable
->init_failed
);
208 * If the initializing thread was rudely aborted, the exception is not stored
212 mono_domain_lock (domain
);
213 if (domain
->type_init_exception_hash
)
214 ex
= mono_g_hash_table_lookup (domain
->type_init_exception_hash
, klass
);
215 mono_domain_unlock (domain
);
218 if (klass
->name_space
&& *klass
->name_space
)
219 full_name
= g_strdup_printf ("%s.%s", klass
->name_space
, klass
->name
);
221 full_name
= g_strdup (klass
->name
);
222 ex
= mono_get_exception_type_initialization (full_name
, NULL
);
229 * mono_runtime_class_init:
230 * @vtable: vtable that needs to be initialized
232 * This routine calls the class constructor for @vtable.
235 mono_runtime_class_init (MonoVTable
*vtable
)
237 mono_runtime_class_init_full (vtable
, TRUE
);
241 * mono_runtime_class_init_full:
242 * @vtable that neeeds to be initialized
243 * @raise_exception is TRUE, exceptions are raised intead of returned
247 mono_runtime_class_init_full (MonoVTable
*vtable
, gboolean raise_exception
)
250 MonoException
*exc_to_throw
;
251 MonoMethod
*method
= NULL
;
257 if (vtable
->initialized
)
261 klass
= vtable
->klass
;
263 if (!klass
->image
->checked_module_cctor
) {
264 mono_image_check_for_module_cctor (klass
->image
);
265 if (klass
->image
->has_module_cctor
) {
266 MonoClass
*module_klass
= mono_class_get (klass
->image
, MONO_TOKEN_TYPE_DEF
| 1);
267 MonoVTable
*module_vtable
= mono_class_vtable_full (vtable
->domain
, module_klass
, raise_exception
);
270 mono_runtime_class_init (module_vtable
);
273 method
= mono_class_get_cctor (klass
);
276 MonoDomain
*domain
= vtable
->domain
;
277 TypeInitializationLock
*lock
;
278 guint32 tid
= GetCurrentThreadId();
279 int do_initialization
= 0;
280 MonoDomain
*last_domain
= NULL
;
282 mono_type_initialization_lock ();
283 /* double check... */
284 if (vtable
->initialized
) {
285 mono_type_initialization_unlock ();
288 if (vtable
->init_failed
) {
289 mono_type_initialization_unlock ();
291 /* The type initialization already failed once, rethrow the same exception */
293 mono_raise_exception (get_type_init_exception_for_vtable (vtable
));
294 return get_type_init_exception_for_vtable (vtable
);
296 lock
= g_hash_table_lookup (type_initialization_hash
, vtable
);
298 /* This thread will get to do the initialization */
299 if (mono_domain_get () != domain
) {
300 /* Transfer into the target domain */
301 last_domain
= mono_domain_get ();
302 if (!mono_domain_set (domain
, FALSE
)) {
303 vtable
->initialized
= 1;
304 mono_type_initialization_unlock ();
306 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
307 return mono_get_exception_appdomain_unloaded ();
310 lock
= g_malloc (sizeof(TypeInitializationLock
));
311 InitializeCriticalSection (&lock
->initialization_section
);
312 lock
->initializing_tid
= tid
;
313 lock
->waiting_count
= 1;
315 /* grab the vtable lock while this thread still owns type_initialization_section */
316 EnterCriticalSection (&lock
->initialization_section
);
317 g_hash_table_insert (type_initialization_hash
, vtable
, lock
);
318 do_initialization
= 1;
321 TypeInitializationLock
*pending_lock
;
323 if (lock
->initializing_tid
== tid
|| lock
->done
) {
324 mono_type_initialization_unlock ();
327 /* see if the thread doing the initialization is already blocked on this thread */
328 blocked
= GUINT_TO_POINTER (lock
->initializing_tid
);
329 while ((pending_lock
= (TypeInitializationLock
*) g_hash_table_lookup (blocked_thread_hash
, blocked
))) {
330 if (pending_lock
->initializing_tid
== tid
) {
331 if (!pending_lock
->done
) {
332 mono_type_initialization_unlock ();
335 /* the thread doing the initialization is blocked on this thread,
336 but on a lock that has already been freed. It just hasn't got
341 blocked
= GUINT_TO_POINTER (pending_lock
->initializing_tid
);
343 ++lock
->waiting_count
;
344 /* record the fact that we are waiting on the initializing thread */
345 g_hash_table_insert (blocked_thread_hash
, GUINT_TO_POINTER (tid
), lock
);
347 mono_type_initialization_unlock ();
349 if (do_initialization
) {
350 mono_runtime_invoke (method
, NULL
, NULL
, (MonoObject
**) &exc
);
352 /* If the initialization failed, mark the class as unusable. */
353 /* Avoid infinite loops */
355 (klass
->image
== mono_defaults
.corlib
&&
356 !strcmp (klass
->name_space
, "System") &&
357 !strcmp (klass
->name
, "TypeInitializationException")))) {
358 vtable
->init_failed
= 1;
360 if (klass
->name_space
&& *klass
->name_space
)
361 full_name
= g_strdup_printf ("%s.%s", klass
->name_space
, klass
->name
);
363 full_name
= g_strdup (klass
->name
);
364 exc_to_throw
= mono_get_exception_type_initialization (full_name
, exc
);
368 * Store the exception object so it could be thrown on subsequent
371 mono_domain_lock (domain
);
372 if (!domain
->type_init_exception_hash
)
373 domain
->type_init_exception_hash
= mono_g_hash_table_new_type (mono_aligned_addr_hash
, NULL
, MONO_HASH_VALUE_GC
);
374 mono_g_hash_table_insert (domain
->type_init_exception_hash
, klass
, exc_to_throw
);
375 mono_domain_unlock (domain
);
379 mono_domain_set (last_domain
, TRUE
);
381 LeaveCriticalSection (&lock
->initialization_section
);
383 /* this just blocks until the initializing thread is done */
384 EnterCriticalSection (&lock
->initialization_section
);
385 LeaveCriticalSection (&lock
->initialization_section
);
388 mono_type_initialization_lock ();
389 if (lock
->initializing_tid
!= tid
)
390 g_hash_table_remove (blocked_thread_hash
, GUINT_TO_POINTER (tid
));
391 --lock
->waiting_count
;
392 if (lock
->waiting_count
== 0) {
393 DeleteCriticalSection (&lock
->initialization_section
);
394 g_hash_table_remove (type_initialization_hash
, vtable
);
397 if (!vtable
->init_failed
)
398 vtable
->initialized
= 1;
399 mono_type_initialization_unlock ();
401 if (vtable
->init_failed
) {
402 /* Either we were the initializing thread or we waited for the initialization */
404 mono_raise_exception (get_type_init_exception_for_vtable (vtable
));
405 return get_type_init_exception_for_vtable (vtable
);
408 vtable
->initialized
= 1;
415 gboolean
release_type_locks (gpointer key
, gpointer value
, gpointer user
)
417 MonoVTable
*vtable
= (MonoVTable
*)key
;
419 TypeInitializationLock
*lock
= (TypeInitializationLock
*) value
;
420 if (lock
->initializing_tid
== GPOINTER_TO_UINT (user
) && !lock
->done
) {
423 * Have to set this since it cannot be set by the normal code in
424 * mono_runtime_class_init (). In this case, the exception object is not stored,
425 * and get_type_init_exception_for_class () needs to be aware of this.
427 vtable
->init_failed
= 1;
428 LeaveCriticalSection (&lock
->initialization_section
);
429 --lock
->waiting_count
;
430 if (lock
->waiting_count
== 0) {
431 DeleteCriticalSection (&lock
->initialization_section
);
440 mono_release_type_locks (MonoInternalThread
*thread
)
442 mono_type_initialization_lock ();
443 g_hash_table_foreach_remove (type_initialization_hash
, release_type_locks
, (gpointer
)(gsize
)(thread
->tid
));
444 mono_type_initialization_unlock ();
448 default_trampoline (MonoMethod
*method
)
454 default_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
)
456 g_assert_not_reached ();
462 default_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
)
464 g_error ("remoting not installed");
469 default_delegate_trampoline (MonoClass
*klass
)
471 g_assert_not_reached ();
475 static MonoTrampoline arch_create_jit_trampoline
= default_trampoline
;
476 static MonoJumpTrampoline arch_create_jump_trampoline
= default_jump_trampoline
;
477 static MonoRemotingTrampoline arch_create_remoting_trampoline
= default_remoting_trampoline
;
478 static MonoDelegateTrampoline arch_create_delegate_trampoline
= default_delegate_trampoline
;
479 static MonoImtThunkBuilder imt_thunk_builder
= NULL
;
480 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
481 #if (MONO_IMT_SIZE > 32)
482 #error "MONO_IMT_SIZE cannot be larger than 32"
486 mono_install_callbacks (MonoRuntimeCallbacks
*cbs
)
488 memcpy (&callbacks
, cbs
, sizeof (*cbs
));
491 MonoRuntimeCallbacks
*
492 mono_get_runtime_callbacks (void)
498 mono_install_trampoline (MonoTrampoline func
)
500 arch_create_jit_trampoline
= func
? func
: default_trampoline
;
504 mono_install_jump_trampoline (MonoJumpTrampoline func
)
506 arch_create_jump_trampoline
= func
? func
: default_jump_trampoline
;
510 mono_install_remoting_trampoline (MonoRemotingTrampoline func
)
512 arch_create_remoting_trampoline
= func
? func
: default_remoting_trampoline
;
516 mono_install_delegate_trampoline (MonoDelegateTrampoline func
)
518 arch_create_delegate_trampoline
= func
? func
: default_delegate_trampoline
;
522 mono_install_imt_thunk_builder (MonoImtThunkBuilder func
) {
523 imt_thunk_builder
= func
;
526 static MonoCompileFunc default_mono_compile_method
= NULL
;
529 * mono_install_compile_method:
530 * @func: function to install
532 * This is a VM internal routine
535 mono_install_compile_method (MonoCompileFunc func
)
537 default_mono_compile_method
= func
;
541 * mono_compile_method:
542 * @method: The method to compile.
544 * This JIT-compiles the method, and returns the pointer to the native code
548 mono_compile_method (MonoMethod
*method
)
550 if (!default_mono_compile_method
) {
551 g_error ("compile method called on uninitialized runtime");
554 return default_mono_compile_method (method
);
558 mono_runtime_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
)
560 return arch_create_jump_trampoline (domain
, method
, add_sync_wrapper
);
564 mono_runtime_create_delegate_trampoline (MonoClass
*klass
)
566 return arch_create_delegate_trampoline (klass
);
569 static MonoFreeMethodFunc default_mono_free_method
= NULL
;
572 * mono_install_free_method:
573 * @func: pointer to the MonoFreeMethodFunc used to release a method
575 * This is an internal VM routine, it is used for the engines to
576 * register a handler to release the resources associated with a method.
578 * Methods are freed when no more references to the delegate that holds
582 mono_install_free_method (MonoFreeMethodFunc func
)
584 default_mono_free_method
= func
;
588 * mono_runtime_free_method:
589 * @domain; domain where the method is hosted
590 * @method: method to release
592 * This routine is invoked to free the resources associated with
593 * a method that has been JIT compiled. This is used to discard
594 * methods that were used only temporarily (for example, used in marshalling)
598 mono_runtime_free_method (MonoDomain
*domain
, MonoMethod
*method
)
600 if (default_mono_free_method
!= NULL
)
601 default_mono_free_method (domain
, method
);
603 mono_method_clear_object (domain
, method
);
605 mono_free_method (method
);
609 * The vtables in the root appdomain are assumed to be reachable by other
610 * roots, and we don't use typed allocation in the other domains.
613 /* The sync block is no longer a GC pointer */
614 #define GC_HEADER_BITMAP (0)
616 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
619 compute_class_bitmap (MonoClass
*class, gsize
*bitmap
, int size
, int offset
, int *max_set
, gboolean static_fields
)
621 MonoClassField
*field
;
627 max_size
= mono_class_data_size (class) / sizeof (gpointer
);
629 max_size
= class->instance_size
/ sizeof (gpointer
);
630 if (max_size
> size
) {
631 g_assert (offset
<= 0);
632 bitmap
= g_malloc0 ((max_size
+ BITMAP_EL_SIZE
- 1) / BITMAP_EL_SIZE
* sizeof (gsize
));
636 for (p
= class; p
!= NULL
; p
= p
->parent
) {
637 gpointer iter
= NULL
;
638 while ((field
= mono_class_get_fields (p
, &iter
))) {
642 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
644 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
647 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
650 /* FIXME: should not happen, flag as type load error */
651 if (field
->type
->byref
)
654 if (static_fields
&& field
->offset
== -1)
658 pos
= field
->offset
/ sizeof (gpointer
);
661 type
= mono_type_get_underlying_type (field
->type
);
662 switch (type
->type
) {
665 case MONO_TYPE_FNPTR
:
667 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
672 if (class->image
!= mono_defaults
.corlib
)
675 case MONO_TYPE_STRING
:
676 case MONO_TYPE_SZARRAY
:
677 case MONO_TYPE_CLASS
:
678 case MONO_TYPE_OBJECT
:
679 case MONO_TYPE_ARRAY
:
680 g_assert ((field
->offset
% sizeof(gpointer
)) == 0);
682 g_assert (pos
< size
|| pos
<= max_size
);
683 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
684 *max_set
= MAX (*max_set
, pos
);
686 case MONO_TYPE_GENERICINST
:
687 if (!mono_type_generic_inst_is_valuetype (type
)) {
688 g_assert ((field
->offset
% sizeof(gpointer
)) == 0);
690 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
691 *max_set
= MAX (*max_set
, pos
);
696 case MONO_TYPE_VALUETYPE
: {
697 MonoClass
*fclass
= mono_class_from_mono_type (field
->type
);
698 if (fclass
->has_references
) {
699 /* remove the object header */
700 compute_class_bitmap (fclass
, bitmap
, size
, pos
- (sizeof (MonoObject
) / sizeof (gpointer
)), max_set
, FALSE
);
714 case MONO_TYPE_BOOLEAN
:
718 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type
->type
, mono_type_get_full_name (field
->parent
), field
->name
);
730 * similar to the above, but sets the bits in the bitmap for any non-ref field
731 * and ignores static fields
734 compute_class_non_ref_bitmap (MonoClass
*class, gsize
*bitmap
, int size
, int offset
)
736 MonoClassField
*field
;
741 max_size
= class->instance_size
/ sizeof (gpointer
);
742 if (max_size
>= size
) {
743 bitmap
= g_malloc0 (sizeof (gsize
) * ((max_size
) + 1));
746 for (p
= class; p
!= NULL
; p
= p
->parent
) {
747 gpointer iter
= NULL
;
748 while ((field
= mono_class_get_fields (p
, &iter
))) {
751 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
753 /* FIXME: should not happen, flag as type load error */
754 if (field
->type
->byref
)
757 pos
= field
->offset
/ sizeof (gpointer
);
760 type
= mono_type_get_underlying_type (field
->type
);
761 switch (type
->type
) {
762 #if SIZEOF_VOID_P == 8
766 case MONO_TYPE_FNPTR
:
771 if ((((field
->offset
+ 7) / sizeof (gpointer
)) + offset
) != pos
) {
772 pos2
= ((field
->offset
+ 7) / sizeof (gpointer
)) + offset
;
773 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
776 #if SIZEOF_VOID_P == 4
780 case MONO_TYPE_FNPTR
:
785 if ((((field
->offset
+ 3) / sizeof (gpointer
)) + offset
) != pos
) {
786 pos2
= ((field
->offset
+ 3) / sizeof (gpointer
)) + offset
;
787 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
793 if ((((field
->offset
+ 1) / sizeof (gpointer
)) + offset
) != pos
) {
794 pos2
= ((field
->offset
+ 1) / sizeof (gpointer
)) + offset
;
795 bitmap
[pos2
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos2
% BITMAP_EL_SIZE
);
798 case MONO_TYPE_BOOLEAN
:
801 bitmap
[pos
/ BITMAP_EL_SIZE
] |= ((gsize
)1) << (pos
% BITMAP_EL_SIZE
);
803 case MONO_TYPE_STRING
:
804 case MONO_TYPE_SZARRAY
:
805 case MONO_TYPE_CLASS
:
806 case MONO_TYPE_OBJECT
:
807 case MONO_TYPE_ARRAY
:
809 case MONO_TYPE_GENERICINST
:
810 if (!mono_type_generic_inst_is_valuetype (type
)) {
815 case MONO_TYPE_VALUETYPE
: {
816 MonoClass
*fclass
= mono_class_from_mono_type (field
->type
);
817 /* remove the object header */
818 compute_class_non_ref_bitmap (fclass
, bitmap
, size
, pos
- (sizeof (MonoObject
) / sizeof (gpointer
)));
822 g_assert_not_reached ();
831 * mono_class_insecure_overlapping:
832 * check if a class with explicit layout has references and non-references
833 * fields overlapping.
835 * Returns: TRUE if it is insecure to load the type.
838 mono_class_insecure_overlapping (MonoClass
*klass
)
842 gsize default_bitmap
[4] = {0};
844 gsize default_nrbitmap
[4] = {0};
845 int i
, insecure
= FALSE
;
848 bitmap
= compute_class_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
849 nrbitmap
= compute_class_non_ref_bitmap (klass
, default_nrbitmap
, sizeof (default_nrbitmap
) * 8, 0);
851 for (i
= 0; i
<= max_set
; i
+= sizeof (bitmap
[0]) * 8) {
852 int idx
= i
% (sizeof (bitmap
[0]) * 8);
853 if (bitmap
[idx
] & nrbitmap
[idx
]) {
858 if (bitmap
!= default_bitmap
)
860 if (nrbitmap
!= default_nrbitmap
)
863 g_print ("class %s.%s in assembly %s has overlapping references\n", klass
->name_space
, klass
->name
, klass
->image
->name
);
871 mono_string_alloc (int length
)
873 return mono_string_new_size (mono_domain_get (), length
);
877 mono_class_compute_gc_descriptor (MonoClass
*class)
881 gsize default_bitmap
[4] = {0};
882 static gboolean gcj_inited
= FALSE
;
887 mono_register_jit_icall (mono_object_new_ptrfree
, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE
);
888 mono_register_jit_icall (mono_object_new_ptrfree_box
, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE
);
889 mono_register_jit_icall (mono_object_new_fast
, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE
);
890 mono_register_jit_icall (mono_string_alloc
, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE
);
892 #ifdef HAVE_GC_GCJ_MALLOC
894 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
898 #ifdef GC_REDIRECT_TO_LOCAL
899 mono_register_jit_icall (GC_local_gcj_malloc
, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE
);
900 mono_register_jit_icall (GC_local_gcj_fast_malloc
, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE
);
902 mono_register_jit_icall (GC_gcj_malloc
, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE
);
903 mono_register_jit_icall (GC_gcj_fast_malloc
, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE
);
908 mono_loader_unlock ();
912 mono_class_init (class);
914 if (class->gc_descr_inited
)
917 class->gc_descr_inited
= TRUE
;
918 class->gc_descr
= GC_NO_DESCRIPTOR
;
920 bitmap
= default_bitmap
;
921 if (class == mono_defaults
.string_class
) {
922 class->gc_descr
= (gpointer
)mono_gc_make_descr_for_string (bitmap
, 2);
923 } else if (class->rank
) {
924 mono_class_compute_gc_descriptor (class->element_class
);
925 if (!class->element_class
->valuetype
) {
927 class->gc_descr
= mono_gc_make_descr_for_array (TRUE
, &abm
, 1, sizeof (gpointer
));
928 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
929 class->name_space, class->name);*/
931 /* remove the object header */
932 bitmap
= compute_class_bitmap (class->element_class
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(sizeof (MonoObject
) / sizeof (gpointer
)), &max_set
, FALSE
);
933 class->gc_descr
= mono_gc_make_descr_for_array (TRUE
, bitmap
, mono_array_element_size (class) / sizeof (gpointer
), mono_array_element_size (class));
934 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
935 class->name_space, class->name);*/
936 if (bitmap
!= default_bitmap
)
940 /*static int count = 0;
943 bitmap
= compute_class_bitmap (class, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, FALSE
);
944 class->gc_descr
= (gpointer
)mono_gc_make_descr_for_object (bitmap
, max_set
+ 1, class->instance_size
);
946 if (class->gc_descr == GC_NO_DESCRIPTOR)
947 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
949 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
950 if (bitmap
!= default_bitmap
)
956 * field_is_special_static:
957 * @fklass: The MonoClass to look up.
958 * @field: The MonoClassField describing the field.
960 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
961 * SPECIAL_STATIC_NONE otherwise.
964 field_is_special_static (MonoClass
*fklass
, MonoClassField
*field
)
966 MonoCustomAttrInfo
*ainfo
;
968 ainfo
= mono_custom_attrs_from_field (fklass
, field
);
971 for (i
= 0; i
< ainfo
->num_attrs
; ++i
) {
972 MonoClass
*klass
= ainfo
->attrs
[i
].ctor
->klass
;
973 if (klass
->image
== mono_defaults
.corlib
) {
974 if (strcmp (klass
->name
, "ThreadStaticAttribute") == 0) {
975 mono_custom_attrs_free (ainfo
);
976 return SPECIAL_STATIC_THREAD
;
978 else if (strcmp (klass
->name
, "ContextStaticAttribute") == 0) {
979 mono_custom_attrs_free (ainfo
);
980 return SPECIAL_STATIC_CONTEXT
;
984 mono_custom_attrs_free (ainfo
);
985 return SPECIAL_STATIC_NONE
;
988 static gpointer imt_trampoline
= NULL
;
991 mono_install_imt_trampoline (gpointer tramp_code
)
993 imt_trampoline
= tramp_code
;
996 static gpointer vtable_trampoline
= NULL
;
999 mono_install_vtable_trampoline (gpointer tramp_code
)
1001 vtable_trampoline
= tramp_code
;
1004 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1005 #define mix(a,b,c) { \
1006 a -= c; a ^= rot(c, 4); c += b; \
1007 b -= a; b ^= rot(a, 6); a += c; \
1008 c -= b; c ^= rot(b, 8); b += a; \
1009 a -= c; a ^= rot(c,16); c += b; \
1010 b -= a; b ^= rot(a,19); a += c; \
1011 c -= b; c ^= rot(b, 4); b += a; \
1013 #define final(a,b,c) { \
1014 c ^= b; c -= rot(b,14); \
1015 a ^= c; a -= rot(c,11); \
1016 b ^= a; b -= rot(a,25); \
1017 c ^= b; c -= rot(b,16); \
1018 a ^= c; a -= rot(c,4); \
1019 b ^= a; b -= rot(a,14); \
1020 c ^= b; c -= rot(b,24); \
1024 * mono_method_get_imt_slot:
1026 * The IMT slot is embedded into AOTed code, so this must return the same value
1027 * for the same method across all executions. This means:
1028 * - pointers shouldn't be used as hash values.
1029 * - mono_metadata_str_hash () should be used for hashing strings.
1032 mono_method_get_imt_slot (MonoMethod
*method
)
1034 MonoMethodSignature
*sig
;
1036 guint32
*hashes_start
, *hashes
;
1040 /* This can be used to stress tests the collision code */
1044 * We do this to simplify generic sharing. It will hurt
1045 * performance in cases where a class implements two different
1046 * instantiations of the same generic interface.
1047 * The code in build_imt_slots () depends on this.
1049 if (method
->is_inflated
)
1050 method
= ((MonoMethodInflated
*)method
)->declaring
;
1052 sig
= mono_method_signature (method
);
1053 hashes_count
= sig
->param_count
+ 4;
1054 hashes_start
= malloc (hashes_count
* sizeof (guint32
));
1055 hashes
= hashes_start
;
1057 if (! MONO_CLASS_IS_INTERFACE (method
->klass
)) {
1058 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1059 method
->klass
->name_space
, method
->klass
->name
, method
->name
);
1060 g_assert_not_reached ();
1063 /* Initialize hashes */
1064 hashes
[0] = mono_metadata_str_hash (method
->klass
->name
);
1065 hashes
[1] = mono_metadata_str_hash (method
->klass
->name_space
);
1066 hashes
[2] = mono_metadata_str_hash (method
->name
);
1067 hashes
[3] = mono_metadata_type_hash (sig
->ret
);
1068 for (i
= 0; i
< sig
->param_count
; i
++) {
1069 hashes
[4 + i
] = mono_metadata_type_hash (sig
->params
[i
]);
1072 /* Setup internal state */
1073 a
= b
= c
= 0xdeadbeef + (((guint32
)hashes_count
)<<2);
1075 /* Handle most of the hashes */
1076 while (hashes_count
> 3) {
1085 /* Handle the last 3 hashes (all the case statements fall through) */
1086 switch (hashes_count
) {
1087 case 3 : c
+= hashes
[2];
1088 case 2 : b
+= hashes
[1];
1089 case 1 : a
+= hashes
[0];
1091 case 0: /* nothing left to add */
1095 free (hashes_start
);
1096 /* Report the result */
1097 return c
% MONO_IMT_SIZE
;
1106 add_imt_builder_entry (MonoImtBuilderEntry
**imt_builder
, MonoMethod
*method
, guint32
*imt_collisions_bitmap
, int vtable_slot
, int slot_num
) {
1107 guint32 imt_slot
= mono_method_get_imt_slot (method
);
1108 MonoImtBuilderEntry
*entry
;
1110 if (slot_num
>= 0 && imt_slot
!= slot_num
) {
1111 /* we build just a single imt slot and this is not it */
1115 entry
= g_malloc0 (sizeof (MonoImtBuilderEntry
));
1116 entry
->key
= method
;
1117 entry
->value
.vtable_slot
= vtable_slot
;
1118 entry
->next
= imt_builder
[imt_slot
];
1119 if (imt_builder
[imt_slot
] != NULL
) {
1120 entry
->children
= imt_builder
[imt_slot
]->children
+ 1;
1121 if (entry
->children
== 1) {
1122 mono_stats
.imt_slots_with_collisions
++;
1123 *imt_collisions_bitmap
|= (1 << imt_slot
);
1126 entry
->children
= 0;
1127 mono_stats
.imt_used_slots
++;
1129 imt_builder
[imt_slot
] = entry
;
1132 char *method_name
= mono_method_full_name (method
, TRUE
);
1133 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1134 method
, method_name
, imt_slot
, vtable_slot
, entry
->children
);
1135 g_free (method_name
);
1142 print_imt_entry (const char* message
, MonoImtBuilderEntry
*e
, int num
) {
1144 MonoMethod
*method
= e
->key
;
1145 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1149 method
->klass
->name_space
,
1150 method
->klass
->name
,
1153 printf (" * %s: NULL\n", message
);
1159 compare_imt_builder_entries (const void *p1
, const void *p2
) {
1160 MonoImtBuilderEntry
*e1
= *(MonoImtBuilderEntry
**) p1
;
1161 MonoImtBuilderEntry
*e2
= *(MonoImtBuilderEntry
**) p2
;
1163 return (e1
->key
< e2
->key
) ? -1 : ((e1
->key
> e2
->key
) ? 1 : 0);
1167 imt_emit_ir (MonoImtBuilderEntry
**sorted_array
, int start
, int end
, GPtrArray
*out_array
)
1169 int count
= end
- start
;
1170 int chunk_start
= out_array
->len
;
1173 for (i
= start
; i
< end
; ++i
) {
1174 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1175 item
->key
= sorted_array
[i
]->key
;
1176 item
->value
= sorted_array
[i
]->value
;
1177 item
->has_target_code
= sorted_array
[i
]->has_target_code
;
1178 item
->is_equals
= TRUE
;
1180 item
->check_target_idx
= out_array
->len
+ 1;
1182 item
->check_target_idx
= 0;
1183 g_ptr_array_add (out_array
, item
);
1186 int middle
= start
+ count
/ 2;
1187 MonoIMTCheckItem
*item
= g_new0 (MonoIMTCheckItem
, 1);
1189 item
->key
= sorted_array
[middle
]->key
;
1190 item
->is_equals
= FALSE
;
1191 g_ptr_array_add (out_array
, item
);
1192 imt_emit_ir (sorted_array
, start
, middle
, out_array
);
1193 item
->check_target_idx
= imt_emit_ir (sorted_array
, middle
, end
, out_array
);
1199 imt_sort_slot_entries (MonoImtBuilderEntry
*entries
) {
1200 int number_of_entries
= entries
->children
+ 1;
1201 MonoImtBuilderEntry
**sorted_array
= malloc (sizeof (MonoImtBuilderEntry
*) * number_of_entries
);
1202 GPtrArray
*result
= g_ptr_array_new ();
1203 MonoImtBuilderEntry
*current_entry
;
1206 for (current_entry
= entries
, i
= 0; current_entry
!= NULL
; current_entry
= current_entry
->next
, i
++) {
1207 sorted_array
[i
] = current_entry
;
1209 qsort (sorted_array
, number_of_entries
, sizeof (MonoImtBuilderEntry
*), compare_imt_builder_entries
);
1211 /*for (i = 0; i < number_of_entries; i++) {
1212 print_imt_entry (" sorted array:", sorted_array [i], i);
1215 imt_emit_ir (sorted_array
, 0, number_of_entries
, result
);
1217 free (sorted_array
);
1222 initialize_imt_slot (MonoVTable
*vtable
, MonoDomain
*domain
, MonoImtBuilderEntry
*imt_builder_entry
, gpointer fail_tramp
)
1224 if (imt_builder_entry
!= NULL
) {
1225 if (imt_builder_entry
->children
== 0 && !fail_tramp
) {
1226 /* No collision, return the vtable slot contents */
1227 return vtable
->vtable
[imt_builder_entry
->value
.vtable_slot
];
1229 /* Collision, build the thunk */
1230 GPtrArray
*imt_ir
= imt_sort_slot_entries (imt_builder_entry
);
1233 result
= imt_thunk_builder (vtable
, domain
,
1234 (MonoIMTCheckItem
**)imt_ir
->pdata
, imt_ir
->len
, fail_tramp
);
1235 for (i
= 0; i
< imt_ir
->len
; ++i
)
1236 g_free (g_ptr_array_index (imt_ir
, i
));
1237 g_ptr_array_free (imt_ir
, TRUE
);
1249 static MonoImtBuilderEntry
*
1250 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
);
1253 * LOCKING: requires the loader and domain locks.
1257 build_imt_slots (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
, int slot_num
)
1261 guint32 imt_collisions_bitmap
= 0;
1262 MonoImtBuilderEntry
**imt_builder
= calloc (MONO_IMT_SIZE
, sizeof (MonoImtBuilderEntry
*));
1263 int method_count
= 0;
1264 gboolean record_method_count_for_max_collisions
= FALSE
;
1265 gboolean has_generic_virtual
= FALSE
, has_variant_iface
= FALSE
;
1268 printf ("Building IMT for class %s.%s slot %d\n", klass
->name_space
, klass
->name
, slot_num
);
1270 for (i
= 0; i
< klass
->interface_offsets_count
; ++i
) {
1271 MonoClass
*iface
= klass
->interfaces_packed
[i
];
1272 int interface_offset
= klass
->interface_offsets_packed
[i
];
1273 int method_slot_in_interface
, vt_slot
;
1275 if (mono_class_has_variant_generic_params (iface
))
1276 has_variant_iface
= TRUE
;
1278 vt_slot
= interface_offset
;
1279 for (method_slot_in_interface
= 0; method_slot_in_interface
< iface
->method
.count
; method_slot_in_interface
++) {
1282 if (slot_num
>= 0 && iface
->is_inflated
) {
1284 * The imt slot of the method is the same as for its declaring method,
1285 * see the comment in mono_method_get_imt_slot (), so we can
1286 * avoid inflating methods which will be discarded by
1287 * add_imt_builder_entry anyway.
1289 method
= mono_class_get_method_by_index (iface
->generic_class
->container_class
, method_slot_in_interface
);
1290 if (mono_method_get_imt_slot (method
) != slot_num
) {
1295 method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1296 if (method
->is_generic
) {
1297 has_generic_virtual
= TRUE
;
1302 if (!(method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
1303 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, vt_slot
, slot_num
);
1308 if (extra_interfaces
) {
1309 int interface_offset
= klass
->vtable_size
;
1311 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
1312 MonoClass
* iface
= list_item
->data
;
1313 int method_slot_in_interface
;
1314 for (method_slot_in_interface
= 0; method_slot_in_interface
< iface
->method
.count
; method_slot_in_interface
++) {
1315 MonoMethod
*method
= mono_class_get_method_by_index (iface
, method_slot_in_interface
);
1316 add_imt_builder_entry (imt_builder
, method
, &imt_collisions_bitmap
, interface_offset
+ method_slot_in_interface
, slot_num
);
1318 interface_offset
+= iface
->method
.count
;
1321 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
) {
1322 /* overwrite the imt slot only if we're building all the entries or if
1323 * we're building this specific one
1325 if (slot_num
< 0 || i
== slot_num
) {
1326 MonoImtBuilderEntry
*entries
= get_generic_virtual_entries (domain
, &imt
[i
]);
1329 if (imt_builder
[i
]) {
1330 MonoImtBuilderEntry
*entry
;
1332 /* Link entries with imt_builder [i] */
1333 for (entry
= entries
; entry
->next
; entry
= entry
->next
) {
1335 MonoMethod
*method
= (MonoMethod
*)entry
->key
;
1336 char *method_name
= mono_method_full_name (method
, TRUE
);
1337 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method
, method_name
, i
);
1338 g_free (method_name
);
1341 entry
->next
= imt_builder
[i
];
1342 entries
->children
+= imt_builder
[i
]->children
+ 1;
1344 imt_builder
[i
] = entries
;
1347 if (has_generic_virtual
|| has_variant_iface
) {
1349 * There might be collisions later when the the thunk is expanded.
1351 imt_collisions_bitmap
|= (1 << i
);
1354 * The IMT thunk might be called with an instance of one of the
1355 * generic virtual methods, so has to fallback to the IMT trampoline.
1357 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], imt_trampoline
);
1359 imt
[i
] = initialize_imt_slot (vt
, domain
, imt_builder
[i
], NULL
);
1362 printf ("initialize_imt_slot[%d]: %p methods %d\n", i
, imt
[i
], imt_builder
[i
]->children
+ 1);
1366 if (imt_builder
[i
] != NULL
) {
1367 int methods_in_slot
= imt_builder
[i
]->children
+ 1;
1368 if (methods_in_slot
> mono_stats
.imt_max_collisions_in_slot
) {
1369 mono_stats
.imt_max_collisions_in_slot
= methods_in_slot
;
1370 record_method_count_for_max_collisions
= TRUE
;
1372 method_count
+= methods_in_slot
;
1376 mono_stats
.imt_number_of_methods
+= method_count
;
1377 if (record_method_count_for_max_collisions
) {
1378 mono_stats
.imt_method_count_when_max_collisions
= method_count
;
1381 for (i
= 0; i
< MONO_IMT_SIZE
; i
++) {
1382 MonoImtBuilderEntry
* entry
= imt_builder
[i
];
1383 while (entry
!= NULL
) {
1384 MonoImtBuilderEntry
* next
= entry
->next
;
1390 /* we OR the bitmap since we may build just a single imt slot at a time */
1391 vt
->imt_collisions_bitmap
|= imt_collisions_bitmap
;
1395 build_imt (MonoClass
*klass
, MonoVTable
*vt
, MonoDomain
*domain
, gpointer
* imt
, GSList
*extra_interfaces
) {
1396 build_imt_slots (klass
, vt
, domain
, imt
, extra_interfaces
, -1);
1400 * mono_vtable_build_imt_slot:
1401 * @vtable: virtual object table struct
1402 * @imt_slot: slot in the IMT table
1404 * Fill the given @imt_slot in the IMT table of @vtable with
1405 * a trampoline or a thunk for the case of collisions.
1406 * This is part of the internal mono API.
1408 * LOCKING: Take the domain lock.
1411 mono_vtable_build_imt_slot (MonoVTable
* vtable
, int imt_slot
)
1413 gpointer
*imt
= (gpointer
*)vtable
;
1414 imt
-= MONO_IMT_SIZE
;
1415 g_assert (imt_slot
>= 0 && imt_slot
< MONO_IMT_SIZE
);
1417 /* no support for extra interfaces: the proxy objects will need
1418 * to build the complete IMT
1419 * Update and heck needs to ahppen inside the proper domain lock, as all
1420 * the changes made to a MonoVTable.
1422 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1423 mono_domain_lock (vtable
->domain
);
1424 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1425 if (imt
[imt_slot
] == imt_trampoline
)
1426 build_imt_slots (vtable
->klass
, vtable
, vtable
->domain
, imt
, NULL
, imt_slot
);
1427 mono_domain_unlock (vtable
->domain
);
1428 mono_loader_unlock ();
1433 * The first two free list entries both belong to the wait list: The
1434 * first entry is the pointer to the head of the list and the second
1435 * entry points to the last element. That way appending and removing
1436 * the first element are both O(1) operations.
1438 #define NUM_FREE_LISTS 12
1439 #define FIRST_FREE_LIST_SIZE 64
1440 #define MAX_WAIT_LENGTH 50
1441 #define THUNK_THRESHOLD 10
1444 * LOCKING: The domain lock must be held.
1447 init_thunk_free_lists (MonoDomain
*domain
)
1449 if (domain
->thunk_free_lists
)
1451 domain
->thunk_free_lists
= mono_domain_alloc0 (domain
, sizeof (gpointer
) * NUM_FREE_LISTS
);
1455 list_index_for_size (int item_size
)
1458 int size
= FIRST_FREE_LIST_SIZE
;
1460 while (item_size
> size
&& i
< NUM_FREE_LISTS
- 1) {
1469 * mono_method_alloc_generic_virtual_thunk:
1471 * @size: size in bytes
1473 * Allocs size bytes to be used for the code of a generic virtual
1474 * thunk. It's either allocated from the domain's code manager or
1475 * reused from a previously invalidated piece.
1477 * LOCKING: The domain lock must be held.
1480 mono_method_alloc_generic_virtual_thunk (MonoDomain
*domain
, int size
)
1482 static gboolean inited
= FALSE
;
1483 static int generic_virtual_thunks_size
= 0;
1487 MonoThunkFreeList
**l
;
1489 init_thunk_free_lists (domain
);
1491 size
+= sizeof (guint32
);
1492 if (size
< sizeof (MonoThunkFreeList
))
1493 size
= sizeof (MonoThunkFreeList
);
1495 i
= list_index_for_size (size
);
1496 for (l
= &domain
->thunk_free_lists
[i
]; *l
; l
= &(*l
)->next
) {
1497 if ((*l
)->size
>= size
) {
1498 MonoThunkFreeList
*item
= *l
;
1500 return ((guint32
*)item
) + 1;
1504 /* no suitable item found - search lists of larger sizes */
1505 while (++i
< NUM_FREE_LISTS
) {
1506 MonoThunkFreeList
*item
= domain
->thunk_free_lists
[i
];
1509 g_assert (item
->size
> size
);
1510 domain
->thunk_free_lists
[i
] = item
->next
;
1511 return ((guint32
*)item
) + 1;
1514 /* still nothing found - allocate it */
1516 mono_counters_register ("Generic virtual thunk bytes",
1517 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &generic_virtual_thunks_size
);
1520 generic_virtual_thunks_size
+= size
;
1522 p
= mono_domain_code_reserve (domain
, size
);
1529 * LOCKING: The domain lock must be held.
1532 invalidate_generic_virtual_thunk (MonoDomain
*domain
, gpointer code
)
1535 MonoThunkFreeList
*l
= (MonoThunkFreeList
*)(p
- 1);
1537 init_thunk_free_lists (domain
);
1539 while (domain
->thunk_free_lists
[0] && domain
->thunk_free_lists
[0]->length
>= MAX_WAIT_LENGTH
) {
1540 MonoThunkFreeList
*item
= domain
->thunk_free_lists
[0];
1541 int length
= item
->length
;
1544 /* unlink the first item from the wait list */
1545 domain
->thunk_free_lists
[0] = item
->next
;
1546 domain
->thunk_free_lists
[0]->length
= length
- 1;
1548 i
= list_index_for_size (item
->size
);
1550 /* put it in the free list */
1551 item
->next
= domain
->thunk_free_lists
[i
];
1552 domain
->thunk_free_lists
[i
] = item
;
1556 if (domain
->thunk_free_lists
[1]) {
1557 domain
->thunk_free_lists
[1] = domain
->thunk_free_lists
[1]->next
= l
;
1558 domain
->thunk_free_lists
[0]->length
++;
1560 g_assert (!domain
->thunk_free_lists
[0]);
1562 domain
->thunk_free_lists
[0] = domain
->thunk_free_lists
[1] = l
;
1563 domain
->thunk_free_lists
[0]->length
= 1;
1567 typedef struct _GenericVirtualCase
{
1571 struct _GenericVirtualCase
*next
;
1572 } GenericVirtualCase
;
1575 * get_generic_virtual_entries:
1577 * Return IMT entries for the generic virtual method instances and
1578 * variant interface methods for vtable slot
1581 static MonoImtBuilderEntry
*
1582 get_generic_virtual_entries (MonoDomain
*domain
, gpointer
*vtable_slot
)
1584 GenericVirtualCase
*list
;
1585 MonoImtBuilderEntry
*entries
;
1587 mono_domain_lock (domain
);
1588 if (!domain
->generic_virtual_cases
)
1589 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1591 list
= g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1594 for (; list
; list
= list
->next
) {
1595 MonoImtBuilderEntry
*entry
;
1597 if (list
->count
< THUNK_THRESHOLD
)
1600 entry
= g_new0 (MonoImtBuilderEntry
, 1);
1601 entry
->key
= list
->method
;
1602 entry
->value
.target_code
= mono_get_addr_from_ftnptr (list
->code
);
1603 entry
->has_target_code
= 1;
1605 entry
->children
= entries
->children
+ 1;
1606 entry
->next
= entries
;
1610 mono_domain_unlock (domain
);
1612 /* FIXME: Leaking memory ? */
1617 * mono_method_add_generic_virtual_invocation:
1619 * @vtable_slot: pointer to the vtable slot
1620 * @method: the inflated generic virtual method
1621 * @code: the method's code
1623 * Registers a call via unmanaged code to a generic virtual method
1624 * instantiation or variant interface method. If the number of calls reaches a threshold
1625 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1626 * virtual method thunk.
1629 mono_method_add_generic_virtual_invocation (MonoDomain
*domain
, MonoVTable
*vtable
,
1630 gpointer
*vtable_slot
,
1631 MonoMethod
*method
, gpointer code
)
1633 static gboolean inited
= FALSE
;
1634 static int num_added
= 0;
1636 GenericVirtualCase
*gvc
, *list
;
1637 MonoImtBuilderEntry
*entries
;
1641 mono_domain_lock (domain
);
1642 if (!domain
->generic_virtual_cases
)
1643 domain
->generic_virtual_cases
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1645 /* Check whether the case was already added */
1646 list
= g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1649 if (gvc
->method
== method
)
1654 /* If not found, make a new one */
1656 gvc
= mono_domain_alloc (domain
, sizeof (GenericVirtualCase
));
1657 gvc
->method
= method
;
1660 gvc
->next
= g_hash_table_lookup (domain
->generic_virtual_cases
, vtable_slot
);
1662 g_hash_table_insert (domain
->generic_virtual_cases
, vtable_slot
, gvc
);
1665 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_added
);
1671 if (++gvc
->count
== THUNK_THRESHOLD
) {
1672 gpointer
*old_thunk
= *vtable_slot
;
1674 if ((gpointer
)vtable_slot
< (gpointer
)vtable
)
1675 /* Force the rebuild of the thunk at the next call */
1676 *vtable_slot
= imt_trampoline
;
1678 entries
= get_generic_virtual_entries (domain
, vtable_slot
);
1680 sorted
= imt_sort_slot_entries (entries
);
1682 *vtable_slot
= imt_thunk_builder (NULL
, domain
, (MonoIMTCheckItem
**)sorted
->pdata
, sorted
->len
,
1686 MonoImtBuilderEntry
*next
= entries
->next
;
1691 for (i
= 0; i
< sorted
->len
; ++i
)
1692 g_free (g_ptr_array_index (sorted
, i
));
1693 g_ptr_array_free (sorted
, TRUE
);
1696 if (old_thunk
!= vtable_trampoline
&& old_thunk
!= imt_trampoline
)
1697 invalidate_generic_virtual_thunk (domain
, old_thunk
);
1700 mono_domain_unlock (domain
);
1703 static MonoVTable
*mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*class, gboolean raise_on_error
);
1706 * mono_class_vtable:
1707 * @domain: the application domain
1708 * @class: the class to initialize
1710 * VTables are domain specific because we create domain specific code, and
1711 * they contain the domain specific static class data.
1712 * On failure, NULL is returned, and class->exception_type is set.
1715 mono_class_vtable (MonoDomain
*domain
, MonoClass
*class)
1717 return mono_class_vtable_full (domain
, class, FALSE
);
1721 * mono_class_vtable_full:
1722 * @domain: the application domain
1723 * @class: the class to initialize
1724 * @raise_on_error if an exception should be raised on failure or not
1726 * VTables are domain specific because we create domain specific code, and
1727 * they contain the domain specific static class data.
1730 mono_class_vtable_full (MonoDomain
*domain
, MonoClass
*class, gboolean raise_on_error
)
1732 MonoClassRuntimeInfo
*runtime_info
;
1736 if (class->exception_type
) {
1738 mono_raise_exception (mono_class_get_exception_for_failure (class));
1742 /* this check can be inlined in jitted code, too */
1743 runtime_info
= class->runtime_info
;
1744 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1745 return runtime_info
->domain_vtables
[domain
->domain_id
];
1746 return mono_class_create_runtime_vtable (domain
, class, raise_on_error
);
1750 * mono_class_try_get_vtable:
1751 * @domain: the application domain
1752 * @class: the class to initialize
1754 * This function tries to get the associated vtable from @class if
1755 * it was already created.
1758 mono_class_try_get_vtable (MonoDomain
*domain
, MonoClass
*class)
1760 MonoClassRuntimeInfo
*runtime_info
;
1764 runtime_info
= class->runtime_info
;
1765 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
])
1766 return runtime_info
->domain_vtables
[domain
->domain_id
];
1771 mono_class_create_runtime_vtable (MonoDomain
*domain
, MonoClass
*class, gboolean raise_on_error
)
1774 MonoClassRuntimeInfo
*runtime_info
, *old_info
;
1775 MonoClassField
*field
;
1778 int imt_table_bytes
= 0;
1779 guint32 vtable_size
, class_size
;
1782 gpointer
*interface_offsets
;
1784 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1785 mono_domain_lock (domain
);
1786 runtime_info
= class->runtime_info
;
1787 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
&& runtime_info
->domain_vtables
[domain
->domain_id
]) {
1788 mono_domain_unlock (domain
);
1789 mono_loader_unlock ();
1790 return runtime_info
->domain_vtables
[domain
->domain_id
];
1792 if (!class->inited
|| class->exception_type
) {
1793 if (!mono_class_init (class) || class->exception_type
) {
1794 mono_domain_unlock (domain
);
1795 mono_loader_unlock ();
1797 mono_raise_exception (mono_class_get_exception_for_failure (class));
1802 /* Array types require that their element type be valid*/
1803 if (class->byval_arg
.type
== MONO_TYPE_ARRAY
|| class->byval_arg
.type
== MONO_TYPE_SZARRAY
) {
1804 MonoClass
*element_class
= class->element_class
;
1805 if (!element_class
->inited
)
1806 mono_class_init (element_class
);
1808 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1809 if (element_class
->exception_type
== MONO_EXCEPTION_NONE
&& !element_class
->vtable_size
)
1810 mono_class_setup_vtable (element_class
);
1812 if (element_class
->exception_type
!= MONO_EXCEPTION_NONE
) {
1813 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1814 if (class->exception_type
== MONO_EXCEPTION_NONE
)
1815 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD
, NULL
);
1816 mono_domain_unlock (domain
);
1817 mono_loader_unlock ();
1819 mono_raise_exception (mono_class_get_exception_for_failure (class));
1825 * For some classes, mono_class_init () already computed class->vtable_size, and
1826 * that is all that is needed because of the vtable trampolines.
1828 if (!class->vtable_size
)
1829 mono_class_setup_vtable (class);
1831 if (class->exception_type
) {
1832 mono_domain_unlock (domain
);
1833 mono_loader_unlock ();
1835 mono_raise_exception (mono_class_get_exception_for_failure (class));
1840 vtable_size
= MONO_SIZEOF_VTABLE
+ class->vtable_size
* sizeof (gpointer
);
1841 if (class->interface_offsets_count
) {
1842 imt_table_bytes
= sizeof (gpointer
) * (MONO_IMT_SIZE
);
1843 vtable_size
+= sizeof (gpointer
) * (MONO_IMT_SIZE
);
1844 mono_stats
.imt_number_of_tables
++;
1845 mono_stats
.imt_tables_size
+= (sizeof (gpointer
) * MONO_IMT_SIZE
);
1848 vtable_size
= sizeof (gpointer
) * (class->max_interface_id
+ 1) +
1849 MONO_SIZEOF_VTABLE
+ class->vtable_size
* sizeof (gpointer
);
1852 mono_stats
.used_class_count
++;
1853 mono_stats
.class_vtable_size
+= vtable_size
;
1854 interface_offsets
= mono_domain_alloc0 (domain
, vtable_size
);
1857 vt
= (MonoVTable
*) ((char*)interface_offsets
+ imt_table_bytes
);
1859 vt
= (MonoVTable
*) (interface_offsets
+ class->max_interface_id
+ 1);
1861 vt
->rank
= class->rank
;
1862 vt
->domain
= domain
;
1864 mono_class_compute_gc_descriptor (class);
1866 * We can't use typed allocation in the non-root domains, since the
1867 * collector needs the GC descriptor stored in the vtable even after
1868 * the mempool containing the vtable is destroyed when the domain is
1869 * unloaded. An alternative might be to allocate vtables in the GC
1870 * heap, but this does not seem to work (it leads to crashes inside
1871 * libgc). If that approach is tried, two gc descriptors need to be
1872 * allocated for each class: one for the root domain, and one for all
1873 * other domains. The second descriptor should contain a bit for the
1874 * vtable field in MonoObject, since we can no longer assume the
1875 * vtable is reachable by other roots after the appdomain is unloaded.
1877 #ifdef HAVE_BOEHM_GC
1878 if (domain
!= mono_get_root_domain () && !mono_dont_free_domains
)
1879 vt
->gc_descr
= GC_NO_DESCRIPTOR
;
1882 vt
->gc_descr
= class->gc_descr
;
1884 if ((class_size
= mono_class_data_size (class))) {
1885 if (class->has_static_refs
) {
1886 gpointer statics_gc_descr
;
1888 gsize default_bitmap
[4] = {0};
1891 bitmap
= compute_class_bitmap (class, default_bitmap
, sizeof (default_bitmap
) * 8, 0, &max_set
, TRUE
);
1892 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1893 statics_gc_descr
= mono_gc_make_descr_from_bitmap (bitmap
, max_set
+ 1);
1894 vt
->data
= mono_gc_alloc_fixed (class_size
, statics_gc_descr
);
1895 mono_domain_add_class_static_data (domain
, class, vt
->data
, NULL
);
1896 if (bitmap
!= default_bitmap
)
1899 vt
->data
= mono_domain_alloc0 (domain
, class_size
);
1901 mono_stats
.class_static_data_size
+= class_size
;
1906 while ((field
= mono_class_get_fields (class, &iter
))) {
1907 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
1909 if (mono_field_is_deleted (field
))
1911 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
1912 gint32 special_static
= class->no_special_static_fields
? SPECIAL_STATIC_NONE
: field_is_special_static (class, field
);
1913 if (special_static
!= SPECIAL_STATIC_NONE
) {
1914 guint32 size
, offset
;
1916 size
= mono_type_size (field
->type
, &align
);
1917 offset
= mono_alloc_special_static_data (special_static
, size
, align
);
1918 if (!domain
->special_static_fields
)
1919 domain
->special_static_fields
= g_hash_table_new (NULL
, NULL
);
1920 g_hash_table_insert (domain
->special_static_fields
, field
, GUINT_TO_POINTER (offset
));
1922 * This marks the field as special static to speed up the
1923 * checks in mono_field_static_get/set_value ().
1929 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_RVA
)) {
1930 MonoClass
*fklass
= mono_class_from_mono_type (field
->type
);
1931 const char *data
= mono_field_get_data (field
);
1933 g_assert (!(field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_DEFAULT
));
1934 t
= (char*)vt
->data
+ field
->offset
;
1935 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1938 if (fklass
->valuetype
) {
1939 memcpy (t
, data
, mono_class_value_size (fklass
, NULL
));
1941 /* it's a pointer type: add check */
1942 g_assert ((fklass
->byval_arg
.type
== MONO_TYPE_PTR
) || (fklass
->byval_arg
.type
== MONO_TYPE_FNPTR
));
1949 vt
->max_interface_id
= class->max_interface_id
;
1950 vt
->interface_bitmap
= class->interface_bitmap
;
1952 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1953 // class->name, class->interface_offsets_count);
1955 if (! ARCH_USE_IMT
) {
1956 /* initialize interface offsets */
1957 for (i
= 0; i
< class->interface_offsets_count
; ++i
) {
1958 int interface_id
= class->interfaces_packed
[i
]->interface_id
;
1959 int slot
= class->interface_offsets_packed
[i
];
1960 interface_offsets
[class->max_interface_id
- interface_id
] = &(vt
->vtable
[slot
]);
1964 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1965 * as we change the code in appdomain.c to invalidate vtables by
1966 * looking at the possible MonoClasses created for the domain.
1968 g_hash_table_insert (domain
->class_vtable_hash
, class, vt
);
1969 /* class->runtime_info is protected by the loader lock, both when
1970 * it it enlarged and when it is stored info.
1973 old_info
= class->runtime_info
;
1974 if (old_info
&& old_info
->max_domain
>= domain
->domain_id
) {
1975 /* someone already created a large enough runtime info */
1976 mono_memory_barrier ();
1977 old_info
->domain_vtables
[domain
->domain_id
] = vt
;
1979 int new_size
= domain
->domain_id
;
1981 new_size
= MAX (new_size
, old_info
->max_domain
);
1983 /* make the new size a power of two */
1985 while (new_size
> i
)
1988 /* this is a bounded memory retention issue: may want to
1989 * handle it differently when we'll have a rcu-like system.
1991 runtime_info
= mono_image_alloc0 (class->image
, MONO_SIZEOF_CLASS_RUNTIME_INFO
+ new_size
* sizeof (gpointer
));
1992 runtime_info
->max_domain
= new_size
- 1;
1993 /* copy the stuff from the older info */
1995 memcpy (runtime_info
->domain_vtables
, old_info
->domain_vtables
, (old_info
->max_domain
+ 1) * sizeof (gpointer
));
1997 runtime_info
->domain_vtables
[domain
->domain_id
] = vt
;
1999 mono_memory_barrier ();
2000 class->runtime_info
= runtime_info
;
2003 /* Initialize vtable */
2004 if (vtable_trampoline
) {
2005 // This also covers the AOT case
2006 for (i
= 0; i
< class->vtable_size
; ++i
) {
2007 vt
->vtable
[i
] = vtable_trampoline
;
2010 mono_class_setup_vtable (class);
2012 for (i
= 0; i
< class->vtable_size
; ++i
) {
2015 if ((cm
= class->vtable
[i
]))
2016 vt
->vtable
[i
] = vtable_trampoline
? vtable_trampoline
: arch_create_jit_trampoline (cm
);
2020 if (ARCH_USE_IMT
&& imt_table_bytes
) {
2021 /* Now that the vtable is full, we can actually fill up the IMT */
2022 if (imt_trampoline
) {
2023 /* lazy construction of the IMT entries enabled */
2024 for (i
= 0; i
< MONO_IMT_SIZE
; ++i
)
2025 interface_offsets
[i
] = imt_trampoline
;
2027 build_imt (class, vt
, domain
, interface_offsets
, NULL
);
2031 mono_domain_unlock (domain
);
2032 mono_loader_unlock ();
2034 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2035 if (mono_is_security_manager_active () && (class->exception_type
== MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND
) && raise_on_error
)
2036 mono_raise_exception (mono_class_get_exception_for_failure (class));
2038 /* make sure the parent is initialized */
2039 /*FIXME shouldn't this fail the current type?*/
2041 mono_class_vtable_full (domain
, class->parent
, raise_on_error
);
2043 /*FIXME check for OOM*/
2044 vt
->type
= mono_type_get_object (domain
, &class->byval_arg
);
2045 if (class->contextbound
)
2054 * mono_class_proxy_vtable:
2055 * @domain: the application domain
2056 * @remove_class: the remote class
2058 * Creates a vtable for transparent proxies. It is basically
2059 * a copy of the real vtable of the class wrapped in @remote_class,
2060 * but all function pointers invoke the remoting functions, and
2061 * vtable->klass points to the transparent proxy class, and not to @class.
2064 mono_class_proxy_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRemotingTarget target_type
)
2067 MonoVTable
*vt
, *pvt
;
2068 int i
, j
, vtsize
, max_interface_id
, extra_interface_vtsize
= 0;
2070 GSList
*extra_interfaces
= NULL
;
2071 MonoClass
*class = remote_class
->proxy_class
;
2072 gpointer
*interface_offsets
;
2074 vt
= mono_class_vtable (domain
, class);
2075 g_assert (vt
); /*FIXME property handle failure*/
2076 max_interface_id
= vt
->max_interface_id
;
2078 /* Calculate vtable space for extra interfaces */
2079 for (j
= 0; j
< remote_class
->interface_count
; j
++) {
2080 MonoClass
* iclass
= remote_class
->interfaces
[j
];
2084 /*FIXME test for interfaces with variant generic arguments*/
2085 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass
->interface_id
))
2086 continue; /* interface implemented by the class */
2087 if (g_slist_find (extra_interfaces
, iclass
))
2090 extra_interfaces
= g_slist_prepend (extra_interfaces
, iclass
);
2092 method_count
= mono_class_num_methods (iclass
);
2094 ifaces
= mono_class_get_implemented_interfaces (iclass
, &error
);
2095 g_assert (mono_error_ok (&error
)); /*FIXME do proper error handling*/
2097 for (i
= 0; i
< ifaces
->len
; ++i
) {
2098 MonoClass
*ic
= g_ptr_array_index (ifaces
, i
);
2099 /*FIXME test for interfaces with variant generic arguments*/
2100 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic
->interface_id
))
2101 continue; /* interface implemented by the class */
2102 if (g_slist_find (extra_interfaces
, ic
))
2104 extra_interfaces
= g_slist_prepend (extra_interfaces
, ic
);
2105 method_count
+= mono_class_num_methods (ic
);
2107 g_ptr_array_free (ifaces
, TRUE
);
2110 extra_interface_vtsize
+= method_count
* sizeof (gpointer
);
2111 if (iclass
->max_interface_id
> max_interface_id
) max_interface_id
= iclass
->max_interface_id
;
2115 mono_stats
.imt_number_of_tables
++;
2116 mono_stats
.imt_tables_size
+= (sizeof (gpointer
) * MONO_IMT_SIZE
);
2117 vtsize
= sizeof (gpointer
) * (MONO_IMT_SIZE
) +
2118 MONO_SIZEOF_VTABLE
+ class->vtable_size
* sizeof (gpointer
);
2120 vtsize
= sizeof (gpointer
) * (max_interface_id
+ 1) +
2121 MONO_SIZEOF_VTABLE
+ class->vtable_size
* sizeof (gpointer
);
2124 mono_stats
.class_vtable_size
+= vtsize
+ extra_interface_vtsize
;
2126 interface_offsets
= mono_domain_alloc0 (domain
, vtsize
+ extra_interface_vtsize
);
2128 pvt
= (MonoVTable
*) (interface_offsets
+ MONO_IMT_SIZE
);
2130 pvt
= (MonoVTable
*) (interface_offsets
+ max_interface_id
+ 1);
2131 memcpy (pvt
, vt
, MONO_SIZEOF_VTABLE
+ class->vtable_size
* sizeof (gpointer
));
2133 pvt
->klass
= mono_defaults
.transparent_proxy_class
;
2134 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2135 pvt
->gc_descr
= mono_defaults
.transparent_proxy_class
->gc_descr
;
2137 /* initialize vtable */
2138 mono_class_setup_vtable (class);
2139 for (i
= 0; i
< class->vtable_size
; ++i
) {
2142 if ((cm
= class->vtable
[i
]))
2143 pvt
->vtable
[i
] = arch_create_remoting_trampoline (domain
, cm
, target_type
);
2145 pvt
->vtable
[i
] = NULL
;
2148 if (class->flags
& TYPE_ATTRIBUTE_ABSTRACT
) {
2149 /* create trampolines for abstract methods */
2150 for (k
= class; k
; k
= k
->parent
) {
2152 gpointer iter
= NULL
;
2153 while ((m
= mono_class_get_methods (k
, &iter
)))
2154 if (!pvt
->vtable
[m
->slot
])
2155 pvt
->vtable
[m
->slot
] = arch_create_remoting_trampoline (domain
, m
, target_type
);
2159 pvt
->max_interface_id
= max_interface_id
;
2160 pvt
->interface_bitmap
= mono_domain_alloc0 (domain
, sizeof (guint8
) * (max_interface_id
/8 + 1 ));
2162 if (! ARCH_USE_IMT
) {
2163 /* initialize interface offsets */
2164 for (i
= 0; i
< class->interface_offsets_count
; ++i
) {
2165 int interface_id
= class->interfaces_packed
[i
]->interface_id
;
2166 int slot
= class->interface_offsets_packed
[i
];
2167 interface_offsets
[class->max_interface_id
- interface_id
] = &(pvt
->vtable
[slot
]);
2170 for (i
= 0; i
< class->interface_offsets_count
; ++i
) {
2171 int interface_id
= class->interfaces_packed
[i
]->interface_id
;
2172 pvt
->interface_bitmap
[interface_id
>> 3] |= (1 << (interface_id
& 7));
2175 if (extra_interfaces
) {
2176 int slot
= class->vtable_size
;
2182 /* Create trampolines for the methods of the interfaces */
2183 for (list_item
= extra_interfaces
; list_item
!= NULL
; list_item
=list_item
->next
) {
2184 interf
= list_item
->data
;
2186 if (! ARCH_USE_IMT
) {
2187 interface_offsets
[max_interface_id
- interf
->interface_id
] = &pvt
->vtable
[slot
];
2189 pvt
->interface_bitmap
[interf
->interface_id
>> 3] |= (1 << (interf
->interface_id
& 7));
2193 while ((cm
= mono_class_get_methods (interf
, &iter
)))
2194 pvt
->vtable
[slot
+ j
++] = arch_create_remoting_trampoline (domain
, cm
, target_type
);
2196 slot
+= mono_class_num_methods (interf
);
2198 if (! ARCH_USE_IMT
) {
2199 g_slist_free (extra_interfaces
);
2204 /* Now that the vtable is full, we can actually fill up the IMT */
2205 build_imt (class, pvt
, domain
, interface_offsets
, extra_interfaces
);
2206 if (extra_interfaces
) {
2207 g_slist_free (extra_interfaces
);
2215 * mono_class_field_is_special_static:
2217 * Returns whether @field is a thread/context static field.
2220 mono_class_field_is_special_static (MonoClassField
*field
)
2222 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
2224 if (mono_field_is_deleted (field
))
2226 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)) {
2227 if (field_is_special_static (field
->parent
, field
) != SPECIAL_STATIC_NONE
)
2234 * mono_class_has_special_static_fields:
2236 * Returns whenever @klass has any thread/context static fields.
2239 mono_class_has_special_static_fields (MonoClass
*klass
)
2241 MonoClassField
*field
;
2245 while ((field
= mono_class_get_fields (klass
, &iter
))) {
2246 g_assert (field
->parent
== klass
);
2247 if (mono_class_field_is_special_static (field
))
2255 * create_remote_class_key:
2256 * Creates an array of pointers that can be used as a hash key for a remote class.
2257 * The first element of the array is the number of pointers.
2260 create_remote_class_key (MonoRemoteClass
*remote_class
, MonoClass
*extra_class
)
2265 if (remote_class
== NULL
) {
2266 if (extra_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2267 key
= g_malloc (sizeof(gpointer
) * 3);
2268 key
[0] = GINT_TO_POINTER (2);
2269 key
[1] = mono_defaults
.marshalbyrefobject_class
;
2270 key
[2] = extra_class
;
2272 key
= g_malloc (sizeof(gpointer
) * 2);
2273 key
[0] = GINT_TO_POINTER (1);
2274 key
[1] = extra_class
;
2277 if (extra_class
!= NULL
&& (extra_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
)) {
2278 key
= g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 3));
2279 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 2);
2280 key
[1] = remote_class
->proxy_class
;
2282 // Keep the list of interfaces sorted
2283 for (i
= 0, j
= 2; i
< remote_class
->interface_count
; i
++, j
++) {
2284 if (extra_class
&& remote_class
->interfaces
[i
] > extra_class
) {
2285 key
[j
++] = extra_class
;
2288 key
[j
] = remote_class
->interfaces
[i
];
2291 key
[j
] = extra_class
;
2293 // Replace the old class. The interface list is the same
2294 key
= g_malloc (sizeof(gpointer
) * (remote_class
->interface_count
+ 2));
2295 key
[0] = GINT_TO_POINTER (remote_class
->interface_count
+ 1);
2296 key
[1] = extra_class
!= NULL
? extra_class
: remote_class
->proxy_class
;
2297 for (i
= 0; i
< remote_class
->interface_count
; i
++)
2298 key
[2 + i
] = remote_class
->interfaces
[i
];
2306 * copy_remote_class_key:
2308 * Make a copy of KEY in the domain and return the copy.
2311 copy_remote_class_key (MonoDomain
*domain
, gpointer
*key
)
2313 int key_size
= (GPOINTER_TO_UINT (key
[0]) + 1) * sizeof (gpointer
);
2314 gpointer
*mp_key
= mono_domain_alloc (domain
, key_size
);
2316 memcpy (mp_key
, key
, key_size
);
2322 * mono_remote_class:
2323 * @domain: the application domain
2324 * @class_name: name of the remote class
2326 * Creates and initializes a MonoRemoteClass object for a remote type.
2328 * Can raise an exception on failure.
2331 mono_remote_class (MonoDomain
*domain
, MonoString
*class_name
, MonoClass
*proxy_class
)
2334 MonoRemoteClass
*rc
;
2335 gpointer
* key
, *mp_key
;
2338 key
= create_remote_class_key (NULL
, proxy_class
);
2340 mono_domain_lock (domain
);
2341 rc
= g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2345 mono_domain_unlock (domain
);
2349 name
= mono_string_to_utf8_mp (domain
->mp
, class_name
, &error
);
2350 if (!mono_error_ok (&error
)) {
2352 mono_domain_unlock (domain
);
2353 mono_error_raise_exception (&error
);
2356 mp_key
= copy_remote_class_key (domain
, key
);
2360 if (proxy_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2361 rc
= mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*));
2362 rc
->interface_count
= 1;
2363 rc
->interfaces
[0] = proxy_class
;
2364 rc
->proxy_class
= mono_defaults
.marshalbyrefobject_class
;
2366 rc
= mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
);
2367 rc
->interface_count
= 0;
2368 rc
->proxy_class
= proxy_class
;
2371 rc
->default_vtable
= NULL
;
2372 rc
->xdomain_vtable
= NULL
;
2373 rc
->proxy_class_name
= name
;
2374 mono_perfcounters
->loader_bytes
+= mono_string_length (class_name
) + 1;
2376 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2378 mono_domain_unlock (domain
);
2383 * clone_remote_class:
2384 * Creates a copy of the remote_class, adding the provided class or interface
2386 static MonoRemoteClass
*
2387 clone_remote_class (MonoDomain
*domain
, MonoRemoteClass
* remote_class
, MonoClass
*extra_class
)
2389 MonoRemoteClass
*rc
;
2390 gpointer
* key
, *mp_key
;
2392 key
= create_remote_class_key (remote_class
, extra_class
);
2393 rc
= g_hash_table_lookup (domain
->proxy_vtable_hash
, key
);
2399 mp_key
= copy_remote_class_key (domain
, key
);
2403 if (extra_class
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2405 rc
= mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * (remote_class
->interface_count
+ 1));
2406 rc
->proxy_class
= remote_class
->proxy_class
;
2407 rc
->interface_count
= remote_class
->interface_count
+ 1;
2409 // Keep the list of interfaces sorted, since the hash key of
2410 // the remote class depends on this
2411 for (i
= 0, j
= 0; i
< remote_class
->interface_count
; i
++, j
++) {
2412 if (remote_class
->interfaces
[i
] > extra_class
&& i
== j
)
2413 rc
->interfaces
[j
++] = extra_class
;
2414 rc
->interfaces
[j
] = remote_class
->interfaces
[i
];
2417 rc
->interfaces
[j
] = extra_class
;
2419 // Replace the old class. The interface array is the same
2420 rc
= mono_domain_alloc (domain
, MONO_SIZEOF_REMOTE_CLASS
+ sizeof(MonoClass
*) * remote_class
->interface_count
);
2421 rc
->proxy_class
= extra_class
;
2422 rc
->interface_count
= remote_class
->interface_count
;
2423 if (rc
->interface_count
> 0)
2424 memcpy (rc
->interfaces
, remote_class
->interfaces
, rc
->interface_count
* sizeof (MonoClass
*));
2427 rc
->default_vtable
= NULL
;
2428 rc
->xdomain_vtable
= NULL
;
2429 rc
->proxy_class_name
= remote_class
->proxy_class_name
;
2431 g_hash_table_insert (domain
->proxy_vtable_hash
, key
, rc
);
2437 mono_remote_class_vtable (MonoDomain
*domain
, MonoRemoteClass
*remote_class
, MonoRealProxy
*rp
)
2439 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2440 mono_domain_lock (domain
);
2441 if (rp
->target_domain_id
!= -1) {
2442 if (remote_class
->xdomain_vtable
== NULL
)
2443 remote_class
->xdomain_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_APPDOMAIN
);
2444 mono_domain_unlock (domain
);
2445 mono_loader_unlock ();
2446 return remote_class
->xdomain_vtable
;
2448 if (remote_class
->default_vtable
== NULL
) {
2451 type
= ((MonoReflectionType
*)rp
->class_to_proxy
)->type
;
2452 klass
= mono_class_from_mono_type (type
);
2453 if ((klass
->is_com_object
|| (mono_defaults
.com_object_class
&& klass
== mono_defaults
.com_object_class
)) && !mono_class_vtable (mono_domain_get (), klass
)->remote
)
2454 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_COMINTEROP
);
2456 remote_class
->default_vtable
= mono_class_proxy_vtable (domain
, remote_class
, MONO_REMOTING_TARGET_UNKNOWN
);
2459 mono_domain_unlock (domain
);
2460 mono_loader_unlock ();
2461 return remote_class
->default_vtable
;
2465 * mono_upgrade_remote_class:
2466 * @domain: the application domain
2467 * @tproxy: the proxy whose remote class has to be upgraded.
2468 * @klass: class to which the remote class can be casted.
2470 * Updates the vtable of the remote class by adding the necessary method slots
2471 * and interface offsets so it can be safely casted to klass. klass can be a
2472 * class or an interface.
2475 mono_upgrade_remote_class (MonoDomain
*domain
, MonoObject
*proxy_object
, MonoClass
*klass
)
2477 MonoTransparentProxy
*tproxy
;
2478 MonoRemoteClass
*remote_class
;
2479 gboolean redo_vtable
;
2481 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2482 mono_domain_lock (domain
);
2484 tproxy
= (MonoTransparentProxy
*) proxy_object
;
2485 remote_class
= tproxy
->remote_class
;
2487 if (klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2490 for (i
= 0; i
< remote_class
->interface_count
&& redo_vtable
; i
++)
2491 if (remote_class
->interfaces
[i
] == klass
)
2492 redo_vtable
= FALSE
;
2495 redo_vtable
= (remote_class
->proxy_class
!= klass
);
2499 tproxy
->remote_class
= clone_remote_class (domain
, remote_class
, klass
);
2500 proxy_object
->vtable
= mono_remote_class_vtable (domain
, tproxy
->remote_class
, tproxy
->rp
);
2503 mono_domain_unlock (domain
);
2504 mono_loader_unlock ();
2509 * mono_object_get_virtual_method:
2510 * @obj: object to operate on.
2513 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2514 * the instance of a callvirt of method.
2517 mono_object_get_virtual_method (MonoObject
*obj
, MonoMethod
*method
)
2520 MonoMethod
**vtable
;
2522 MonoMethod
*res
= NULL
;
2524 klass
= mono_object_class (obj
);
2525 if (klass
== mono_defaults
.transparent_proxy_class
) {
2526 klass
= ((MonoTransparentProxy
*)obj
)->remote_class
->proxy_class
;
2532 if (!is_proxy
&& ((method
->flags
& METHOD_ATTRIBUTE_FINAL
) || !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)))
2535 mono_class_setup_vtable (klass
);
2536 vtable
= klass
->vtable
;
2538 if (method
->slot
== -1) {
2539 /* method->slot might not be set for instances of generic methods */
2540 if (method
->is_inflated
) {
2541 g_assert (((MonoMethodInflated
*)method
)->declaring
->slot
!= -1);
2542 method
->slot
= ((MonoMethodInflated
*)method
)->declaring
->slot
;
2545 g_assert_not_reached ();
2549 /* check method->slot is a valid index: perform isinstance? */
2550 if (method
->slot
!= -1) {
2551 if (method
->klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
2553 gboolean variance_used
= FALSE
;
2554 int iface_offset
= mono_class_interface_offset_with_variance (klass
, method
->klass
, &variance_used
);
2555 g_assert (iface_offset
> 0);
2556 res
= vtable
[iface_offset
+ method
->slot
];
2559 res
= vtable
[method
->slot
];
2564 /* It may be an interface, abstract class method or generic method */
2565 if (!res
|| mono_method_signature (res
)->generic_param_count
)
2568 /* generic methods demand invoke_with_check */
2569 if (mono_method_signature (res
)->generic_param_count
)
2570 res
= mono_marshal_get_remoting_invoke_with_check (res
);
2573 if (klass
== mono_defaults
.com_object_class
|| klass
->is_com_object
)
2574 res
= mono_cominterop_get_invoke (res
);
2577 res
= mono_marshal_get_remoting_invoke (res
);
2580 if (method
->is_inflated
) {
2581 /* Have to inflate the result */
2582 res
= mono_class_inflate_generic_method (res
, &((MonoMethodInflated
*)method
)->context
);
2592 dummy_mono_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
2594 g_error ("runtime invoke called on uninitialized runtime");
2598 static MonoInvokeFunc default_mono_runtime_invoke
= dummy_mono_runtime_invoke
;
2601 * mono_runtime_invoke:
2602 * @method: method to invoke
2603 * @obJ: object instance
2604 * @params: arguments to the method
2605 * @exc: exception information.
2607 * Invokes the method represented by @method on the object @obj.
2609 * obj is the 'this' pointer, it should be NULL for static
2610 * methods, a MonoObject* for object instances and a pointer to
2611 * the value type for value types.
2613 * The params array contains the arguments to the method with the
2614 * same convention: MonoObject* pointers for object instances and
2615 * pointers to the value type otherwise.
2617 * From unmanaged code you'll usually use the
2618 * mono_runtime_invoke() variant.
2620 * Note that this function doesn't handle virtual methods for
2621 * you, it will exec the exact method you pass: we still need to
2622 * expose a function to lookup the derived class implementation
2623 * of a virtual method (there are examples of this in the code,
2626 * You can pass NULL as the exc argument if you don't want to
2627 * catch exceptions, otherwise, *exc will be set to the exception
2628 * thrown, if any. if an exception is thrown, you can't use the
2629 * MonoObject* result from the function.
2631 * If the method returns a value type, it is boxed in an object
2635 mono_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
2639 if (mono_runtime_get_no_exec ())
2640 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method
, TRUE
));
2642 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS
)
2643 mono_profiler_method_start_invoke (method
);
2645 result
= default_mono_runtime_invoke (method
, obj
, params
, exc
);
2647 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS
)
2648 mono_profiler_method_end_invoke (method
);
2654 * mono_method_get_unmanaged_thunk:
2655 * @method: method to generate a thunk for.
2657 * Returns an unmanaged->managed thunk that can be used to call
2658 * a managed method directly from C.
2660 * The thunk's C signature closely matches the managed signature:
2662 * C#: public bool Equals (object obj);
2663 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2664 * MonoObject*, MonoException**);
2666 * The 1st ("this") parameter must not be used with static methods:
2668 * C#: public static bool ReferenceEquals (object a, object b);
2669 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2672 * The last argument must be a non-null pointer of a MonoException* pointer.
2673 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2674 * exception has been thrown in managed code. Otherwise it will point
2675 * to the MonoException* caught by the thunk. In this case, the result of
2676 * the thunk is undefined:
2678 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2679 * MonoException *ex = NULL;
2680 * Equals func = mono_method_get_unmanaged_thunk (method);
2681 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2683 * // handle exception
2686 * The calling convention of the thunk matches the platform's default
2687 * convention. This means that under Windows, C declarations must
2688 * contain the __stdcall attribute:
2690 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2691 * MonoObject*, MonoException**);
2695 * Value type arguments and return values are treated as they were objects:
2697 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2698 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2700 * Arguments must be properly boxed upon trunk's invocation, while return
2701 * values must be unboxed.
2704 mono_method_get_unmanaged_thunk (MonoMethod
*method
)
2706 method
= mono_marshal_get_thunk_invoke_wrapper (method
);
2707 return mono_compile_method (method
);
2711 set_value (MonoType
*type
, void *dest
, void *value
, int deref_pointer
)
2715 /* object fields cannot be byref, so we don't need a
2717 gpointer
*p
= (gpointer
*)dest
;
2724 case MONO_TYPE_BOOLEAN
:
2726 case MONO_TYPE_U1
: {
2727 guint8
*p
= (guint8
*)dest
;
2728 *p
= value
? *(guint8
*)value
: 0;
2733 case MONO_TYPE_CHAR
: {
2734 guint16
*p
= (guint16
*)dest
;
2735 *p
= value
? *(guint16
*)value
: 0;
2738 #if SIZEOF_VOID_P == 4
2743 case MONO_TYPE_U4
: {
2744 gint32
*p
= (gint32
*)dest
;
2745 *p
= value
? *(gint32
*)value
: 0;
2748 #if SIZEOF_VOID_P == 8
2753 case MONO_TYPE_U8
: {
2754 gint64
*p
= (gint64
*)dest
;
2755 *p
= value
? *(gint64
*)value
: 0;
2758 case MONO_TYPE_R4
: {
2759 float *p
= (float*)dest
;
2760 *p
= value
? *(float*)value
: 0;
2763 case MONO_TYPE_R8
: {
2764 double *p
= (double*)dest
;
2765 *p
= value
? *(double*)value
: 0;
2768 case MONO_TYPE_STRING
:
2769 case MONO_TYPE_SZARRAY
:
2770 case MONO_TYPE_CLASS
:
2771 case MONO_TYPE_OBJECT
:
2772 case MONO_TYPE_ARRAY
:
2773 mono_gc_wbarrier_generic_store (dest
, deref_pointer
? *(gpointer
*)value
: value
);
2775 case MONO_TYPE_FNPTR
:
2776 case MONO_TYPE_PTR
: {
2777 gpointer
*p
= (gpointer
*)dest
;
2778 *p
= deref_pointer
? *(gpointer
*)value
: value
;
2781 case MONO_TYPE_VALUETYPE
:
2782 /* note that 't' and 'type->type' can be different */
2783 if (type
->type
== MONO_TYPE_VALUETYPE
&& type
->data
.klass
->enumtype
) {
2784 t
= mono_class_enum_basetype (type
->data
.klass
)->type
;
2787 MonoClass
*class = mono_class_from_mono_type (type
);
2788 int size
= mono_class_value_size (class, NULL
);
2790 memset (dest
, 0, size
);
2792 mono_gc_wbarrier_value_copy (dest
, value
, 1, class);
2795 case MONO_TYPE_GENERICINST
:
2796 t
= type
->data
.generic_class
->container_class
->byval_arg
.type
;
2799 g_warning ("got type %x", type
->type
);
2800 g_assert_not_reached ();
2805 * mono_field_set_value:
2806 * @obj: Instance object
2807 * @field: MonoClassField describing the field to set
2808 * @value: The value to be set
2810 * Sets the value of the field described by @field in the object instance @obj
2811 * to the value passed in @value. This method should only be used for instance
2812 * fields. For static fields, use mono_field_static_set_value.
2814 * The value must be on the native format of the field type.
2817 mono_field_set_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
2821 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
));
2823 dest
= (char*)obj
+ field
->offset
;
2824 set_value (field
->type
, dest
, value
, FALSE
);
2828 * mono_field_static_set_value:
2829 * @field: MonoClassField describing the field to set
2830 * @value: The value to be set
2832 * Sets the value of the static field described by @field
2833 * to the value passed in @value.
2835 * The value must be on the native format of the field type.
2838 mono_field_static_set_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
2842 g_return_if_fail (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
2843 /* you cant set a constant! */
2844 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
));
2846 if (field
->offset
== -1) {
2847 /* Special static */
2848 gpointer addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
2849 dest
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
2851 dest
= (char*)vt
->data
+ field
->offset
;
2853 set_value (field
->type
, dest
, value
, FALSE
);
2856 /* Used by the debugger */
2858 mono_vtable_get_static_field_data (MonoVTable
*vt
)
2864 * mono_field_get_value:
2865 * @obj: Object instance
2866 * @field: MonoClassField describing the field to fetch information from
2867 * @value: pointer to the location where the value will be stored
2869 * Use this routine to get the value of the field @field in the object
2872 * The pointer provided by value must be of the field type, for reference
2873 * types this is a MonoObject*, for value types its the actual pointer to
2878 * mono_field_get_value (obj, int_field, &i);
2881 mono_field_get_value (MonoObject
*obj
, MonoClassField
*field
, void *value
)
2885 g_return_if_fail (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
));
2887 src
= (char*)obj
+ field
->offset
;
2888 set_value (field
->type
, value
, src
, TRUE
);
2892 * mono_field_get_value_object:
2893 * @domain: domain where the object will be created (if boxing)
2894 * @field: MonoClassField describing the field to fetch information from
2895 * @obj: The object instance for the field.
2897 * Returns: a new MonoObject with the value from the given field. If the
2898 * field represents a value type, the value is boxed.
2902 mono_field_get_value_object (MonoDomain
*domain
, MonoClassField
*field
, MonoObject
*obj
)
2906 MonoVTable
*vtable
= NULL
;
2908 gboolean is_static
= FALSE
;
2909 gboolean is_ref
= FALSE
;
2911 switch (field
->type
->type
) {
2912 case MONO_TYPE_STRING
:
2913 case MONO_TYPE_OBJECT
:
2914 case MONO_TYPE_CLASS
:
2915 case MONO_TYPE_ARRAY
:
2916 case MONO_TYPE_SZARRAY
:
2921 case MONO_TYPE_BOOLEAN
:
2924 case MONO_TYPE_CHAR
:
2933 case MONO_TYPE_VALUETYPE
:
2934 is_ref
= field
->type
->byref
;
2936 case MONO_TYPE_GENERICINST
:
2937 is_ref
= !field
->type
->data
.generic_class
->container_class
->valuetype
;
2940 g_error ("type 0x%x not handled in "
2941 "mono_field_get_value_object", field
->type
->type
);
2945 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
2947 vtable
= mono_class_vtable (domain
, field
->parent
);
2949 char *name
= mono_type_get_full_name (field
->parent
);
2950 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name
);
2954 if (!vtable
->initialized
)
2955 mono_runtime_class_init (vtable
);
2960 mono_field_static_get_value (vtable
, field
, &o
);
2962 mono_field_get_value (obj
, field
, &o
);
2967 /* boxed value type */
2968 klass
= mono_class_from_mono_type (field
->type
);
2969 o
= mono_object_new (domain
, klass
);
2970 v
= ((gchar
*) o
) + sizeof (MonoObject
);
2972 mono_field_static_get_value (vtable
, field
, v
);
2974 mono_field_get_value (obj
, field
, v
);
2981 mono_get_constant_value_from_blob (MonoDomain
* domain
, MonoTypeEnum type
, const char *blob
, void *value
)
2984 const char *p
= blob
;
2985 mono_metadata_decode_blob_size (p
, &p
);
2988 case MONO_TYPE_BOOLEAN
:
2991 *(guint8
*) value
= *p
;
2993 case MONO_TYPE_CHAR
:
2996 *(guint16
*) value
= read16 (p
);
3000 *(guint32
*) value
= read32 (p
);
3004 *(guint64
*) value
= read64 (p
);
3007 readr4 (p
, (float*) value
);
3010 readr8 (p
, (double*) value
);
3012 case MONO_TYPE_STRING
:
3013 *(gpointer
*) value
= mono_ldstr_metadata_sig (domain
, blob
);
3015 case MONO_TYPE_CLASS
:
3016 *(gpointer
*) value
= NULL
;
3020 g_warning ("type 0x%02x should not be in constant table", type
);
3026 get_default_field_value (MonoDomain
* domain
, MonoClassField
*field
, void *value
)
3028 MonoTypeEnum def_type
;
3031 data
= mono_class_get_field_default_value (field
, &def_type
);
3032 mono_get_constant_value_from_blob (domain
, def_type
, data
, value
);
3036 * mono_field_static_get_value:
3037 * @vt: vtable to the object
3038 * @field: MonoClassField describing the field to fetch information from
3039 * @value: where the value is returned
3041 * Use this routine to get the value of the static field @field value.
3043 * The pointer provided by value must be of the field type, for reference
3044 * types this is a MonoObject*, for value types its the actual pointer to
3049 * mono_field_static_get_value (vt, int_field, &i);
3052 mono_field_static_get_value (MonoVTable
*vt
, MonoClassField
*field
, void *value
)
3056 g_return_if_fail (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
3058 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
) {
3059 get_default_field_value (vt
->domain
, field
, value
);
3063 if (field
->offset
== -1) {
3064 /* Special static */
3065 gpointer addr
= g_hash_table_lookup (vt
->domain
->special_static_fields
, field
);
3066 src
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
3068 src
= (char*)vt
->data
+ field
->offset
;
3070 set_value (field
->type
, value
, src
, TRUE
);
3074 * mono_property_set_value:
3075 * @prop: MonoProperty to set
3076 * @obj: instance object on which to act
3077 * @params: parameters to pass to the propery
3078 * @exc: optional exception
3080 * Invokes the property's set method with the given arguments on the
3081 * object instance obj (or NULL for static properties).
3083 * You can pass NULL as the exc argument if you don't want to
3084 * catch exceptions, otherwise, *exc will be set to the exception
3085 * thrown, if any. if an exception is thrown, you can't use the
3086 * MonoObject* result from the function.
3089 mono_property_set_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3091 default_mono_runtime_invoke (prop
->set
, obj
, params
, exc
);
3095 * mono_property_get_value:
3096 * @prop: MonoProperty to fetch
3097 * @obj: instance object on which to act
3098 * @params: parameters to pass to the propery
3099 * @exc: optional exception
3101 * Invokes the property's get method with the given arguments on the
3102 * object instance obj (or NULL for static properties).
3104 * You can pass NULL as the exc argument if you don't want to
3105 * catch exceptions, otherwise, *exc will be set to the exception
3106 * thrown, if any. if an exception is thrown, you can't use the
3107 * MonoObject* result from the function.
3109 * Returns: the value from invoking the get method on the property.
3112 mono_property_get_value (MonoProperty
*prop
, void *obj
, void **params
, MonoObject
**exc
)
3114 return default_mono_runtime_invoke (prop
->get
, obj
, params
, exc
);
3118 * mono_nullable_init:
3119 * @buf: The nullable structure to initialize.
3120 * @value: the value to initialize from
3121 * @klass: the type for the object
3123 * Initialize the nullable structure pointed to by @buf from @value which
3124 * should be a boxed value type. The size of @buf should be able to hold
3125 * as much data as the @klass->instance_size (which is the number of bytes
3126 * that will be copies).
3128 * Since Nullables have variable structure, we can not define a C
3129 * structure for them.
3132 mono_nullable_init (guint8
*buf
, MonoObject
*value
, MonoClass
*klass
)
3134 MonoClass
*param_class
= klass
->cast_class
;
3136 g_assert (mono_class_from_mono_type (klass
->fields
[0].type
) == param_class
);
3137 g_assert (mono_class_from_mono_type (klass
->fields
[1].type
) == mono_defaults
.boolean_class
);
3139 *(guint8
*)(buf
+ klass
->fields
[1].offset
- sizeof (MonoObject
)) = value
? 1 : 0;
3141 if (param_class
->has_references
)
3142 mono_gc_wbarrier_value_copy (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_object_unbox (value
), 1, param_class
);
3144 memcpy (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_object_unbox (value
), mono_class_value_size (param_class
, NULL
));
3146 memset (buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), 0, mono_class_value_size (param_class
, NULL
));
3151 * mono_nullable_box:
3152 * @buf: The buffer representing the data to be boxed
3153 * @klass: the type to box it as.
3155 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3159 mono_nullable_box (guint8
*buf
, MonoClass
*klass
)
3161 MonoClass
*param_class
= klass
->cast_class
;
3163 g_assert (mono_class_from_mono_type (klass
->fields
[0].type
) == param_class
);
3164 g_assert (mono_class_from_mono_type (klass
->fields
[1].type
) == mono_defaults
.boolean_class
);
3166 if (*(guint8
*)(buf
+ klass
->fields
[1].offset
- sizeof (MonoObject
))) {
3167 MonoObject
*o
= mono_object_new (mono_domain_get (), param_class
);
3168 if (param_class
->has_references
)
3169 mono_gc_wbarrier_value_copy (mono_object_unbox (o
), buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), 1, param_class
);
3171 memcpy (mono_object_unbox (o
), buf
+ klass
->fields
[0].offset
- sizeof (MonoObject
), mono_class_value_size (param_class
, NULL
));
3179 * mono_get_delegate_invoke:
3180 * @klass: The delegate class
3182 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3185 mono_get_delegate_invoke (MonoClass
*klass
)
3189 /* This is called at runtime, so avoid the slower search in metadata */
3190 mono_class_setup_methods (klass
);
3191 if (klass
->exception_type
)
3193 im
= mono_class_get_method_from_name (klass
, "Invoke", -1);
3200 * mono_runtime_delegate_invoke:
3201 * @delegate: pointer to a delegate object.
3202 * @params: parameters for the delegate.
3203 * @exc: Pointer to the exception result.
3205 * Invokes the delegate method @delegate with the parameters provided.
3207 * You can pass NULL as the exc argument if you don't want to
3208 * catch exceptions, otherwise, *exc will be set to the exception
3209 * thrown, if any. if an exception is thrown, you can't use the
3210 * MonoObject* result from the function.
3213 mono_runtime_delegate_invoke (MonoObject
*delegate
, void **params
, MonoObject
**exc
)
3217 im
= mono_get_delegate_invoke (delegate
->vtable
->klass
);
3220 return mono_runtime_invoke (im
, delegate
, params
, exc
);
3223 static char **main_args
= NULL
;
3224 static int num_main_args
;
3227 * mono_runtime_get_main_args:
3229 * Returns: a MonoArray with the arguments passed to the main program
3232 mono_runtime_get_main_args (void)
3236 MonoDomain
*domain
= mono_domain_get ();
3241 res
= (MonoArray
*)mono_array_new (domain
, mono_defaults
.string_class
, num_main_args
);
3243 for (i
= 0; i
< num_main_args
; ++i
)
3244 mono_array_setref (res
, i
, mono_string_new (domain
, main_args
[i
]));
3250 fire_process_exit_event (void)
3252 MonoClassField
*field
;
3253 MonoDomain
*domain
= mono_domain_get ();
3255 MonoObject
*delegate
, *exc
;
3257 field
= mono_class_get_field_from_name (mono_defaults
.appdomain_class
, "ProcessExit");
3260 if (domain
!= mono_get_root_domain ())
3263 delegate
= *(MonoObject
**)(((char *)domain
->domain
) + field
->offset
);
3264 if (delegate
== NULL
)
3269 mono_runtime_delegate_invoke (delegate
, pa
, &exc
);
3273 * mono_runtime_run_main:
3274 * @method: the method to start the application with (usually Main)
3275 * @argc: number of arguments from the command line
3276 * @argv: array of strings from the command line
3277 * @exc: excetption results
3279 * Execute a standard Main() method (argc/argv contains the
3280 * executable name). This method also sets the command line argument value
3281 * needed by System.Environment.
3286 mono_runtime_run_main (MonoMethod
*method
, int argc
, char* argv
[],
3290 MonoArray
*args
= NULL
;
3291 MonoDomain
*domain
= mono_domain_get ();
3292 gchar
*utf8_fullpath
;
3295 g_assert (method
!= NULL
);
3297 mono_thread_set_main (mono_thread_current ());
3299 main_args
= g_new0 (char*, argc
);
3300 num_main_args
= argc
;
3302 if (!g_path_is_absolute (argv
[0])) {
3303 gchar
*basename
= g_path_get_basename (argv
[0]);
3304 gchar
*fullpath
= g_build_filename (method
->klass
->image
->assembly
->basedir
,
3308 utf8_fullpath
= mono_utf8_from_external (fullpath
);
3309 if(utf8_fullpath
== NULL
) {
3310 /* Printing the arg text will cause glib to
3311 * whinge about "Invalid UTF-8", but at least
3312 * its relevant, and shows the problem text
3315 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath
);
3316 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3323 utf8_fullpath
= mono_utf8_from_external (argv
[0]);
3324 if(utf8_fullpath
== NULL
) {
3325 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv
[0]);
3326 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3331 main_args
[0] = utf8_fullpath
;
3333 for (i
= 1; i
< argc
; ++i
) {
3336 utf8_arg
=mono_utf8_from_external (argv
[i
]);
3337 if(utf8_arg
==NULL
) {
3338 /* Ditto the comment about Invalid UTF-8 here */
3339 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i
, argv
[i
]);
3340 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3344 main_args
[i
] = utf8_arg
;
3348 if (mono_method_signature (method
)->param_count
) {
3349 args
= (MonoArray
*)mono_array_new (domain
, mono_defaults
.string_class
, argc
);
3350 for (i
= 0; i
< argc
; ++i
) {
3351 /* The encodings should all work, given that
3352 * we've checked all these args for the
3355 gchar
*str
= mono_utf8_from_external (argv
[i
]);
3356 MonoString
*arg
= mono_string_new (domain
, str
);
3357 mono_array_setref (args
, i
, arg
);
3361 args
= (MonoArray
*)mono_array_new (domain
, mono_defaults
.string_class
, 0);
3364 mono_assembly_set_main (method
->klass
->image
->assembly
);
3366 result
= mono_runtime_exec_main (method
, args
, exc
);
3367 fire_process_exit_event ();
3372 serialize_object (MonoObject
*obj
, gboolean
*failure
, MonoObject
**exc
)
3374 static MonoMethod
*serialize_method
;
3379 if (!serialize_method
) {
3380 MonoClass
*klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting", "RemotingServices");
3381 serialize_method
= mono_class_get_method_from_name (klass
, "SerializeCallData", -1);
3384 if (!serialize_method
) {
3389 g_assert (!mono_object_class (obj
)->marshalbyref
);
3393 array
= mono_runtime_invoke (serialize_method
, NULL
, params
, exc
);
3401 deserialize_object (MonoObject
*obj
, gboolean
*failure
, MonoObject
**exc
)
3403 static MonoMethod
*deserialize_method
;
3408 if (!deserialize_method
) {
3409 MonoClass
*klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting", "RemotingServices");
3410 deserialize_method
= mono_class_get_method_from_name (klass
, "DeserializeCallData", -1);
3412 if (!deserialize_method
) {
3419 result
= mono_runtime_invoke (deserialize_method
, NULL
, params
, exc
);
3427 make_transparent_proxy (MonoObject
*obj
, gboolean
*failure
, MonoObject
**exc
)
3429 static MonoMethod
*get_proxy_method
;
3431 MonoDomain
*domain
= mono_domain_get ();
3432 MonoRealProxy
*real_proxy
;
3433 MonoReflectionType
*reflection_type
;
3434 MonoTransparentProxy
*transparent_proxy
;
3436 if (!get_proxy_method
)
3437 get_proxy_method
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0);
3439 g_assert (obj
->vtable
->klass
->marshalbyref
);
3441 real_proxy
= (MonoRealProxy
*) mono_object_new (domain
, mono_defaults
.real_proxy_class
);
3442 reflection_type
= mono_type_get_object (domain
, &obj
->vtable
->klass
->byval_arg
);
3444 MONO_OBJECT_SETREF (real_proxy
, class_to_proxy
, reflection_type
);
3445 MONO_OBJECT_SETREF (real_proxy
, unwrapped_server
, obj
);
3448 transparent_proxy
= (MonoTransparentProxy
*) mono_runtime_invoke (get_proxy_method
, real_proxy
, NULL
, exc
);
3452 return (MonoObject
*) transparent_proxy
;
3456 * mono_object_xdomain_representation
3458 * @target_domain: a domain
3459 * @exc: pointer to a MonoObject*
3461 * Creates a representation of obj in the domain target_domain. This
3462 * is either a copy of obj arrived through via serialization and
3463 * deserialization or a proxy, depending on whether the object is
3464 * serializable or marshal by ref. obj must not be in target_domain.
3466 * If the object cannot be represented in target_domain, NULL is
3467 * returned and *exc is set to an appropriate exception.
3470 mono_object_xdomain_representation (MonoObject
*obj
, MonoDomain
*target_domain
, MonoObject
**exc
)
3472 MonoObject
*deserialized
= NULL
;
3473 gboolean failure
= FALSE
;
3477 if (mono_object_class (obj
)->marshalbyref
) {
3478 deserialized
= make_transparent_proxy (obj
, &failure
, exc
);
3480 MonoDomain
*domain
= mono_domain_get ();
3481 MonoObject
*serialized
;
3483 mono_domain_set_internal_with_options (mono_object_domain (obj
), FALSE
);
3484 serialized
= serialize_object (obj
, &failure
, exc
);
3485 mono_domain_set_internal_with_options (target_domain
, FALSE
);
3487 deserialized
= deserialize_object (serialized
, &failure
, exc
);
3488 if (domain
!= target_domain
)
3489 mono_domain_set_internal_with_options (domain
, FALSE
);
3492 return deserialized
;
3495 /* Used in call_unhandled_exception_delegate */
3497 create_unhandled_exception_eventargs (MonoObject
*exc
)
3501 MonoMethod
*method
= NULL
;
3502 MonoBoolean is_terminating
= TRUE
;
3505 klass
= mono_class_from_name (mono_defaults
.corlib
, "System", "UnhandledExceptionEventArgs");
3508 mono_class_init (klass
);
3510 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3511 method
= mono_class_get_method_from_name_flags (klass
, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC
);
3515 args
[1] = &is_terminating
;
3517 obj
= mono_object_new (mono_domain_get (), klass
);
3518 mono_runtime_invoke (method
, obj
, args
, NULL
);
3523 /* Used in mono_unhandled_exception */
3525 call_unhandled_exception_delegate (MonoDomain
*domain
, MonoObject
*delegate
, MonoObject
*exc
) {
3526 MonoObject
*e
= NULL
;
3528 MonoDomain
*current_domain
= mono_domain_get ();
3530 if (domain
!= current_domain
)
3531 mono_domain_set_internal_with_options (domain
, FALSE
);
3533 g_assert (domain
== mono_object_domain (domain
->domain
));
3535 if (mono_object_domain (exc
) != domain
) {
3536 MonoObject
*serialization_exc
;
3538 exc
= mono_object_xdomain_representation (exc
, domain
, &serialization_exc
);
3540 if (serialization_exc
) {
3542 exc
= mono_object_xdomain_representation (serialization_exc
, domain
, &dummy
);
3545 exc
= (MonoObject
*) mono_exception_from_name_msg (mono_get_corlib (),
3546 "System.Runtime.Serialization", "SerializationException",
3547 "Could not serialize unhandled exception.");
3551 g_assert (mono_object_domain (exc
) == domain
);
3553 pa
[0] = domain
->domain
;
3554 pa
[1] = create_unhandled_exception_eventargs (exc
);
3555 mono_runtime_delegate_invoke (delegate
, pa
, &e
);
3557 if (domain
!= current_domain
)
3558 mono_domain_set_internal_with_options (current_domain
, FALSE
);
3562 gchar
*msg
= mono_string_to_utf8_checked (((MonoException
*) e
)->message
, &error
);
3563 if (!mono_error_ok (&error
)) {
3564 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3565 mono_error_cleanup (&error
);
3567 g_warning ("exception inside UnhandledException handler: %s\n", msg
);
3573 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy
= MONO_UNHANDLED_POLICY_CURRENT
;
3576 * mono_runtime_unhandled_exception_policy_set:
3577 * @policy: the new policy
3579 * This is a VM internal routine.
3581 * Sets the runtime policy for handling unhandled exceptions.
3584 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy
) {
3585 runtime_unhandled_exception_policy
= policy
;
3589 * mono_runtime_unhandled_exception_policy_get:
3591 * This is a VM internal routine.
3593 * Gets the runtime policy for handling unhandled exceptions.
3595 MonoRuntimeUnhandledExceptionPolicy
3596 mono_runtime_unhandled_exception_policy_get (void) {
3597 return runtime_unhandled_exception_policy
;
3601 * mono_unhandled_exception:
3602 * @exc: exception thrown
3604 * This is a VM internal routine.
3606 * We call this function when we detect an unhandled exception
3607 * in the default domain.
3609 * It invokes the * UnhandledException event in AppDomain or prints
3610 * a warning to the console
3613 mono_unhandled_exception (MonoObject
*exc
)
3615 MonoDomain
*current_domain
= mono_domain_get ();
3616 MonoDomain
*root_domain
= mono_get_root_domain ();
3617 MonoClassField
*field
;
3618 MonoObject
*current_appdomain_delegate
;
3619 MonoObject
*root_appdomain_delegate
;
3621 field
=mono_class_get_field_from_name(mono_defaults
.appdomain_class
,
3622 "UnhandledException");
3625 if (exc
->vtable
->klass
!= mono_defaults
.threadabortexception_class
) {
3626 gboolean abort_process
= (main_thread
&& (mono_thread_internal_current () == main_thread
->internal_thread
)) ||
3627 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
);
3628 root_appdomain_delegate
= *(MonoObject
**)(((char *)root_domain
->domain
) + field
->offset
);
3629 if (current_domain
!= root_domain
&& (mono_framework_version () >= 2)) {
3630 current_appdomain_delegate
= *(MonoObject
**)(((char *)current_domain
->domain
) + field
->offset
);
3632 current_appdomain_delegate
= NULL
;
3635 /* set exitcode only if we will abort the process */
3637 mono_environment_exitcode_set (1);
3638 if ((current_appdomain_delegate
== NULL
) && (root_appdomain_delegate
== NULL
)) {
3639 mono_print_unhandled_exception (exc
);
3641 if (root_appdomain_delegate
) {
3642 call_unhandled_exception_delegate (root_domain
, root_appdomain_delegate
, exc
);
3644 if (current_appdomain_delegate
) {
3645 call_unhandled_exception_delegate (current_domain
, current_appdomain_delegate
, exc
);
3652 * Launch a new thread to execute a function
3654 * main_func is called back from the thread with main_args as the
3655 * parameter. The callback function is expected to start Main()
3656 * eventually. This function then waits for all managed threads to
3658 * It is not necesseray anymore to execute managed code in a subthread,
3659 * so this function should not be used anymore by default: just
3660 * execute the code and then call mono_thread_manage ().
3663 mono_runtime_exec_managed_code (MonoDomain
*domain
,
3664 MonoMainThreadFunc main_func
,
3667 mono_thread_create (domain
, main_func
, main_args
);
3669 mono_thread_manage ();
3673 * Execute a standard Main() method (args doesn't contain the
3677 mono_runtime_exec_main (MonoMethod
*method
, MonoArray
*args
, MonoObject
**exc
)
3682 MonoCustomAttrInfo
* cinfo
;
3683 gboolean has_stathread_attribute
;
3684 MonoInternalThread
* thread
= mono_thread_internal_current ();
3690 domain
= mono_object_domain (args
);
3691 if (!domain
->entry_assembly
) {
3693 MonoAssembly
*assembly
;
3695 assembly
= method
->klass
->image
->assembly
;
3696 domain
->entry_assembly
= assembly
;
3697 /* Domains created from another domain already have application_base and configuration_file set */
3698 if (domain
->setup
->application_base
== NULL
) {
3699 MONO_OBJECT_SETREF (domain
->setup
, application_base
, mono_string_new (domain
, assembly
->basedir
));
3702 if (domain
->setup
->configuration_file
== NULL
) {
3703 str
= g_strconcat (assembly
->image
->name
, ".config", NULL
);
3704 MONO_OBJECT_SETREF (domain
->setup
, configuration_file
, mono_string_new (domain
, str
));
3706 mono_set_private_bin_path_from_config (domain
);
3710 cinfo
= mono_custom_attrs_from_method (method
);
3712 static MonoClass
*stathread_attribute
= NULL
;
3713 if (!stathread_attribute
)
3714 stathread_attribute
= mono_class_from_name (mono_defaults
.corlib
, "System", "STAThreadAttribute");
3715 has_stathread_attribute
= mono_custom_attrs_has_attr (cinfo
, stathread_attribute
);
3717 mono_custom_attrs_free (cinfo
);
3719 has_stathread_attribute
= FALSE
;
3721 if (has_stathread_attribute
) {
3722 thread
->apartment_state
= ThreadApartmentState_STA
;
3723 } else if (mono_framework_version () == 1) {
3724 thread
->apartment_state
= ThreadApartmentState_Unknown
;
3726 thread
->apartment_state
= ThreadApartmentState_MTA
;
3728 mono_thread_init_apartment_state ();
3730 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN
, 0, 0);
3732 /* FIXME: check signature of method */
3733 if (mono_method_signature (method
)->ret
->type
== MONO_TYPE_I4
) {
3735 res
= mono_runtime_invoke (method
, NULL
, pa
, exc
);
3737 rval
= *(guint32
*)((char *)res
+ sizeof (MonoObject
));
3741 mono_environment_exitcode_set (rval
);
3743 mono_runtime_invoke (method
, NULL
, pa
, exc
);
3747 /* If the return type of Main is void, only
3748 * set the exitcode if an exception was thrown
3749 * (we don't want to blow away an
3750 * explicitly-set exit code)
3753 mono_environment_exitcode_set (rval
);
3757 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED
, (guint64
) (gsize
) rval
, 0);
3763 * mono_install_runtime_invoke:
3764 * @func: Function to install
3766 * This is a VM internal routine
3769 mono_install_runtime_invoke (MonoInvokeFunc func
)
3771 default_mono_runtime_invoke
= func
? func
: dummy_mono_runtime_invoke
;
3776 * mono_runtime_invoke_array:
3777 * @method: method to invoke
3778 * @obJ: object instance
3779 * @params: arguments to the method
3780 * @exc: exception information.
3782 * Invokes the method represented by @method on the object @obj.
3784 * obj is the 'this' pointer, it should be NULL for static
3785 * methods, a MonoObject* for object instances and a pointer to
3786 * the value type for value types.
3788 * The params array contains the arguments to the method with the
3789 * same convention: MonoObject* pointers for object instances and
3790 * pointers to the value type otherwise. The _invoke_array
3791 * variant takes a C# object[] as the params argument (MonoArray
3792 * *params): in this case the value types are boxed inside the
3793 * respective reference representation.
3795 * From unmanaged code you'll usually use the
3796 * mono_runtime_invoke() variant.
3798 * Note that this function doesn't handle virtual methods for
3799 * you, it will exec the exact method you pass: we still need to
3800 * expose a function to lookup the derived class implementation
3801 * of a virtual method (there are examples of this in the code,
3804 * You can pass NULL as the exc argument if you don't want to
3805 * catch exceptions, otherwise, *exc will be set to the exception
3806 * thrown, if any. if an exception is thrown, you can't use the
3807 * MonoObject* result from the function.
3809 * If the method returns a value type, it is boxed in an object
3813 mono_runtime_invoke_array (MonoMethod
*method
, void *obj
, MonoArray
*params
,
3816 MonoMethodSignature
*sig
= mono_method_signature (method
);
3817 gpointer
*pa
= NULL
;
3820 gboolean has_byref_nullables
= FALSE
;
3822 if (NULL
!= params
) {
3823 pa
= alloca (sizeof (gpointer
) * mono_array_length (params
));
3824 for (i
= 0; i
< mono_array_length (params
); i
++) {
3825 MonoType
*t
= sig
->params
[i
];
3831 case MONO_TYPE_BOOLEAN
:
3834 case MONO_TYPE_CHAR
:
3843 case MONO_TYPE_VALUETYPE
:
3844 if (t
->type
== MONO_TYPE_VALUETYPE
&& mono_class_is_nullable (mono_class_from_mono_type (sig
->params
[i
]))) {
3845 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3846 pa
[i
] = mono_array_get (params
, MonoObject
*, i
);
3848 has_byref_nullables
= TRUE
;
3850 /* MS seems to create the objects if a null is passed in */
3851 if (!mono_array_get (params
, MonoObject
*, i
))
3852 mono_array_setref (params
, i
, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig
->params
[i
])));
3856 * We can't pass the unboxed vtype byref to the callee, since
3857 * that would mean the callee would be able to modify boxed
3858 * primitive types. So we (and MS) make a copy of the boxed
3859 * object, pass that to the callee, and replace the original
3860 * boxed object in the arg array with the copy.
3862 MonoObject
*orig
= mono_array_get (params
, MonoObject
*, i
);
3863 MonoObject
*copy
= mono_value_box (mono_domain_get (), orig
->vtable
->klass
, mono_object_unbox (orig
));
3864 mono_array_setref (params
, i
, copy
);
3867 pa
[i
] = mono_object_unbox (mono_array_get (params
, MonoObject
*, i
));
3870 case MONO_TYPE_STRING
:
3871 case MONO_TYPE_OBJECT
:
3872 case MONO_TYPE_CLASS
:
3873 case MONO_TYPE_ARRAY
:
3874 case MONO_TYPE_SZARRAY
:
3876 pa
[i
] = mono_array_addr (params
, MonoObject
*, i
);
3877 // FIXME: I need to check this code path
3879 pa
[i
] = mono_array_get (params
, MonoObject
*, i
);
3881 case MONO_TYPE_GENERICINST
:
3883 t
= &t
->data
.generic_class
->container_class
->this_arg
;
3885 t
= &t
->data
.generic_class
->container_class
->byval_arg
;
3887 case MONO_TYPE_PTR
: {
3890 /* The argument should be an IntPtr */
3891 arg
= mono_array_get (params
, MonoObject
*, i
);
3895 g_assert (arg
->vtable
->klass
== mono_defaults
.int_class
);
3896 pa
[i
] = ((MonoIntPtr
*)arg
)->m_value
;
3901 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig
->params
[i
]->type
);
3906 if (!strcmp (method
->name
, ".ctor") && method
->klass
!= mono_defaults
.string_class
) {
3909 if (mono_class_is_nullable (method
->klass
)) {
3910 /* Need to create a boxed vtype instead */
3916 return mono_value_box (mono_domain_get (), method
->klass
->cast_class
, pa
[0]);
3920 obj
= mono_object_new (mono_domain_get (), method
->klass
);
3921 if (mono_object_class(obj
) == mono_defaults
.transparent_proxy_class
) {
3922 method
= mono_marshal_get_remoting_invoke (method
->slot
== -1 ? method
: method
->klass
->vtable
[method
->slot
]);
3924 if (method
->klass
->valuetype
)
3925 o
= mono_object_unbox (obj
);
3928 } else if (method
->klass
->valuetype
) {
3929 obj
= mono_value_box (mono_domain_get (), method
->klass
, obj
);
3932 mono_runtime_invoke (method
, o
, pa
, exc
);
3935 if (mono_class_is_nullable (method
->klass
)) {
3936 MonoObject
*nullable
;
3938 /* Convert the unboxed vtype into a Nullable structure */
3939 nullable
= mono_object_new (mono_domain_get (), method
->klass
);
3941 mono_nullable_init (mono_object_unbox (nullable
), mono_value_box (mono_domain_get (), method
->klass
->cast_class
, obj
), method
->klass
);
3942 obj
= mono_object_unbox (nullable
);
3945 /* obj must be already unboxed if needed */
3946 res
= mono_runtime_invoke (method
, obj
, pa
, exc
);
3948 if (sig
->ret
->type
== MONO_TYPE_PTR
) {
3949 MonoClass
*pointer_class
;
3950 static MonoMethod
*box_method
;
3952 MonoObject
*box_exc
;
3955 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3956 * convert it to a Pointer object.
3958 pointer_class
= mono_class_from_name_cached (mono_defaults
.corlib
, "System.Reflection", "Pointer");
3960 box_method
= mono_class_get_method_from_name (pointer_class
, "Box", -1);
3962 g_assert (res
->vtable
->klass
== mono_defaults
.int_class
);
3963 box_args
[0] = ((MonoIntPtr
*)res
)->m_value
;
3964 box_args
[1] = mono_type_get_object (mono_domain_get (), sig
->ret
);
3965 res
= mono_runtime_invoke (box_method
, NULL
, box_args
, &box_exc
);
3966 g_assert (!box_exc
);
3969 if (has_byref_nullables
) {
3971 * The runtime invoke wrapper already converted byref nullables back,
3972 * and stored them in pa, we just need to copy them back to the
3975 for (i
= 0; i
< mono_array_length (params
); i
++) {
3976 MonoType
*t
= sig
->params
[i
];
3978 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
3979 mono_array_setref (params
, i
, pa
[i
]);
3988 arith_overflow (void)
3990 mono_raise_exception (mono_get_exception_overflow ());
3994 * mono_object_allocate:
3995 * @size: number of bytes to allocate
3997 * This is a very simplistic routine until we have our GC-aware
4000 * Returns: an allocated object of size @size, or NULL on failure.
4002 static inline void *
4003 mono_object_allocate (size_t size
, MonoVTable
*vtable
)
4006 mono_stats
.new_object_count
++;
4007 ALLOC_OBJECT (o
, vtable
, size
);
4013 * mono_object_allocate_ptrfree:
4014 * @size: number of bytes to allocate
4016 * Note that the memory allocated is not zeroed.
4017 * Returns: an allocated object of size @size, or NULL on failure.
4019 static inline void *
4020 mono_object_allocate_ptrfree (size_t size
, MonoVTable
*vtable
)
4023 mono_stats
.new_object_count
++;
4024 ALLOC_PTRFREE (o
, vtable
, size
);
4028 static inline void *
4029 mono_object_allocate_spec (size_t size
, MonoVTable
*vtable
)
4032 ALLOC_TYPED (o
, size
, vtable
);
4033 mono_stats
.new_object_count
++;
4040 * @klass: the class of the object that we want to create
4042 * Returns: a newly created object whose definition is
4043 * looked up using @klass. This will not invoke any constructors,
4044 * so the consumer of this routine has to invoke any constructors on
4045 * its own to initialize the object.
4047 * It returns NULL on failure.
4050 mono_object_new (MonoDomain
*domain
, MonoClass
*klass
)
4054 MONO_ARCH_SAVE_REGS
;
4055 vtable
= mono_class_vtable (domain
, klass
);
4058 return mono_object_new_specific (vtable
);
4062 * mono_object_new_specific:
4063 * @vtable: the vtable of the object that we want to create
4065 * Returns: A newly created object with class and domain specified
4069 mono_object_new_specific (MonoVTable
*vtable
)
4073 MONO_ARCH_SAVE_REGS
;
4075 /* check for is_com_object for COM Interop */
4076 if (vtable
->remote
|| vtable
->klass
->is_com_object
)
4079 MonoMethod
*im
= vtable
->domain
->create_proxy_for_type_method
;
4082 MonoClass
*klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Activation", "ActivationServices");
4085 mono_class_init (klass
);
4087 im
= mono_class_get_method_from_name (klass
, "CreateProxyForType", 1);
4089 vtable
->domain
->create_proxy_for_type_method
= im
;
4092 pa
[0] = mono_type_get_object (mono_domain_get (), &vtable
->klass
->byval_arg
);
4094 o
= mono_runtime_invoke (im
, NULL
, pa
, NULL
);
4095 if (o
!= NULL
) return o
;
4098 return mono_object_new_alloc_specific (vtable
);
4102 mono_object_new_alloc_specific (MonoVTable
*vtable
)
4106 if (!vtable
->klass
->has_references
) {
4107 o
= mono_object_new_ptrfree (vtable
);
4108 } else if (vtable
->gc_descr
!= GC_NO_DESCRIPTOR
) {
4109 o
= mono_object_allocate_spec (vtable
->klass
->instance_size
, vtable
);
4111 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4112 o
= mono_object_allocate (vtable
->klass
->instance_size
, vtable
);
4114 if (G_UNLIKELY (vtable
->klass
->has_finalize
))
4115 mono_object_register_finalizer (o
);
4117 if (G_UNLIKELY (profile_allocs
))
4118 mono_profiler_allocation (o
, vtable
->klass
);
4123 mono_object_new_fast (MonoVTable
*vtable
)
4126 ALLOC_TYPED (o
, vtable
->klass
->instance_size
, vtable
);
4131 mono_object_new_ptrfree (MonoVTable
*vtable
)
4134 ALLOC_PTRFREE (obj
, vtable
, vtable
->klass
->instance_size
);
4135 #if NEED_TO_ZERO_PTRFREE
4136 /* an inline memset is much faster for the common vcase of small objects
4137 * note we assume the allocated size is a multiple of sizeof (void*).
4139 if (vtable
->klass
->instance_size
< 128) {
4141 end
= (gpointer
*)((char*)obj
+ vtable
->klass
->instance_size
);
4142 p
= (gpointer
*)((char*)obj
+ sizeof (MonoObject
));
4148 memset ((char*)obj
+ sizeof (MonoObject
), 0, vtable
->klass
->instance_size
- sizeof (MonoObject
));
4155 mono_object_new_ptrfree_box (MonoVTable
*vtable
)
4158 ALLOC_PTRFREE (obj
, vtable
, vtable
->klass
->instance_size
);
4159 /* the object will be boxed right away, no need to memzero it */
4164 * mono_class_get_allocation_ftn:
4166 * @for_box: the object will be used for boxing
4167 * @pass_size_in_words:
4169 * Return the allocation function appropriate for the given class.
4173 mono_class_get_allocation_ftn (MonoVTable
*vtable
, gboolean for_box
, gboolean
*pass_size_in_words
)
4175 *pass_size_in_words
= FALSE
;
4177 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS
))
4178 profile_allocs
= FALSE
;
4180 if (vtable
->klass
->has_finalize
|| vtable
->klass
->marshalbyref
|| (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS
))
4181 return mono_object_new_specific
;
4183 if (!vtable
->klass
->has_references
) {
4184 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4186 return mono_object_new_ptrfree_box
;
4187 return mono_object_new_ptrfree
;
4190 if (vtable
->gc_descr
!= GC_NO_DESCRIPTOR
) {
4192 return mono_object_new_fast
;
4195 * FIXME: This is actually slower than mono_object_new_fast, because
4196 * of the overhead of parameter passing.
4199 *pass_size_in_words = TRUE;
4200 #ifdef GC_REDIRECT_TO_LOCAL
4201 return GC_local_gcj_fast_malloc;
4203 return GC_gcj_fast_malloc;
4208 return mono_object_new_specific
;
4212 * mono_object_new_from_token:
4213 * @image: Context where the type_token is hosted
4214 * @token: a token of the type that we want to create
4216 * Returns: A newly created object whose definition is
4217 * looked up using @token in the @image image
4220 mono_object_new_from_token (MonoDomain
*domain
, MonoImage
*image
, guint32 token
)
4224 class = mono_class_get (image
, token
);
4226 return mono_object_new (domain
, class);
4231 * mono_object_clone:
4232 * @obj: the object to clone
4234 * Returns: A newly created object who is a shallow copy of @obj
4237 mono_object_clone (MonoObject
*obj
)
4240 int size
= obj
->vtable
->klass
->instance_size
;
4242 o
= mono_object_allocate (size
, obj
->vtable
);
4244 if (obj
->vtable
->klass
->has_references
) {
4245 mono_gc_wbarrier_object_copy (o
, obj
);
4247 int size
= obj
->vtable
->klass
->instance_size
;
4248 /* do not copy the sync state */
4249 memcpy ((char*)o
+ sizeof (MonoObject
), (char*)obj
+ sizeof (MonoObject
), size
- sizeof (MonoObject
));
4251 if (G_UNLIKELY (profile_allocs
))
4252 mono_profiler_allocation (o
, obj
->vtable
->klass
);
4254 if (obj
->vtable
->klass
->has_finalize
)
4255 mono_object_register_finalizer (o
);
4260 * mono_array_full_copy:
4261 * @src: source array to copy
4262 * @dest: destination array
4264 * Copies the content of one array to another with exactly the same type and size.
4267 mono_array_full_copy (MonoArray
*src
, MonoArray
*dest
)
4269 mono_array_size_t size
;
4270 MonoClass
*klass
= src
->obj
.vtable
->klass
;
4272 MONO_ARCH_SAVE_REGS
;
4274 g_assert (klass
== dest
->obj
.vtable
->klass
);
4276 size
= mono_array_length (src
);
4277 g_assert (size
== mono_array_length (dest
));
4278 size
*= mono_array_element_size (klass
);
4280 if (klass
->element_class
->valuetype
) {
4281 if (klass
->element_class
->has_references
)
4282 mono_value_copy_array (dest
, 0, mono_array_addr_with_size (src
, 0, 0), mono_array_length (src
));
4284 memcpy (&dest
->vector
, &src
->vector
, size
);
4286 mono_array_memcpy_refs (dest
, 0, src
, 0, mono_array_length (src
));
4289 memcpy (&dest
->vector
, &src
->vector
, size
);
4294 * mono_array_clone_in_domain:
4295 * @domain: the domain in which the array will be cloned into
4296 * @array: the array to clone
4298 * This routine returns a copy of the array that is hosted on the
4299 * specified MonoDomain.
4302 mono_array_clone_in_domain (MonoDomain
*domain
, MonoArray
*array
)
4305 mono_array_size_t size
, i
;
4306 mono_array_size_t
*sizes
;
4307 MonoClass
*klass
= array
->obj
.vtable
->klass
;
4309 MONO_ARCH_SAVE_REGS
;
4311 if (array
->bounds
== NULL
) {
4312 size
= mono_array_length (array
);
4313 o
= mono_array_new_full (domain
, klass
, &size
, NULL
);
4315 size
*= mono_array_element_size (klass
);
4317 if (klass
->element_class
->valuetype
) {
4318 if (klass
->element_class
->has_references
)
4319 mono_value_copy_array (o
, 0, mono_array_addr_with_size (array
, 0, 0), mono_array_length (array
));
4321 memcpy (&o
->vector
, &array
->vector
, size
);
4323 mono_array_memcpy_refs (o
, 0, array
, 0, mono_array_length (array
));
4326 memcpy (&o
->vector
, &array
->vector
, size
);
4331 sizes
= alloca (klass
->rank
* sizeof(mono_array_size_t
) * 2);
4332 size
= mono_array_element_size (klass
);
4333 for (i
= 0; i
< klass
->rank
; ++i
) {
4334 sizes
[i
] = array
->bounds
[i
].length
;
4335 size
*= array
->bounds
[i
].length
;
4336 sizes
[i
+ klass
->rank
] = array
->bounds
[i
].lower_bound
;
4338 o
= mono_array_new_full (domain
, klass
, sizes
, sizes
+ klass
->rank
);
4340 if (klass
->element_class
->valuetype
) {
4341 if (klass
->element_class
->has_references
)
4342 mono_value_copy_array (o
, 0, mono_array_addr_with_size (array
, 0, 0), mono_array_length (array
));
4344 memcpy (&o
->vector
, &array
->vector
, size
);
4346 mono_array_memcpy_refs (o
, 0, array
, 0, mono_array_length (array
));
4349 memcpy (&o
->vector
, &array
->vector
, size
);
4357 * @array: the array to clone
4359 * Returns: A newly created array who is a shallow copy of @array
4362 mono_array_clone (MonoArray
*array
)
4364 return mono_array_clone_in_domain (((MonoObject
*)array
)->vtable
->domain
, array
);
4367 /* helper macros to check for overflow when calculating the size of arrays */
4368 #ifdef MONO_BIG_ARRAYS
4369 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4370 #define MYGUINT_MAX MYGUINT64_MAX
4371 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4372 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4373 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4374 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4375 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4377 #define MYGUINT32_MAX 4294967295U
4378 #define MYGUINT_MAX MYGUINT32_MAX
4379 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4380 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4381 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4382 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4383 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4387 mono_array_calc_byte_len (MonoClass
*class, mono_array_size_t len
, mono_array_size_t
*res
)
4389 mono_array_size_t byte_len
;
4391 byte_len
= mono_array_element_size (class);
4392 if (CHECK_MUL_OVERFLOW_UN (byte_len
, len
))
4395 if (CHECK_ADD_OVERFLOW_UN (byte_len
, sizeof (MonoArray
)))
4397 byte_len
+= sizeof (MonoArray
);
4405 * mono_array_new_full:
4406 * @domain: domain where the object is created
4407 * @array_class: array class
4408 * @lengths: lengths for each dimension in the array
4409 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4411 * This routine creates a new array objects with the given dimensions,
4412 * lower bounds and type.
4415 mono_array_new_full (MonoDomain
*domain
, MonoClass
*array_class
, mono_array_size_t
*lengths
, mono_array_size_t
*lower_bounds
)
4417 mono_array_size_t byte_len
, len
, bounds_size
;
4420 MonoArrayBounds
*bounds
;
4424 if (!array_class
->inited
)
4425 mono_class_init (array_class
);
4429 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4430 if (array_class
->rank
== 1 && ((array_class
->byval_arg
.type
== MONO_TYPE_SZARRAY
) || (lower_bounds
&& lower_bounds
[0] == 0))) {
4432 if (len
> MONO_ARRAY_MAX_INDEX
)//MONO_ARRAY_MAX_INDEX
4436 bounds_size
= sizeof (MonoArrayBounds
) * array_class
->rank
;
4438 for (i
= 0; i
< array_class
->rank
; ++i
) {
4439 if (lengths
[i
] > MONO_ARRAY_MAX_INDEX
) //MONO_ARRAY_MAX_INDEX
4441 if (CHECK_MUL_OVERFLOW_UN (len
, lengths
[i
]))
4442 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE
);
4447 if (!mono_array_calc_byte_len (array_class
, len
, &byte_len
))
4448 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE
);
4452 if (CHECK_ADD_OVERFLOW_UN (byte_len
, 3))
4453 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE
);
4454 byte_len
= (byte_len
+ 3) & ~3;
4455 if (CHECK_ADD_OVERFLOW_UN (byte_len
, bounds_size
))
4456 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE
);
4457 byte_len
+= bounds_size
;
4460 * Following three lines almost taken from mono_object_new ():
4461 * they need to be kept in sync.
4463 vtable
= mono_class_vtable_full (domain
, array_class
, TRUE
);
4464 #ifndef HAVE_SGEN_GC
4465 if (!array_class
->has_references
) {
4466 o
= mono_object_allocate_ptrfree (byte_len
, vtable
);
4467 #if NEED_TO_ZERO_PTRFREE
4468 memset ((char*)o
+ sizeof (MonoObject
), 0, byte_len
- sizeof (MonoObject
));
4470 } else if (vtable
->gc_descr
!= GC_NO_DESCRIPTOR
) {
4471 o
= mono_object_allocate_spec (byte_len
, vtable
);
4473 o
= mono_object_allocate (byte_len
, vtable
);
4476 array
= (MonoArray
*)o
;
4477 array
->max_length
= len
;
4480 bounds
= (MonoArrayBounds
*)((char*)array
+ byte_len
- bounds_size
);
4481 array
->bounds
= bounds
;
4485 o
= mono_gc_alloc_array (vtable
, byte_len
, len
, bounds_size
);
4487 o
= mono_gc_alloc_vector (vtable
, byte_len
, len
);
4488 array
= (MonoArray
*)o
;
4489 mono_stats
.new_object_count
++;
4491 bounds
= array
->bounds
;
4495 for (i
= 0; i
< array_class
->rank
; ++i
) {
4496 bounds
[i
].length
= lengths
[i
];
4498 bounds
[i
].lower_bound
= lower_bounds
[i
];
4502 if (G_UNLIKELY (profile_allocs
))
4503 mono_profiler_allocation (o
, array_class
);
4510 * @domain: domain where the object is created
4511 * @eclass: element class
4512 * @n: number of array elements
4514 * This routine creates a new szarray with @n elements of type @eclass.
4517 mono_array_new (MonoDomain
*domain
, MonoClass
*eclass
, mono_array_size_t n
)
4521 MONO_ARCH_SAVE_REGS
;
4523 ac
= mono_array_class_get (eclass
, 1);
4526 return mono_array_new_specific (mono_class_vtable_full (domain
, ac
, TRUE
), n
);
4530 * mono_array_new_specific:
4531 * @vtable: a vtable in the appropriate domain for an initialized class
4532 * @n: number of array elements
4534 * This routine is a fast alternative to mono_array_new() for code which
4535 * can be sure about the domain it operates in.
4538 mono_array_new_specific (MonoVTable
*vtable
, mono_array_size_t n
)
4544 MONO_ARCH_SAVE_REGS
;
4546 if (G_UNLIKELY (n
> MONO_ARRAY_MAX_INDEX
)) {
4551 if (!mono_array_calc_byte_len (vtable
->klass
, n
, &byte_len
)) {
4552 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE
);
4555 #ifndef HAVE_SGEN_GC
4556 if (!vtable
->klass
->has_references
) {
4557 o
= mono_object_allocate_ptrfree (byte_len
, vtable
);
4558 #if NEED_TO_ZERO_PTRFREE
4559 ((MonoArray
*)o
)->bounds
= NULL
;
4560 memset ((char*)o
+ sizeof (MonoObject
), 0, byte_len
- sizeof (MonoObject
));
4562 } else if (vtable
->gc_descr
!= GC_NO_DESCRIPTOR
) {
4563 o
= mono_object_allocate_spec (byte_len
, vtable
);
4565 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4566 o
= mono_object_allocate (byte_len
, vtable
);
4569 ao
= (MonoArray
*)o
;
4572 o
= mono_gc_alloc_vector (vtable
, byte_len
, n
);
4574 mono_stats
.new_object_count
++;
4577 if (G_UNLIKELY (profile_allocs
))
4578 mono_profiler_allocation (o
, vtable
->klass
);
4584 * mono_string_new_utf16:
4585 * @text: a pointer to an utf16 string
4586 * @len: the length of the string
4588 * Returns: A newly created string object which contains @text.
4591 mono_string_new_utf16 (MonoDomain
*domain
, const guint16
*text
, gint32 len
)
4595 s
= mono_string_new_size (domain
, len
);
4596 g_assert (s
!= NULL
);
4598 memcpy (mono_string_chars (s
), text
, len
* 2);
4604 * mono_string_new_size:
4605 * @text: a pointer to an utf16 string
4606 * @len: the length of the string
4608 * Returns: A newly created string object of @len
4611 mono_string_new_size (MonoDomain
*domain
, gint32 len
)
4615 size_t size
= (sizeof (MonoString
) + ((len
+ 1) * 2));
4617 /* overflow ? can't fit it, can't allocate it! */
4619 mono_gc_out_of_memory (-1);
4621 vtable
= mono_class_vtable (domain
, mono_defaults
.string_class
);
4624 s
= mono_object_allocate_ptrfree (size
, vtable
);
4627 #if NEED_TO_ZERO_PTRFREE
4630 if (G_UNLIKELY (profile_allocs
))
4631 mono_profiler_allocation ((MonoObject
*)s
, mono_defaults
.string_class
);
4637 * mono_string_new_len:
4638 * @text: a pointer to an utf8 string
4639 * @length: number of bytes in @text to consider
4641 * Returns: A newly created string object which contains @text.
4644 mono_string_new_len (MonoDomain
*domain
, const char *text
, guint length
)
4646 GError
*error
= NULL
;
4647 MonoString
*o
= NULL
;
4649 glong items_written
;
4651 ut
= g_utf8_to_utf16 (text
, length
, NULL
, &items_written
, &error
);
4654 o
= mono_string_new_utf16 (domain
, ut
, items_written
);
4656 g_error_free (error
);
4665 * @text: a pointer to an utf8 string
4667 * Returns: A newly created string object which contains @text.
4670 mono_string_new (MonoDomain
*domain
, const char *text
)
4672 GError
*error
= NULL
;
4673 MonoString
*o
= NULL
;
4675 glong items_written
;
4680 ut
= g_utf8_to_utf16 (text
, l
, NULL
, &items_written
, &error
);
4683 o
= mono_string_new_utf16 (domain
, ut
, items_written
);
4685 g_error_free (error
);
4688 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4693 MonoString
*o
= NULL
;
4695 if (!g_utf8_validate (text
, -1, &end
))
4698 len
= g_utf8_strlen (text
, -1);
4699 o
= mono_string_new_size (domain
, len
);
4700 str
= mono_string_chars (o
);
4702 while (text
< end
) {
4703 *str
++ = g_utf8_get_char (text
);
4704 text
= g_utf8_next_char (text
);
4711 * mono_string_new_wrapper:
4712 * @text: pointer to utf8 characters.
4714 * Helper function to create a string object from @text in the current domain.
4717 mono_string_new_wrapper (const char *text
)
4719 MonoDomain
*domain
= mono_domain_get ();
4721 MONO_ARCH_SAVE_REGS
;
4724 return mono_string_new (domain
, text
);
4731 * @class: the class of the value
4732 * @value: a pointer to the unboxed data
4734 * Returns: A newly created object which contains @value.
4737 mono_value_box (MonoDomain
*domain
, MonoClass
*class, gpointer value
)
4743 g_assert (class->valuetype
);
4744 if (mono_class_is_nullable (class))
4745 return mono_nullable_box (value
, class);
4747 vtable
= mono_class_vtable (domain
, class);
4750 size
= mono_class_instance_size (class);
4751 res
= mono_object_new_alloc_specific (vtable
);
4752 if (G_UNLIKELY (profile_allocs
))
4753 mono_profiler_allocation (res
, class);
4755 size
= size
- sizeof (MonoObject
);
4758 g_assert (size
== mono_class_value_size (class, NULL
));
4759 mono_gc_wbarrier_value_copy ((char *)res
+ sizeof (MonoObject
), value
, 1, class);
4761 #if NO_UNALIGNED_ACCESS
4762 memcpy ((char *)res
+ sizeof (MonoObject
), value
, size
);
4766 *((guint8
*) res
+ sizeof (MonoObject
)) = *(guint8
*) value
;
4769 *(guint16
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint16
*) value
;
4772 *(guint32
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint32
*) value
;
4775 *(guint64
*)((guint8
*) res
+ sizeof (MonoObject
)) = *(guint64
*) value
;
4778 memcpy ((char *)res
+ sizeof (MonoObject
), value
, size
);
4782 if (class->has_finalize
)
4783 mono_object_register_finalizer (res
);
4789 * @dest: destination pointer
4790 * @src: source pointer
4791 * @klass: a valuetype class
4793 * Copy a valuetype from @src to @dest. This function must be used
4794 * when @klass contains references fields.
4797 mono_value_copy (gpointer dest
, gpointer src
, MonoClass
*klass
)
4799 mono_gc_wbarrier_value_copy (dest
, src
, 1, klass
);
4803 * mono_value_copy_array:
4804 * @dest: destination array
4805 * @dest_idx: index in the @dest array
4806 * @src: source pointer
4807 * @count: number of items
4809 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4810 * This function must be used when @klass contains references fields.
4811 * Overlap is handled.
4814 mono_value_copy_array (MonoArray
*dest
, int dest_idx
, gpointer src
, int count
)
4816 int size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
4817 char *d
= mono_array_addr_with_size (dest
, size
, dest_idx
);
4818 g_assert (size
== mono_class_value_size (mono_object_class (dest
)->element_class
, NULL
));
4819 mono_gc_wbarrier_value_copy (d
, src
, count
, mono_object_class (dest
)->element_class
);
4823 * mono_object_get_domain:
4824 * @obj: object to query
4826 * Returns: the MonoDomain where the object is hosted
4829 mono_object_get_domain (MonoObject
*obj
)
4831 return mono_object_domain (obj
);
4835 * mono_object_get_class:
4836 * @obj: object to query
4838 * Returns: the MonOClass of the object.
4841 mono_object_get_class (MonoObject
*obj
)
4843 return mono_object_class (obj
);
4846 * mono_object_get_size:
4847 * @o: object to query
4849 * Returns: the size, in bytes, of @o
4852 mono_object_get_size (MonoObject
* o
)
4854 MonoClass
* klass
= mono_object_class (o
);
4855 if (klass
== mono_defaults
.string_class
) {
4856 return sizeof (MonoString
) + 2 * mono_string_length ((MonoString
*) o
) + 2;
4857 } else if (o
->vtable
->rank
) {
4858 MonoArray
*array
= (MonoArray
*)o
;
4859 size_t size
= sizeof (MonoArray
) + mono_array_element_size (klass
) * mono_array_length (array
);
4860 if (array
->bounds
) {
4863 size
+= sizeof (MonoArrayBounds
) * o
->vtable
->rank
;
4867 return mono_class_instance_size (klass
);
4872 * mono_object_unbox:
4873 * @obj: object to unbox
4875 * Returns: a pointer to the start of the valuetype boxed in this
4878 * This method will assert if the object passed is not a valuetype.
4881 mono_object_unbox (MonoObject
*obj
)
4883 /* add assert for valuetypes? */
4884 g_assert (obj
->vtable
->klass
->valuetype
);
4885 return ((char*)obj
) + sizeof (MonoObject
);
4889 * mono_object_isinst:
4891 * @klass: a pointer to a class
4893 * Returns: @obj if @obj is derived from @klass
4896 mono_object_isinst (MonoObject
*obj
, MonoClass
*klass
)
4899 mono_class_init (klass
);
4901 if (klass
->marshalbyref
|| (klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
))
4902 return mono_object_isinst_mbyref (obj
, klass
);
4907 return mono_class_is_assignable_from (klass
, obj
->vtable
->klass
) ? obj
: NULL
;
4911 mono_object_isinst_mbyref (MonoObject
*obj
, MonoClass
*klass
)
4920 if (klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
4921 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt
, klass
->interface_id
)) {
4925 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
4926 if (mono_class_has_variant_generic_params (klass
) && mono_class_is_assignable_from (klass
, obj
->vtable
->klass
))
4929 MonoClass
*oklass
= vt
->klass
;
4930 if ((oklass
== mono_defaults
.transparent_proxy_class
))
4931 oklass
= ((MonoTransparentProxy
*)obj
)->remote_class
->proxy_class
;
4933 if ((oklass
->idepth
>= klass
->idepth
) && (oklass
->supertypes
[klass
->idepth
- 1] == klass
))
4937 if (vt
->klass
== mono_defaults
.transparent_proxy_class
&& ((MonoTransparentProxy
*)obj
)->custom_type_info
)
4939 MonoDomain
*domain
= mono_domain_get ();
4941 MonoObject
*rp
= (MonoObject
*)((MonoTransparentProxy
*)obj
)->rp
;
4942 MonoClass
*rpklass
= mono_defaults
.iremotingtypeinfo_class
;
4943 MonoMethod
*im
= NULL
;
4946 im
= mono_class_get_method_from_name (rpklass
, "CanCastTo", -1);
4947 im
= mono_object_get_virtual_method (rp
, im
);
4950 pa
[0] = mono_type_get_object (domain
, &klass
->byval_arg
);
4953 res
= mono_runtime_invoke (im
, rp
, pa
, NULL
);
4955 if (*(MonoBoolean
*) mono_object_unbox(res
)) {
4956 /* Update the vtable of the remote type, so it can safely cast to this new type */
4957 mono_upgrade_remote_class (domain
, obj
, klass
);
4966 * mono_object_castclass_mbyref:
4968 * @klass: a pointer to a class
4970 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4973 mono_object_castclass_mbyref (MonoObject
*obj
, MonoClass
*klass
)
4975 if (!obj
) return NULL
;
4976 if (mono_object_isinst_mbyref (obj
, klass
)) return obj
;
4978 mono_raise_exception (mono_exception_from_name (mono_defaults
.corlib
,
4980 "InvalidCastException"));
4985 MonoDomain
*orig_domain
;
4991 str_lookup (MonoDomain
*domain
, gpointer user_data
)
4993 LDStrInfo
*info
= user_data
;
4994 if (info
->res
|| domain
== info
->orig_domain
)
4996 info
->res
= mono_g_hash_table_lookup (domain
->ldstr_table
, info
->ins
);
5002 mono_string_get_pinned (MonoString
*str
)
5006 size
= sizeof (MonoString
) + 2 * (mono_string_length (str
) + 1);
5007 news
= mono_gc_alloc_pinned_obj (((MonoObject
*)str
)->vtable
, size
);
5008 memcpy (mono_string_chars (news
), mono_string_chars (str
), mono_string_length (str
) * 2);
5009 news
->length
= mono_string_length (str
);
5014 #define mono_string_get_pinned(str) (str)
5018 mono_string_is_interned_lookup (MonoString
*str
, int insert
)
5020 MonoGHashTable
*ldstr_table
;
5024 domain
= ((MonoObject
*)str
)->vtable
->domain
;
5025 ldstr_table
= domain
->ldstr_table
;
5027 if ((res
= mono_g_hash_table_lookup (ldstr_table
, str
))) {
5032 str
= mono_string_get_pinned (str
);
5033 mono_g_hash_table_insert (ldstr_table
, str
, str
);
5037 LDStrInfo ldstr_info
;
5038 ldstr_info
.orig_domain
= domain
;
5039 ldstr_info
.ins
= str
;
5040 ldstr_info
.res
= NULL
;
5042 mono_domain_foreach (str_lookup
, &ldstr_info
);
5043 if (ldstr_info
.res
) {
5045 * the string was already interned in some other domain:
5046 * intern it in the current one as well.
5048 mono_g_hash_table_insert (ldstr_table
, str
, str
);
5058 * mono_string_is_interned:
5059 * @o: String to probe
5061 * Returns whether the string has been interned.
5064 mono_string_is_interned (MonoString
*o
)
5066 return mono_string_is_interned_lookup (o
, FALSE
);
5070 * mono_string_intern:
5071 * @o: String to intern
5073 * Interns the string passed.
5074 * Returns: The interned string.
5077 mono_string_intern (MonoString
*str
)
5079 return mono_string_is_interned_lookup (str
, TRUE
);
5084 * @domain: the domain where the string will be used.
5085 * @image: a metadata context
5086 * @idx: index into the user string table.
5088 * Implementation for the ldstr opcode.
5089 * Returns: a loaded string from the @image/@idx combination.
5092 mono_ldstr (MonoDomain
*domain
, MonoImage
*image
, guint32 idx
)
5094 MONO_ARCH_SAVE_REGS
;
5096 if (image
->dynamic
) {
5097 MonoString
*str
= mono_lookup_dynamic_token (image
, MONO_TOKEN_STRING
| idx
, NULL
);
5098 if (mono_profiler_events
& MONO_PROFILE_STRING_ALLOC
)
5099 mono_profiler_string_allocation (domain
, str
);
5102 if (!mono_verifier_verify_string_signature (image
, idx
, NULL
))
5103 return NULL
; /*FIXME we should probably be raising an exception here*/
5104 return mono_ldstr_metadata_sig (domain
, mono_metadata_user_string (image
, idx
));
5109 * mono_ldstr_metadata_sig
5110 * @domain: the domain for the string
5111 * @sig: the signature of a metadata string
5113 * Returns: a MonoString for a string stored in the metadata
5116 mono_ldstr_metadata_sig (MonoDomain
*domain
, const char* sig
)
5118 const char *str
= sig
;
5119 MonoString
*o
, *interned
;
5122 len2
= mono_metadata_decode_blob_size (str
, &str
);
5125 o
= mono_string_new_utf16 (domain
, (guint16
*)str
, len2
);
5126 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5129 guint16
*p2
= (guint16
*)mono_string_chars (o
);
5130 for (i
= 0; i
< len2
; ++i
) {
5131 *p2
= GUINT16_FROM_LE (*p2
);
5137 if ((interned
= mono_g_hash_table_lookup (domain
->ldstr_table
, o
))) {
5139 /* o will get garbage collected */
5143 o
= mono_string_get_pinned (o
);
5144 mono_g_hash_table_insert (domain
->ldstr_table
, o
, o
);
5147 if (mono_profiler_events
& MONO_PROFILE_STRING_ALLOC
)
5148 mono_profiler_string_allocation (domain
, o
);
5154 * mono_string_to_utf8:
5155 * @s: a System.String
5157 * Return the UTF8 representation for @s.
5158 * the resulting buffer nedds to be freed with g_free().
5160 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5163 mono_string_to_utf8 (MonoString
*s
)
5166 char *result
= mono_string_to_utf8_checked (s
, &error
);
5168 if (!mono_error_ok (&error
))
5169 mono_error_raise_exception (&error
);
5174 mono_string_to_utf8_checked (MonoString
*s
, MonoError
*error
)
5178 GError
*gerror
= NULL
;
5180 mono_error_init (error
);
5186 return g_strdup ("");
5188 as
= g_utf16_to_utf8 (mono_string_chars (s
), s
->length
, NULL
, &written
, &gerror
);
5190 mono_error_set_argument (error
, "string", "%s", gerror
->message
);
5191 g_error_free (gerror
);
5194 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5195 if (s
->length
> written
) {
5196 /* allocate the total length and copy the part of the string that has been converted */
5197 char *as2
= g_malloc0 (s
->length
);
5198 memcpy (as2
, as
, written
);
5207 * mono_string_to_utf16:
5210 * Return an null-terminated array of the utf-16 chars
5211 * contained in @s. The result must be freed with g_free().
5212 * This is a temporary helper until our string implementation
5213 * is reworked to always include the null terminating char.
5216 mono_string_to_utf16 (MonoString
*s
)
5223 as
= g_malloc ((s
->length
* 2) + 2);
5224 as
[(s
->length
* 2)] = '\0';
5225 as
[(s
->length
* 2) + 1] = '\0';
5228 return (gunichar2
*)(as
);
5231 memcpy (as
, mono_string_chars(s
), s
->length
* 2);
5232 return (gunichar2
*)(as
);
5236 * mono_string_from_utf16:
5237 * @data: the UTF16 string (LPWSTR) to convert
5239 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5241 * Returns: a MonoString.
5244 mono_string_from_utf16 (gunichar2
*data
)
5246 MonoDomain
*domain
= mono_domain_get ();
5252 while (data
[len
]) len
++;
5254 return mono_string_new_utf16 (domain
, data
, len
);
5259 mono_string_to_utf8_internal (MonoMemPool
*mp
, MonoImage
*image
, MonoString
*s
, MonoError
*error
)
5265 r
= mono_string_to_utf8_checked (s
, error
);
5266 if (!mono_error_ok (error
))
5272 len
= strlen (r
) + 1;
5274 mp_s
= mono_mempool_alloc (mp
, len
);
5276 mp_s
= mono_image_alloc (image
, len
);
5278 memcpy (mp_s
, r
, len
);
5286 * mono_string_to_utf8_image:
5287 * @s: a System.String
5289 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5292 mono_string_to_utf8_image (MonoImage
*image
, MonoString
*s
, MonoError
*error
)
5294 return mono_string_to_utf8_internal (NULL
, image
, s
, error
);
5298 * mono_string_to_utf8_mp:
5299 * @s: a System.String
5301 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5304 mono_string_to_utf8_mp (MonoMemPool
*mp
, MonoString
*s
, MonoError
*error
)
5306 return mono_string_to_utf8_internal (mp
, NULL
, s
, error
);
5310 default_ex_handler (MonoException
*ex
)
5312 MonoObject
*o
= (MonoObject
*)ex
;
5313 g_error ("Exception %s.%s raised in C code", o
->vtable
->klass
->name_space
, o
->vtable
->klass
->name
);
5317 static MonoExceptionFunc ex_handler
= default_ex_handler
;
5320 * mono_install_handler:
5321 * @func: exception handler
5323 * This is an internal JIT routine used to install the handler for exceptions
5327 mono_install_handler (MonoExceptionFunc func
)
5329 ex_handler
= func
? func
: default_ex_handler
;
5333 * mono_raise_exception:
5334 * @ex: exception object
5336 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5339 mono_raise_exception (MonoException
*ex
)
5342 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5343 * that will cause gcc to omit the function epilog, causing problems when
5344 * the JIT tries to walk the stack, since the return address on the stack
5345 * will point into the next function in the executable, not this one.
5348 if (((MonoObject
*)ex
)->vtable
->klass
== mono_defaults
.threadabortexception_class
) {
5349 MonoInternalThread
*thread
= mono_thread_internal_current ();
5350 g_assert (ex
->object
.vtable
->domain
== mono_domain_get ());
5351 MONO_OBJECT_SETREF (thread
, abort_exc
, ex
);
5358 * mono_wait_handle_new:
5359 * @domain: Domain where the object will be created
5360 * @handle: Handle for the wait handle
5362 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5365 mono_wait_handle_new (MonoDomain
*domain
, HANDLE handle
)
5367 MonoWaitHandle
*res
;
5368 gpointer params
[1];
5369 static MonoMethod
*handle_set
;
5371 res
= (MonoWaitHandle
*)mono_object_new (domain
, mono_defaults
.manualresetevent_class
);
5373 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5375 handle_set
= mono_class_get_property_from_name (mono_defaults
.manualresetevent_class
, "Handle")->set
;
5377 params
[0] = &handle
;
5378 mono_runtime_invoke (handle_set
, res
, params
, NULL
);
5384 mono_wait_handle_get_handle (MonoWaitHandle
*handle
)
5386 static MonoClassField
*f_os_handle
;
5387 static MonoClassField
*f_safe_handle
;
5389 if (!f_os_handle
&& !f_safe_handle
) {
5390 f_os_handle
= mono_class_get_field_from_name (mono_defaults
.manualresetevent_class
, "os_handle");
5391 f_safe_handle
= mono_class_get_field_from_name (mono_defaults
.manualresetevent_class
, "safe_wait_handle");
5396 mono_field_get_value ((MonoObject
*)handle
, f_os_handle
, &retval
);
5400 mono_field_get_value ((MonoObject
*)handle
, f_safe_handle
, &sh
);
5407 mono_runtime_capture_context (MonoDomain
*domain
)
5409 RuntimeInvokeFunction runtime_invoke
;
5411 if (!domain
->capture_context_runtime_invoke
|| !domain
->capture_context_method
) {
5412 MonoMethod
*method
= mono_get_context_capture_method ();
5413 MonoMethod
*wrapper
;
5416 wrapper
= mono_marshal_get_runtime_invoke (method
, FALSE
);
5417 domain
->capture_context_runtime_invoke
= mono_compile_method (wrapper
);
5418 domain
->capture_context_method
= mono_compile_method (method
);
5421 runtime_invoke
= domain
->capture_context_runtime_invoke
;
5423 return runtime_invoke (NULL
, NULL
, NULL
, domain
->capture_context_method
);
5426 * mono_async_result_new:
5427 * @domain:domain where the object will be created.
5428 * @handle: wait handle.
5429 * @state: state to pass to AsyncResult
5430 * @data: C closure data.
5432 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5433 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5437 mono_async_result_new (MonoDomain
*domain
, HANDLE handle
, MonoObject
*state
, gpointer data
, MonoObject
*object_data
)
5439 MonoAsyncResult
*res
= (MonoAsyncResult
*)mono_object_new (domain
, mono_defaults
.asyncresult_class
);
5440 MonoObject
*context
= mono_runtime_capture_context (domain
);
5441 /* we must capture the execution context from the original thread */
5443 MONO_OBJECT_SETREF (res
, execution_context
, context
);
5444 /* note: result may be null if the flow is suppressed */
5448 MONO_OBJECT_SETREF (res
, object_data
, object_data
);
5449 MONO_OBJECT_SETREF (res
, async_state
, state
);
5451 MONO_OBJECT_SETREF (res
, handle
, (MonoObject
*) mono_wait_handle_new (domain
, handle
));
5453 res
->sync_completed
= FALSE
;
5454 res
->completed
= FALSE
;
5460 mono_message_init (MonoDomain
*domain
,
5461 MonoMethodMessage
*this,
5462 MonoReflectionMethod
*method
,
5463 MonoArray
*out_args
)
5465 static MonoClass
*object_array_klass
;
5466 static MonoClass
*byte_array_klass
;
5467 static MonoClass
*string_array_klass
;
5468 MonoMethodSignature
*sig
= mono_method_signature (method
->method
);
5474 if (!object_array_klass
) {
5477 klass
= mono_array_class_get (mono_defaults
.object_class
, 1);
5480 mono_memory_barrier ();
5481 object_array_klass
= klass
;
5483 klass
= mono_array_class_get (mono_defaults
.byte_class
, 1);
5486 mono_memory_barrier ();
5487 byte_array_klass
= klass
;
5489 klass
= mono_array_class_get (mono_defaults
.string_class
, 1);
5492 mono_memory_barrier ();
5493 string_array_klass
= klass
;
5496 MONO_OBJECT_SETREF (this, method
, method
);
5498 MONO_OBJECT_SETREF (this, args
, mono_array_new_specific (mono_class_vtable (domain
, object_array_klass
), sig
->param_count
));
5499 MONO_OBJECT_SETREF (this, arg_types
, mono_array_new_specific (mono_class_vtable (domain
, byte_array_klass
), sig
->param_count
));
5500 this->async_result
= NULL
;
5501 this->call_type
= CallType_Sync
;
5503 names
= g_new (char *, sig
->param_count
);
5504 mono_method_get_param_names (method
->method
, (const char **) names
);
5505 MONO_OBJECT_SETREF (this, names
, mono_array_new_specific (mono_class_vtable (domain
, string_array_klass
), sig
->param_count
));
5507 for (i
= 0; i
< sig
->param_count
; i
++) {
5508 name
= mono_string_new (domain
, names
[i
]);
5509 mono_array_setref (this->names
, i
, name
);
5513 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
5514 if (sig
->params
[i
]->byref
) {
5516 MonoObject
* arg
= mono_array_get (out_args
, gpointer
, j
);
5517 mono_array_setref (this->args
, i
, arg
);
5521 if (!(sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
))
5525 if (sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
)
5528 mono_array_set (this->arg_types
, guint8
, i
, arg_type
);
5533 * mono_remoting_invoke:
5534 * @real_proxy: pointer to a RealProxy object
5535 * @msg: The MonoMethodMessage to execute
5536 * @exc: used to store exceptions
5537 * @out_args: used to store output arguments
5539 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5540 * IMessage interface and it is not trivial to extract results from there. So
5541 * we call an helper method PrivateInvoke instead of calling
5542 * RealProxy::Invoke() directly.
5544 * Returns: the result object.
5547 mono_remoting_invoke (MonoObject
*real_proxy
, MonoMethodMessage
*msg
,
5548 MonoObject
**exc
, MonoArray
**out_args
)
5550 MonoMethod
*im
= real_proxy
->vtable
->domain
->private_invoke_method
;
5553 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5556 im
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "PrivateInvoke", 4);
5558 real_proxy
->vtable
->domain
->private_invoke_method
= im
;
5561 pa
[0] = real_proxy
;
5566 return mono_runtime_invoke (im
, NULL
, pa
, exc
);
5570 mono_message_invoke (MonoObject
*target
, MonoMethodMessage
*msg
,
5571 MonoObject
**exc
, MonoArray
**out_args
)
5573 static MonoClass
*object_array_klass
;
5576 MonoMethodSignature
*sig
;
5578 int i
, j
, outarg_count
= 0;
5580 if (target
&& target
->vtable
->klass
== mono_defaults
.transparent_proxy_class
) {
5582 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)target
;
5583 if (tp
->remote_class
->proxy_class
->contextbound
&& tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
5584 target
= tp
->rp
->unwrapped_server
;
5586 return mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, exc
, out_args
);
5590 domain
= mono_domain_get ();
5591 method
= msg
->method
->method
;
5592 sig
= mono_method_signature (method
);
5594 for (i
= 0; i
< sig
->param_count
; i
++) {
5595 if (sig
->params
[i
]->byref
)
5599 if (!object_array_klass
) {
5602 klass
= mono_array_class_get (mono_defaults
.object_class
, 1);
5605 mono_memory_barrier ();
5606 object_array_klass
= klass
;
5609 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5610 *out_args
= mono_array_new_specific (mono_class_vtable (domain
, object_array_klass
), outarg_count
);
5613 ret
= mono_runtime_invoke_array (method
, method
->klass
->valuetype
? mono_object_unbox (target
): target
, msg
->args
, exc
);
5615 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
5616 if (sig
->params
[i
]->byref
) {
5618 arg
= mono_array_get (msg
->args
, gpointer
, i
);
5619 mono_array_setref (*out_args
, j
, arg
);
5628 * mono_print_unhandled_exception:
5629 * @exc: The exception
5631 * Prints the unhandled exception.
5634 mono_print_unhandled_exception (MonoObject
*exc
)
5637 char *message
= (char *) "";
5641 gboolean free_message
= FALSE
;
5643 if (mono_object_isinst (exc
, mono_defaults
.exception_class
)) {
5644 klass
= exc
->vtable
->klass
;
5646 while (klass
&& method
== NULL
) {
5647 method
= mono_class_get_method_from_name_flags (klass
, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL
| METHOD_ATTRIBUTE_PUBLIC
);
5649 klass
= klass
->parent
;
5654 str
= (MonoString
*) mono_runtime_invoke (method
, exc
, NULL
, NULL
);
5656 message
= mono_string_to_utf8_checked (str
, &error
);
5657 if (!mono_error_ok (&error
)) {
5658 mono_error_cleanup (&error
);
5659 message
= (char *)"";
5661 free_message
= TRUE
;
5667 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5668 * exc->vtable->klass->name, message);
5670 g_printerr ("\nUnhandled Exception: %s\n", message
);
5677 * mono_delegate_ctor:
5678 * @this: pointer to an uninitialized delegate object
5679 * @target: target object
5680 * @addr: pointer to native code
5683 * Initialize a delegate and sets a specific method, not the one
5684 * associated with addr. This is useful when sharing generic code.
5685 * In that case addr will most probably not be associated with the
5686 * correct instantiation of the method.
5689 mono_delegate_ctor_with_method (MonoObject
*this, MonoObject
*target
, gpointer addr
, MonoMethod
*method
)
5691 MonoDelegate
*delegate
= (MonoDelegate
*)this;
5698 delegate
->method
= method
;
5700 class = this->vtable
->klass
;
5701 mono_stats
.delegate_creations
++;
5703 if (target
&& target
->vtable
->klass
== mono_defaults
.transparent_proxy_class
) {
5705 method
= mono_marshal_get_remoting_invoke (method
);
5706 delegate
->method_ptr
= mono_compile_method (method
);
5707 MONO_OBJECT_SETREF (delegate
, target
, target
);
5708 } else if (method
&& mono_method_signature (method
)->hasthis
&& method
->klass
->valuetype
) {
5709 method
= mono_marshal_get_unbox_wrapper (method
);
5710 delegate
->method_ptr
= mono_compile_method (method
);
5711 MONO_OBJECT_SETREF (delegate
, target
, target
);
5713 delegate
->method_ptr
= addr
;
5714 MONO_OBJECT_SETREF (delegate
, target
, target
);
5717 delegate
->invoke_impl
= arch_create_delegate_trampoline (delegate
->object
.vtable
->klass
);
5721 * mono_delegate_ctor:
5722 * @this: pointer to an uninitialized delegate object
5723 * @target: target object
5724 * @addr: pointer to native code
5726 * This is used to initialize a delegate.
5729 mono_delegate_ctor (MonoObject
*this, MonoObject
*target
, gpointer addr
)
5731 MonoDomain
*domain
= mono_domain_get ();
5733 MonoMethod
*method
= NULL
;
5737 if ((ji
= mono_jit_info_table_find (domain
, mono_get_addr_from_ftnptr (addr
)))) {
5738 method
= ji
->method
;
5739 g_assert (!method
->klass
->generic_container
);
5742 mono_delegate_ctor_with_method (this, target
, addr
, method
);
5746 * mono_method_call_message_new:
5747 * @method: method to encapsulate
5748 * @params: parameters to the method
5749 * @invoke: optional, delegate invoke.
5750 * @cb: async callback delegate.
5751 * @state: state passed to the async callback.
5753 * Translates arguments pointers into a MonoMethodMessage.
5756 mono_method_call_message_new (MonoMethod
*method
, gpointer
*params
, MonoMethod
*invoke
,
5757 MonoDelegate
**cb
, MonoObject
**state
)
5759 MonoDomain
*domain
= mono_domain_get ();
5760 MonoMethodSignature
*sig
= mono_method_signature (method
);
5761 MonoMethodMessage
*msg
;
5764 msg
= (MonoMethodMessage
*)mono_object_new (domain
, mono_defaults
.mono_method_message_class
);
5767 mono_message_init (domain
, msg
, mono_method_get_object (domain
, invoke
, NULL
), NULL
);
5768 count
= sig
->param_count
- 2;
5770 mono_message_init (domain
, msg
, mono_method_get_object (domain
, method
, NULL
), NULL
);
5771 count
= sig
->param_count
;
5774 for (i
= 0; i
< count
; i
++) {
5779 if (sig
->params
[i
]->byref
)
5780 vpos
= *((gpointer
*)params
[i
]);
5784 type
= sig
->params
[i
]->type
;
5785 class = mono_class_from_mono_type (sig
->params
[i
]);
5787 if (class->valuetype
)
5788 arg
= mono_value_box (domain
, class, vpos
);
5790 arg
= *((MonoObject
**)vpos
);
5792 mono_array_setref (msg
->args
, i
, arg
);
5795 if (cb
!= NULL
&& state
!= NULL
) {
5796 *cb
= *((MonoDelegate
**)params
[i
]);
5798 *state
= *((MonoObject
**)params
[i
]);
5805 * mono_method_return_message_restore:
5807 * Restore results from message based processing back to arguments pointers
5810 mono_method_return_message_restore (MonoMethod
*method
, gpointer
*params
, MonoArray
*out_args
)
5812 MonoMethodSignature
*sig
= mono_method_signature (method
);
5813 int i
, j
, type
, size
, out_len
;
5815 if (out_args
== NULL
)
5817 out_len
= mono_array_length (out_args
);
5821 for (i
= 0, j
= 0; i
< sig
->param_count
; i
++) {
5822 MonoType
*pt
= sig
->params
[i
];
5827 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5829 arg
= mono_array_get (out_args
, gpointer
, j
);
5832 g_assert (type
!= MONO_TYPE_VOID
);
5834 if (MONO_TYPE_IS_REFERENCE (pt
)) {
5835 mono_gc_wbarrier_generic_store (*((MonoObject
***)params
[i
]), (MonoObject
*)arg
);
5838 MonoClass
*class = ((MonoObject
*)arg
)->vtable
->klass
;
5839 size
= mono_class_value_size (class, NULL
);
5840 if (class->has_references
)
5841 mono_gc_wbarrier_value_copy (*((gpointer
*)params
[i
]), arg
+ sizeof (MonoObject
), 1, class);
5843 memcpy (*((gpointer
*)params
[i
]), arg
+ sizeof (MonoObject
), size
);
5845 size
= mono_class_value_size (mono_class_from_mono_type (pt
), NULL
);
5846 memset (*((gpointer
*)params
[i
]), 0, size
);
5856 * mono_load_remote_field:
5857 * @this: pointer to an object
5858 * @klass: klass of the object containing @field
5859 * @field: the field to load
5860 * @res: a storage to store the result
5862 * This method is called by the runtime on attempts to load fields of
5863 * transparent proxy objects. @this points to such TP, @klass is the class of
5864 * the object containing @field. @res is a storage location which can be
5865 * used to store the result.
5867 * Returns: an address pointing to the value of field.
5870 mono_load_remote_field (MonoObject
*this, MonoClass
*klass
, MonoClassField
*field
, gpointer
*res
)
5872 static MonoMethod
*getter
= NULL
;
5873 MonoDomain
*domain
= mono_domain_get ();
5874 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this;
5875 MonoClass
*field_class
;
5876 MonoMethodMessage
*msg
;
5877 MonoArray
*out_args
;
5881 g_assert (this->vtable
->klass
== mono_defaults
.transparent_proxy_class
);
5882 g_assert (res
!= NULL
);
5884 if (tp
->remote_class
->proxy_class
->contextbound
&& tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
5885 mono_field_get_value (tp
->rp
->unwrapped_server
, field
, res
);
5890 getter
= mono_class_get_method_from_name (mono_defaults
.object_class
, "FieldGetter", -1);
5894 field_class
= mono_class_from_mono_type (field
->type
);
5896 msg
= (MonoMethodMessage
*)mono_object_new (domain
, mono_defaults
.mono_method_message_class
);
5897 out_args
= mono_array_new (domain
, mono_defaults
.object_class
, 1);
5898 mono_message_init (domain
, msg
, mono_method_get_object (domain
, getter
, NULL
), out_args
);
5900 full_name
= mono_type_get_full_name (klass
);
5901 mono_array_setref (msg
->args
, 0, mono_string_new (domain
, full_name
));
5902 mono_array_setref (msg
->args
, 1, mono_string_new (domain
, mono_field_get_name (field
)));
5905 mono_remoting_invoke ((MonoObject
*)(tp
->rp
), msg
, &exc
, &out_args
);
5907 if (exc
) mono_raise_exception ((MonoException
*)exc
);
5909 if (mono_array_length (out_args
) == 0)
5912 *res
= mono_array_get (out_args
, MonoObject
*, 0); /* FIXME: GC write abrrier for res */
5914 if (field_class
->valuetype
) {
5915 return ((char *)*res
) + sizeof (MonoObject
);
5921 * mono_load_remote_field_new:
5926 * Missing documentation.
5929 mono_load_remote_field_new (MonoObject
*this, MonoClass
*klass
, MonoClassField
*field
)
5931 static MonoMethod
*getter
= NULL
;
5932 MonoDomain
*domain
= mono_domain_get ();
5933 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this;
5934 MonoClass
*field_class
;
5935 MonoMethodMessage
*msg
;
5936 MonoArray
*out_args
;
5937 MonoObject
*exc
, *res
;
5940 g_assert (this->vtable
->klass
== mono_defaults
.transparent_proxy_class
);
5942 field_class
= mono_class_from_mono_type (field
->type
);
5944 if (tp
->remote_class
->proxy_class
->contextbound
&& tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
5946 if (field_class
->valuetype
) {
5947 res
= mono_object_new (domain
, field_class
);
5948 val
= ((gchar
*) res
) + sizeof (MonoObject
);
5952 mono_field_get_value (tp
->rp
->unwrapped_server
, field
, val
);
5957 getter
= mono_class_get_method_from_name (mono_defaults
.object_class
, "FieldGetter", -1);
5961 msg
= (MonoMethodMessage
*)mono_object_new (domain
, mono_defaults
.mono_method_message_class
);
5962 out_args
= mono_array_new (domain
, mono_defaults
.object_class
, 1);
5964 mono_message_init (domain
, msg
, mono_method_get_object (domain
, getter
, NULL
), out_args
);
5966 full_name
= mono_type_get_full_name (klass
);
5967 mono_array_setref (msg
->args
, 0, mono_string_new (domain
, full_name
));
5968 mono_array_setref (msg
->args
, 1, mono_string_new (domain
, mono_field_get_name (field
)));
5971 mono_remoting_invoke ((MonoObject
*)(tp
->rp
), msg
, &exc
, &out_args
);
5973 if (exc
) mono_raise_exception ((MonoException
*)exc
);
5975 if (mono_array_length (out_args
) == 0)
5978 res
= mono_array_get (out_args
, MonoObject
*, 0);
5984 * mono_store_remote_field:
5985 * @this: pointer to an object
5986 * @klass: klass of the object containing @field
5987 * @field: the field to load
5988 * @val: the value/object to store
5990 * This method is called by the runtime on attempts to store fields of
5991 * transparent proxy objects. @this points to such TP, @klass is the class of
5992 * the object containing @field. @val is the new value to store in @field.
5995 mono_store_remote_field (MonoObject
*this, MonoClass
*klass
, MonoClassField
*field
, gpointer val
)
5997 static MonoMethod
*setter
= NULL
;
5998 MonoDomain
*domain
= mono_domain_get ();
5999 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this;
6000 MonoClass
*field_class
;
6001 MonoMethodMessage
*msg
;
6002 MonoArray
*out_args
;
6007 g_assert (this->vtable
->klass
== mono_defaults
.transparent_proxy_class
);
6009 field_class
= mono_class_from_mono_type (field
->type
);
6011 if (tp
->remote_class
->proxy_class
->contextbound
&& tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
6012 if (field_class
->valuetype
) mono_field_set_value (tp
->rp
->unwrapped_server
, field
, val
);
6013 else mono_field_set_value (tp
->rp
->unwrapped_server
, field
, *((MonoObject
**)val
));
6018 setter
= mono_class_get_method_from_name (mono_defaults
.object_class
, "FieldSetter", -1);
6022 if (field_class
->valuetype
)
6023 arg
= mono_value_box (domain
, field_class
, val
);
6025 arg
= *((MonoObject
**)val
);
6028 msg
= (MonoMethodMessage
*)mono_object_new (domain
, mono_defaults
.mono_method_message_class
);
6029 mono_message_init (domain
, msg
, mono_method_get_object (domain
, setter
, NULL
), NULL
);
6031 full_name
= mono_type_get_full_name (klass
);
6032 mono_array_setref (msg
->args
, 0, mono_string_new (domain
, full_name
));
6033 mono_array_setref (msg
->args
, 1, mono_string_new (domain
, mono_field_get_name (field
)));
6034 mono_array_setref (msg
->args
, 2, arg
);
6037 mono_remoting_invoke ((MonoObject
*)(tp
->rp
), msg
, &exc
, &out_args
);
6039 if (exc
) mono_raise_exception ((MonoException
*)exc
);
6043 * mono_store_remote_field_new:
6049 * Missing documentation
6052 mono_store_remote_field_new (MonoObject
*this, MonoClass
*klass
, MonoClassField
*field
, MonoObject
*arg
)
6054 static MonoMethod
*setter
= NULL
;
6055 MonoDomain
*domain
= mono_domain_get ();
6056 MonoTransparentProxy
*tp
= (MonoTransparentProxy
*) this;
6057 MonoClass
*field_class
;
6058 MonoMethodMessage
*msg
;
6059 MonoArray
*out_args
;
6063 g_assert (this->vtable
->klass
== mono_defaults
.transparent_proxy_class
);
6065 field_class
= mono_class_from_mono_type (field
->type
);
6067 if (tp
->remote_class
->proxy_class
->contextbound
&& tp
->rp
->context
== (MonoObject
*) mono_context_get ()) {
6068 if (field_class
->valuetype
) mono_field_set_value (tp
->rp
->unwrapped_server
, field
, ((gchar
*) arg
) + sizeof (MonoObject
));
6069 else mono_field_set_value (tp
->rp
->unwrapped_server
, field
, arg
);
6074 setter
= mono_class_get_method_from_name (mono_defaults
.object_class
, "FieldSetter", -1);
6078 msg
= (MonoMethodMessage
*)mono_object_new (domain
, mono_defaults
.mono_method_message_class
);
6079 mono_message_init (domain
, msg
, mono_method_get_object (domain
, setter
, NULL
), NULL
);
6081 full_name
= mono_type_get_full_name (klass
);
6082 mono_array_setref (msg
->args
, 0, mono_string_new (domain
, full_name
));
6083 mono_array_setref (msg
->args
, 1, mono_string_new (domain
, mono_field_get_name (field
)));
6084 mono_array_setref (msg
->args
, 2, arg
);
6087 mono_remoting_invoke ((MonoObject
*)(tp
->rp
), msg
, &exc
, &out_args
);
6089 if (exc
) mono_raise_exception ((MonoException
*)exc
);
6093 * mono_create_ftnptr:
6095 * Given a function address, create a function descriptor for it.
6096 * This is only needed on some platforms.
6099 mono_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
6101 return callbacks
.create_ftnptr (domain
, addr
);
6105 * mono_get_addr_from_ftnptr:
6107 * Given a pointer to a function descriptor, return the function address.
6108 * This is only needed on some platforms.
6111 mono_get_addr_from_ftnptr (gpointer descr
)
6113 return callbacks
.get_addr_from_ftnptr (descr
);
6118 * mono_string_chars:
6121 * Returns a pointer to the UCS16 characters stored in the MonoString
6124 mono_string_chars(MonoString
*s
)
6126 /* This method is here only for documentation extraction, this is a macro */
6130 * mono_string_length:
6133 * Returns the lenght in characters of the string
6136 mono_string_length (MonoString
*s
)
6138 /* This method is here only for documentation extraction, this is a macro */