[runtime] MonoError-ize mono_delegate_ctor
[mono-project.git] / mono / metadata / object.c
blob2ae47e6373266658bb8264435bf932e27cec86bb
1 /*
2 * object.c: Object creation for the Mono runtime
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include <config.h>
14 #ifdef HAVE_ALLOCA_H
15 #include <alloca.h>
16 #endif
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/utils/strenc.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-memory-model.h>
48 #include <mono/utils/checked-build.h>
49 #include <mono/utils/mono-threads.h>
50 #include "cominterop.h"
52 static void
53 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
55 static MonoString*
56 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
58 static void
59 free_main_args (void);
61 static char *
62 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
64 /* Class lazy loading functions */
65 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
66 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
67 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
68 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
69 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
72 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
73 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
74 static mono_mutex_t ldstr_section;
76 /**
77 * mono_runtime_object_init:
78 * @this_obj: the object to initialize
80 * This function calls the zero-argument constructor (which must
81 * exist) for the given object.
83 void
84 mono_runtime_object_init (MonoObject *this_obj)
86 MonoError error;
87 mono_runtime_object_init_checked (this_obj, &error);
88 mono_error_assert_ok (&error);
91 /**
92 * mono_runtime_object_init_checked:
93 * @this_obj: the object to initialize
94 * @error: set on error.
96 * This function calls the zero-argument constructor (which must
97 * exist) for the given object and returns TRUE on success, or FALSE
98 * on error and sets @error.
100 gboolean
101 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
103 MONO_REQ_GC_UNSAFE_MODE;
105 MonoMethod *method = NULL;
106 MonoClass *klass = this_obj->vtable->klass;
108 mono_error_init (error);
109 method = mono_class_get_method_from_name (klass, ".ctor", 0);
110 if (!method)
111 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
113 if (method->klass->valuetype)
114 this_obj = (MonoObject *)mono_object_unbox (this_obj);
116 mono_runtime_invoke_checked (method, this_obj, NULL, error);
117 return is_ok (error);
120 /* The pseudo algorithm for type initialization from the spec
121 Note it doesn't say anything about domains - only threads.
123 2. If the type is initialized you are done.
124 2.1. If the type is not yet initialized, try to take an
125 initialization lock.
126 2.2. If successful, record this thread as responsible for
127 initializing the type and proceed to step 2.3.
128 2.2.1. If not, see whether this thread or any thread
129 waiting for this thread to complete already holds the lock.
130 2.2.2. If so, return since blocking would create a deadlock. This thread
131 will now see an incompletely initialized state for the type,
132 but no deadlock will arise.
133 2.2.3 If not, block until the type is initialized then return.
134 2.3 Initialize the parent type and then all interfaces implemented
135 by this type.
136 2.4 Execute the type initialization code for this type.
137 2.5 Mark the type as initialized, release the initialization lock,
138 awaken any threads waiting for this type to be initialized,
139 and return.
143 typedef struct
145 MonoNativeThreadId initializing_tid;
146 guint32 waiting_count;
147 gboolean done;
148 MonoCoopMutex initialization_section;
149 } TypeInitializationLock;
151 /* for locking access to type_initialization_hash and blocked_thread_hash */
152 static MonoCoopMutex type_initialization_section;
154 static inline void
155 mono_type_initialization_lock (void)
157 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
158 mono_coop_mutex_lock (&type_initialization_section);
161 static inline void
162 mono_type_initialization_unlock (void)
164 mono_coop_mutex_unlock (&type_initialization_section);
167 static void
168 mono_type_init_lock (TypeInitializationLock *lock)
170 MONO_REQ_GC_NEUTRAL_MODE;
172 mono_coop_mutex_lock (&lock->initialization_section);
175 static void
176 mono_type_init_unlock (TypeInitializationLock *lock)
178 mono_coop_mutex_unlock (&lock->initialization_section);
181 /* from vtable to lock */
182 static GHashTable *type_initialization_hash;
184 /* from thread id to thread id being waited on */
185 static GHashTable *blocked_thread_hash;
187 /* Main thread */
188 static MonoThread *main_thread;
190 /* Functions supplied by the runtime */
191 static MonoRuntimeCallbacks callbacks;
194 * mono_thread_set_main:
195 * @thread: thread to set as the main thread
197 * This function can be used to instruct the runtime to treat @thread
198 * as the main thread, ie, the thread that would normally execute the Main()
199 * method. This basically means that at the end of @thread, the runtime will
200 * wait for the existing foreground threads to quit and other such details.
202 void
203 mono_thread_set_main (MonoThread *thread)
205 MONO_REQ_GC_UNSAFE_MODE;
207 static gboolean registered = FALSE;
209 if (!registered) {
210 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
211 registered = TRUE;
214 main_thread = thread;
217 MonoThread*
218 mono_thread_get_main (void)
220 MONO_REQ_GC_UNSAFE_MODE;
222 return main_thread;
225 void
226 mono_type_initialization_init (void)
228 mono_coop_mutex_init_recursive (&type_initialization_section);
229 type_initialization_hash = g_hash_table_new (NULL, NULL);
230 blocked_thread_hash = g_hash_table_new (NULL, NULL);
231 mono_os_mutex_init_recursive (&ldstr_section);
234 void
235 mono_type_initialization_cleanup (void)
237 #if 0
238 /* This is causing race conditions with
239 * mono_release_type_locks
241 mono_coop_mutex_destroy (&type_initialization_section);
242 g_hash_table_destroy (type_initialization_hash);
243 type_initialization_hash = NULL;
244 #endif
245 mono_os_mutex_destroy (&ldstr_section);
246 g_hash_table_destroy (blocked_thread_hash);
247 blocked_thread_hash = NULL;
249 free_main_args ();
253 * get_type_init_exception_for_vtable:
255 * Return the stored type initialization exception for VTABLE.
257 static MonoException*
258 get_type_init_exception_for_vtable (MonoVTable *vtable)
260 MONO_REQ_GC_UNSAFE_MODE;
262 MonoError error;
263 MonoDomain *domain = vtable->domain;
264 MonoClass *klass = vtable->klass;
265 MonoException *ex;
266 gchar *full_name;
268 if (!vtable->init_failed)
269 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
272 * If the initializing thread was rudely aborted, the exception is not stored
273 * in the hash.
275 ex = NULL;
276 mono_domain_lock (domain);
277 if (domain->type_init_exception_hash)
278 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
279 mono_domain_unlock (domain);
281 if (!ex) {
282 if (klass->name_space && *klass->name_space)
283 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
284 else
285 full_name = g_strdup (klass->name);
286 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
287 g_free (full_name);
288 return_val_if_nok (&error, NULL);
291 return ex;
295 * mono_runtime_class_init:
296 * @vtable: vtable that needs to be initialized
298 * This routine calls the class constructor for @vtable.
300 void
301 mono_runtime_class_init (MonoVTable *vtable)
303 MONO_REQ_GC_UNSAFE_MODE;
304 MonoError error;
306 mono_runtime_class_init_full (vtable, &error);
307 mono_error_assert_ok (&error);
311 * mono_runtime_class_init_full:
312 * @vtable that neeeds to be initialized
313 * @error set on error
315 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
318 gboolean
319 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
321 MONO_REQ_GC_UNSAFE_MODE;
323 MonoMethod *method = NULL;
324 MonoClass *klass;
325 gchar *full_name;
326 MonoDomain *domain = vtable->domain;
327 TypeInitializationLock *lock;
328 MonoNativeThreadId tid;
329 int do_initialization = 0;
330 MonoDomain *last_domain = NULL;
332 mono_error_init (error);
334 if (vtable->initialized)
335 return TRUE;
337 klass = vtable->klass;
339 if (!klass->image->checked_module_cctor) {
340 mono_image_check_for_module_cctor (klass->image);
341 if (klass->image->has_module_cctor) {
342 MonoClass *module_klass;
343 MonoVTable *module_vtable;
345 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
346 if (!module_klass) {
347 return FALSE;
350 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
351 if (!module_vtable)
352 return FALSE;
353 if (!mono_runtime_class_init_full (module_vtable, error))
354 return FALSE;
357 method = mono_class_get_cctor (klass);
358 if (!method) {
359 vtable->initialized = 1;
360 return TRUE;
363 tid = mono_native_thread_id_get ();
365 mono_type_initialization_lock ();
366 /* double check... */
367 if (vtable->initialized) {
368 mono_type_initialization_unlock ();
369 return TRUE;
371 if (vtable->init_failed) {
372 mono_type_initialization_unlock ();
374 /* The type initialization already failed once, rethrow the same exception */
375 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
376 return FALSE;
378 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
379 if (lock == NULL) {
380 /* This thread will get to do the initialization */
381 if (mono_domain_get () != domain) {
382 /* Transfer into the target domain */
383 last_domain = mono_domain_get ();
384 if (!mono_domain_set (domain, FALSE)) {
385 vtable->initialized = 1;
386 mono_type_initialization_unlock ();
387 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
388 return FALSE;
391 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
392 mono_coop_mutex_init_recursive (&lock->initialization_section);
393 lock->initializing_tid = tid;
394 lock->waiting_count = 1;
395 lock->done = FALSE;
396 /* grab the vtable lock while this thread still owns type_initialization_section */
397 /* This is why type_initialization_lock needs to enter blocking mode */
398 mono_type_init_lock (lock);
399 g_hash_table_insert (type_initialization_hash, vtable, lock);
400 do_initialization = 1;
401 } else {
402 gpointer blocked;
403 TypeInitializationLock *pending_lock;
405 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
406 mono_type_initialization_unlock ();
407 return TRUE;
409 /* see if the thread doing the initialization is already blocked on this thread */
410 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
411 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
412 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
413 if (!pending_lock->done) {
414 mono_type_initialization_unlock ();
415 return TRUE;
416 } else {
417 /* the thread doing the initialization is blocked on this thread,
418 but on a lock that has already been freed. It just hasn't got
419 time to awake */
420 break;
423 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
425 ++lock->waiting_count;
426 /* record the fact that we are waiting on the initializing thread */
427 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
429 mono_type_initialization_unlock ();
431 if (do_initialization) {
432 MonoException *exc = NULL;
433 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
434 if (exc != NULL && mono_error_ok (error)) {
435 mono_error_set_exception_instance (error, exc);
438 /* If the initialization failed, mark the class as unusable. */
439 /* Avoid infinite loops */
440 if (!(mono_error_ok(error) ||
441 (klass->image == mono_defaults.corlib &&
442 !strcmp (klass->name_space, "System") &&
443 !strcmp (klass->name, "TypeInitializationException")))) {
444 vtable->init_failed = 1;
446 if (klass->name_space && *klass->name_space)
447 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
448 else
449 full_name = g_strdup (klass->name);
451 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
452 g_free (full_name);
453 return_val_if_nok (error, FALSE);
455 mono_error_set_exception_instance (error, exc_to_throw);
457 MonoException *exc_to_store = mono_error_convert_to_exception (error);
458 /* What we really want to do here is clone the error object and store one copy in the
459 * domain's exception hash and use the other one to error out here. */
460 mono_error_set_exception_instance (error, exc_to_store);
462 * Store the exception object so it could be thrown on subsequent
463 * accesses.
465 mono_domain_lock (domain);
466 if (!domain->type_init_exception_hash)
467 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
468 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
469 mono_domain_unlock (domain);
472 if (last_domain)
473 mono_domain_set (last_domain, TRUE);
474 lock->done = TRUE;
475 mono_type_init_unlock (lock);
476 } else {
477 /* this just blocks until the initializing thread is done */
478 mono_type_init_lock (lock);
479 mono_type_init_unlock (lock);
482 mono_type_initialization_lock ();
483 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
484 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
485 --lock->waiting_count;
486 if (lock->waiting_count == 0) {
487 mono_coop_mutex_destroy (&lock->initialization_section);
488 g_hash_table_remove (type_initialization_hash, vtable);
489 g_free (lock);
491 mono_memory_barrier ();
492 if (!vtable->init_failed)
493 vtable->initialized = 1;
494 mono_type_initialization_unlock ();
496 if (vtable->init_failed) {
497 /* Either we were the initializing thread or we waited for the initialization */
498 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
499 return FALSE;
501 return TRUE;
504 static
505 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
507 MONO_REQ_GC_NEUTRAL_MODE;
509 MonoVTable *vtable = (MonoVTable*)key;
511 TypeInitializationLock *lock = (TypeInitializationLock*) value;
512 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
513 lock->done = TRUE;
515 * Have to set this since it cannot be set by the normal code in
516 * mono_runtime_class_init (). In this case, the exception object is not stored,
517 * and get_type_init_exception_for_class () needs to be aware of this.
519 vtable->init_failed = 1;
520 mono_type_init_unlock (lock);
521 --lock->waiting_count;
522 if (lock->waiting_count == 0) {
523 mono_coop_mutex_destroy (&lock->initialization_section);
524 g_free (lock);
525 return TRUE;
528 return FALSE;
531 void
532 mono_release_type_locks (MonoInternalThread *thread)
534 MONO_REQ_GC_UNSAFE_MODE;
536 mono_type_initialization_lock ();
537 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
538 mono_type_initialization_unlock ();
541 #ifndef DISABLE_REMOTING
543 static gpointer
544 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
546 g_error ("remoting not installed");
547 return NULL;
550 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
551 #endif
553 static gpointer
554 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
556 g_assert_not_reached ();
557 return NULL;
560 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
561 static MonoImtThunkBuilder imt_thunk_builder;
562 static gboolean always_build_imt_thunks;
564 #if (MONO_IMT_SIZE > 32)
565 #error "MONO_IMT_SIZE cannot be larger than 32"
566 #endif
568 void
569 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
571 memcpy (&callbacks, cbs, sizeof (*cbs));
574 MonoRuntimeCallbacks*
575 mono_get_runtime_callbacks (void)
577 return &callbacks;
580 #ifndef DISABLE_REMOTING
581 void
582 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
584 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
586 #endif
588 void
589 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
591 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
594 void
595 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
596 imt_thunk_builder = func;
599 void
600 mono_set_always_build_imt_thunks (gboolean value)
602 always_build_imt_thunks = value;
606 * mono_compile_method:
607 * @method: The method to compile.
609 * This JIT-compiles the method, and returns the pointer to the native code
610 * produced.
612 gpointer
613 mono_compile_method (MonoMethod *method)
615 MonoError error;
616 gpointer result = mono_compile_method_checked (method, &error);
617 mono_error_cleanup (&error);
618 return result;
622 * mono_compile_method:
623 * @method: The method to compile.
624 * @error: set on error.
626 * This JIT-compiles the method, and returns the pointer to the native code
627 * produced. On failure returns NULL and sets @error.
629 gpointer
630 mono_compile_method_checked (MonoMethod *method, MonoError *error)
632 gpointer res;
634 MONO_REQ_GC_NEUTRAL_MODE
636 mono_error_init (error);
638 if (!callbacks.compile_method) {
639 g_error ("compile method called on uninitialized runtime");
640 return NULL;
642 res = callbacks.compile_method (method, error);
643 return res;
646 gpointer
647 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
649 gpointer res;
651 MONO_REQ_GC_NEUTRAL_MODE;
653 mono_error_init (error);
654 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
655 return res;
658 gpointer
659 mono_runtime_create_delegate_trampoline (MonoClass *klass)
661 MONO_REQ_GC_NEUTRAL_MODE
663 return arch_create_delegate_trampoline (mono_domain_get (), klass);
666 static MonoFreeMethodFunc default_mono_free_method = NULL;
669 * mono_install_free_method:
670 * @func: pointer to the MonoFreeMethodFunc used to release a method
672 * This is an internal VM routine, it is used for the engines to
673 * register a handler to release the resources associated with a method.
675 * Methods are freed when no more references to the delegate that holds
676 * them are left.
678 void
679 mono_install_free_method (MonoFreeMethodFunc func)
681 default_mono_free_method = func;
685 * mono_runtime_free_method:
686 * @domain; domain where the method is hosted
687 * @method: method to release
689 * This routine is invoked to free the resources associated with
690 * a method that has been JIT compiled. This is used to discard
691 * methods that were used only temporarily (for example, used in marshalling)
694 void
695 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
697 MONO_REQ_GC_NEUTRAL_MODE
699 if (default_mono_free_method != NULL)
700 default_mono_free_method (domain, method);
702 mono_method_clear_object (domain, method);
704 mono_free_method (method);
708 * The vtables in the root appdomain are assumed to be reachable by other
709 * roots, and we don't use typed allocation in the other domains.
712 /* The sync block is no longer a GC pointer */
713 #define GC_HEADER_BITMAP (0)
715 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
717 static gsize*
718 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
720 MONO_REQ_GC_NEUTRAL_MODE;
722 MonoClassField *field;
723 MonoClass *p;
724 guint32 pos;
725 int max_size;
727 if (static_fields)
728 max_size = mono_class_data_size (klass) / sizeof (gpointer);
729 else
730 max_size = klass->instance_size / sizeof (gpointer);
731 if (max_size > size) {
732 g_assert (offset <= 0);
733 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
734 size = max_size;
737 #ifdef HAVE_SGEN_GC
738 /*An Ephemeron cannot be marked by sgen*/
739 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
740 *max_set = 0;
741 memset (bitmap, 0, size / 8);
742 return bitmap;
744 #endif
746 for (p = klass; p != NULL; p = p->parent) {
747 gpointer iter = NULL;
748 while ((field = mono_class_get_fields (p, &iter))) {
749 MonoType *type;
751 if (static_fields) {
752 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
753 continue;
754 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
755 continue;
756 } else {
757 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
758 continue;
760 /* FIXME: should not happen, flag as type load error */
761 if (field->type->byref)
762 break;
764 if (static_fields && field->offset == -1)
765 /* special static */
766 continue;
768 pos = field->offset / sizeof (gpointer);
769 pos += offset;
771 type = mono_type_get_underlying_type (field->type);
772 switch (type->type) {
773 case MONO_TYPE_I:
774 case MONO_TYPE_PTR:
775 case MONO_TYPE_FNPTR:
776 break;
777 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
778 case MONO_TYPE_U:
779 #ifdef HAVE_SGEN_GC
780 break;
781 #else
782 if (klass->image != mono_defaults.corlib)
783 break;
784 #endif
785 case MONO_TYPE_STRING:
786 case MONO_TYPE_SZARRAY:
787 case MONO_TYPE_CLASS:
788 case MONO_TYPE_OBJECT:
789 case MONO_TYPE_ARRAY:
790 g_assert ((field->offset % sizeof(gpointer)) == 0);
792 g_assert (pos < size || pos <= max_size);
793 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
794 *max_set = MAX (*max_set, pos);
795 break;
796 case MONO_TYPE_GENERICINST:
797 if (!mono_type_generic_inst_is_valuetype (type)) {
798 g_assert ((field->offset % sizeof(gpointer)) == 0);
800 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
801 *max_set = MAX (*max_set, pos);
802 break;
803 } else {
804 /* fall through */
806 case MONO_TYPE_VALUETYPE: {
807 MonoClass *fclass = mono_class_from_mono_type (field->type);
808 if (fclass->has_references) {
809 /* remove the object header */
810 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
812 break;
814 case MONO_TYPE_I1:
815 case MONO_TYPE_U1:
816 case MONO_TYPE_I2:
817 case MONO_TYPE_U2:
818 case MONO_TYPE_I4:
819 case MONO_TYPE_U4:
820 case MONO_TYPE_I8:
821 case MONO_TYPE_U8:
822 case MONO_TYPE_R4:
823 case MONO_TYPE_R8:
824 case MONO_TYPE_BOOLEAN:
825 case MONO_TYPE_CHAR:
826 break;
827 default:
828 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
829 break;
832 if (static_fields)
833 break;
835 return bitmap;
839 * mono_class_compute_bitmap:
841 * Mono internal function to compute a bitmap of reference fields in a class.
843 gsize*
844 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
846 MONO_REQ_GC_NEUTRAL_MODE;
848 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
851 #if 0
853 * similar to the above, but sets the bits in the bitmap for any non-ref field
854 * and ignores static fields
856 static gsize*
857 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
859 MonoClassField *field;
860 MonoClass *p;
861 guint32 pos, pos2;
862 int max_size;
864 max_size = class->instance_size / sizeof (gpointer);
865 if (max_size >= size) {
866 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
869 for (p = class; p != NULL; p = p->parent) {
870 gpointer iter = NULL;
871 while ((field = mono_class_get_fields (p, &iter))) {
872 MonoType *type;
874 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
875 continue;
876 /* FIXME: should not happen, flag as type load error */
877 if (field->type->byref)
878 break;
880 pos = field->offset / sizeof (gpointer);
881 pos += offset;
883 type = mono_type_get_underlying_type (field->type);
884 switch (type->type) {
885 #if SIZEOF_VOID_P == 8
886 case MONO_TYPE_I:
887 case MONO_TYPE_U:
888 case MONO_TYPE_PTR:
889 case MONO_TYPE_FNPTR:
890 #endif
891 case MONO_TYPE_I8:
892 case MONO_TYPE_U8:
893 case MONO_TYPE_R8:
894 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
895 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
896 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
898 /* fall through */
899 #if SIZEOF_VOID_P == 4
900 case MONO_TYPE_I:
901 case MONO_TYPE_U:
902 case MONO_TYPE_PTR:
903 case MONO_TYPE_FNPTR:
904 #endif
905 case MONO_TYPE_I4:
906 case MONO_TYPE_U4:
907 case MONO_TYPE_R4:
908 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
909 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
910 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
912 /* fall through */
913 case MONO_TYPE_CHAR:
914 case MONO_TYPE_I2:
915 case MONO_TYPE_U2:
916 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
917 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
918 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
920 /* fall through */
921 case MONO_TYPE_BOOLEAN:
922 case MONO_TYPE_I1:
923 case MONO_TYPE_U1:
924 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
925 break;
926 case MONO_TYPE_STRING:
927 case MONO_TYPE_SZARRAY:
928 case MONO_TYPE_CLASS:
929 case MONO_TYPE_OBJECT:
930 case MONO_TYPE_ARRAY:
931 break;
932 case MONO_TYPE_GENERICINST:
933 if (!mono_type_generic_inst_is_valuetype (type)) {
934 break;
935 } else {
936 /* fall through */
938 case MONO_TYPE_VALUETYPE: {
939 MonoClass *fclass = mono_class_from_mono_type (field->type);
940 /* remove the object header */
941 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
942 break;
944 default:
945 g_assert_not_reached ();
946 break;
950 return bitmap;
954 * mono_class_insecure_overlapping:
955 * check if a class with explicit layout has references and non-references
956 * fields overlapping.
958 * Returns: TRUE if it is insecure to load the type.
960 gboolean
961 mono_class_insecure_overlapping (MonoClass *klass)
963 int max_set = 0;
964 gsize *bitmap;
965 gsize default_bitmap [4] = {0};
966 gsize *nrbitmap;
967 gsize default_nrbitmap [4] = {0};
968 int i, insecure = FALSE;
969 return FALSE;
971 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
972 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
974 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
975 int idx = i % (sizeof (bitmap [0]) * 8);
976 if (bitmap [idx] & nrbitmap [idx]) {
977 insecure = TRUE;
978 break;
981 if (bitmap != default_bitmap)
982 g_free (bitmap);
983 if (nrbitmap != default_nrbitmap)
984 g_free (nrbitmap);
985 if (insecure) {
986 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
987 return FALSE;
989 return insecure;
991 #endif
993 MonoString*
994 ves_icall_string_alloc (int length)
996 MonoError error;
997 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
998 mono_error_set_pending_exception (&error);
1000 return str;
1003 void
1004 mono_class_compute_gc_descriptor (MonoClass *klass)
1006 MONO_REQ_GC_NEUTRAL_MODE;
1008 int max_set = 0;
1009 gsize *bitmap;
1010 gsize default_bitmap [4] = {0};
1011 static gboolean gcj_inited = FALSE;
1013 if (!gcj_inited) {
1014 mono_loader_lock ();
1016 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1017 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1019 gcj_inited = TRUE;
1020 mono_loader_unlock ();
1023 if (!klass->inited)
1024 mono_class_init (klass);
1026 if (klass->gc_descr_inited)
1027 return;
1029 klass->gc_descr_inited = TRUE;
1030 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1032 bitmap = default_bitmap;
1033 if (klass == mono_defaults.string_class) {
1034 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1035 } else if (klass->rank) {
1036 mono_class_compute_gc_descriptor (klass->element_class);
1037 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1038 gsize abm = 1;
1039 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1040 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1041 class->name_space, class->name);*/
1042 } else {
1043 /* remove the object header */
1044 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1045 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1046 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1047 class->name_space, class->name);*/
1048 if (bitmap != default_bitmap)
1049 g_free (bitmap);
1051 } else {
1052 /*static int count = 0;
1053 if (count++ > 58)
1054 return;*/
1055 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1056 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1058 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1059 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1061 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1062 if (bitmap != default_bitmap)
1063 g_free (bitmap);
1068 * field_is_special_static:
1069 * @fklass: The MonoClass to look up.
1070 * @field: The MonoClassField describing the field.
1072 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1073 * SPECIAL_STATIC_NONE otherwise.
1075 static gint32
1076 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1078 MONO_REQ_GC_NEUTRAL_MODE;
1080 MonoError error;
1081 MonoCustomAttrInfo *ainfo;
1082 int i;
1083 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1084 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1085 if (!ainfo)
1086 return FALSE;
1087 for (i = 0; i < ainfo->num_attrs; ++i) {
1088 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1089 if (klass->image == mono_defaults.corlib) {
1090 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1091 mono_custom_attrs_free (ainfo);
1092 return SPECIAL_STATIC_THREAD;
1094 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1095 mono_custom_attrs_free (ainfo);
1096 return SPECIAL_STATIC_CONTEXT;
1100 mono_custom_attrs_free (ainfo);
1101 return SPECIAL_STATIC_NONE;
1104 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1105 #define mix(a,b,c) { \
1106 a -= c; a ^= rot(c, 4); c += b; \
1107 b -= a; b ^= rot(a, 6); a += c; \
1108 c -= b; c ^= rot(b, 8); b += a; \
1109 a -= c; a ^= rot(c,16); c += b; \
1110 b -= a; b ^= rot(a,19); a += c; \
1111 c -= b; c ^= rot(b, 4); b += a; \
1113 #define final(a,b,c) { \
1114 c ^= b; c -= rot(b,14); \
1115 a ^= c; a -= rot(c,11); \
1116 b ^= a; b -= rot(a,25); \
1117 c ^= b; c -= rot(b,16); \
1118 a ^= c; a -= rot(c,4); \
1119 b ^= a; b -= rot(a,14); \
1120 c ^= b; c -= rot(b,24); \
1124 * mono_method_get_imt_slot:
1126 * The IMT slot is embedded into AOTed code, so this must return the same value
1127 * for the same method across all executions. This means:
1128 * - pointers shouldn't be used as hash values.
1129 * - mono_metadata_str_hash () should be used for hashing strings.
1131 guint32
1132 mono_method_get_imt_slot (MonoMethod *method)
1134 MONO_REQ_GC_NEUTRAL_MODE;
1136 MonoMethodSignature *sig;
1137 int hashes_count;
1138 guint32 *hashes_start, *hashes;
1139 guint32 a, b, c;
1140 int i;
1142 /* This can be used to stress tests the collision code */
1143 //return 0;
1146 * We do this to simplify generic sharing. It will hurt
1147 * performance in cases where a class implements two different
1148 * instantiations of the same generic interface.
1149 * The code in build_imt_slots () depends on this.
1151 if (method->is_inflated)
1152 method = ((MonoMethodInflated*)method)->declaring;
1154 sig = mono_method_signature (method);
1155 hashes_count = sig->param_count + 4;
1156 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1157 hashes = hashes_start;
1159 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1160 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1161 method->klass->name_space, method->klass->name, method->name);
1164 /* Initialize hashes */
1165 hashes [0] = mono_metadata_str_hash (method->klass->name);
1166 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1167 hashes [2] = mono_metadata_str_hash (method->name);
1168 hashes [3] = mono_metadata_type_hash (sig->ret);
1169 for (i = 0; i < sig->param_count; i++) {
1170 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1173 /* Setup internal state */
1174 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1176 /* Handle most of the hashes */
1177 while (hashes_count > 3) {
1178 a += hashes [0];
1179 b += hashes [1];
1180 c += hashes [2];
1181 mix (a,b,c);
1182 hashes_count -= 3;
1183 hashes += 3;
1186 /* Handle the last 3 hashes (all the case statements fall through) */
1187 switch (hashes_count) {
1188 case 3 : c += hashes [2];
1189 case 2 : b += hashes [1];
1190 case 1 : a += hashes [0];
1191 final (a,b,c);
1192 case 0: /* nothing left to add */
1193 break;
1196 free (hashes_start);
1197 /* Report the result */
1198 return c % MONO_IMT_SIZE;
1200 #undef rot
1201 #undef mix
1202 #undef final
1204 #define DEBUG_IMT 0
1206 static void
1207 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1208 MONO_REQ_GC_NEUTRAL_MODE;
1210 guint32 imt_slot = mono_method_get_imt_slot (method);
1211 MonoImtBuilderEntry *entry;
1213 if (slot_num >= 0 && imt_slot != slot_num) {
1214 /* we build just a single imt slot and this is not it */
1215 return;
1218 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1219 entry->key = method;
1220 entry->value.vtable_slot = vtable_slot;
1221 entry->next = imt_builder [imt_slot];
1222 if (imt_builder [imt_slot] != NULL) {
1223 entry->children = imt_builder [imt_slot]->children + 1;
1224 if (entry->children == 1) {
1225 mono_stats.imt_slots_with_collisions++;
1226 *imt_collisions_bitmap |= (1 << imt_slot);
1228 } else {
1229 entry->children = 0;
1230 mono_stats.imt_used_slots++;
1232 imt_builder [imt_slot] = entry;
1233 #if DEBUG_IMT
1235 char *method_name = mono_method_full_name (method, TRUE);
1236 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1237 method, method_name, imt_slot, vtable_slot, entry->children);
1238 g_free (method_name);
1240 #endif
1243 #if DEBUG_IMT
1244 static void
1245 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1246 if (e != NULL) {
1247 MonoMethod *method = e->key;
1248 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1249 message,
1250 num,
1251 method,
1252 method->klass->name_space,
1253 method->klass->name,
1254 method->name);
1255 } else {
1256 printf (" * %s: NULL\n", message);
1259 #endif
1261 static int
1262 compare_imt_builder_entries (const void *p1, const void *p2) {
1263 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1264 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1266 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1269 static int
1270 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1272 MONO_REQ_GC_NEUTRAL_MODE;
1274 int count = end - start;
1275 int chunk_start = out_array->len;
1276 if (count < 4) {
1277 int i;
1278 for (i = start; i < end; ++i) {
1279 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1280 item->key = sorted_array [i]->key;
1281 item->value = sorted_array [i]->value;
1282 item->has_target_code = sorted_array [i]->has_target_code;
1283 item->is_equals = TRUE;
1284 if (i < end - 1)
1285 item->check_target_idx = out_array->len + 1;
1286 else
1287 item->check_target_idx = 0;
1288 g_ptr_array_add (out_array, item);
1290 } else {
1291 int middle = start + count / 2;
1292 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1294 item->key = sorted_array [middle]->key;
1295 item->is_equals = FALSE;
1296 g_ptr_array_add (out_array, item);
1297 imt_emit_ir (sorted_array, start, middle, out_array);
1298 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1300 return chunk_start;
1303 static GPtrArray*
1304 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1305 MONO_REQ_GC_NEUTRAL_MODE;
1307 int number_of_entries = entries->children + 1;
1308 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1309 GPtrArray *result = g_ptr_array_new ();
1310 MonoImtBuilderEntry *current_entry;
1311 int i;
1313 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1314 sorted_array [i] = current_entry;
1316 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1318 /*for (i = 0; i < number_of_entries; i++) {
1319 print_imt_entry (" sorted array:", sorted_array [i], i);
1322 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1324 free (sorted_array);
1325 return result;
1328 static gpointer
1329 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1331 MONO_REQ_GC_NEUTRAL_MODE;
1333 if (imt_builder_entry != NULL) {
1334 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1335 /* No collision, return the vtable slot contents */
1336 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1337 } else {
1338 /* Collision, build the thunk */
1339 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1340 gpointer result;
1341 int i;
1342 result = imt_thunk_builder (vtable, domain,
1343 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1344 for (i = 0; i < imt_ir->len; ++i)
1345 g_free (g_ptr_array_index (imt_ir, i));
1346 g_ptr_array_free (imt_ir, TRUE);
1347 return result;
1349 } else {
1350 if (fail_tramp)
1351 return fail_tramp;
1352 else
1353 /* Empty slot */
1354 return NULL;
1358 static MonoImtBuilderEntry*
1359 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1362 * LOCKING: requires the loader and domain locks.
1365 static void
1366 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1368 MONO_REQ_GC_NEUTRAL_MODE;
1370 int i;
1371 GSList *list_item;
1372 guint32 imt_collisions_bitmap = 0;
1373 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1374 int method_count = 0;
1375 gboolean record_method_count_for_max_collisions = FALSE;
1376 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1378 #if DEBUG_IMT
1379 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1380 #endif
1381 for (i = 0; i < klass->interface_offsets_count; ++i) {
1382 MonoClass *iface = klass->interfaces_packed [i];
1383 int interface_offset = klass->interface_offsets_packed [i];
1384 int method_slot_in_interface, vt_slot;
1386 if (mono_class_has_variant_generic_params (iface))
1387 has_variant_iface = TRUE;
1389 mono_class_setup_methods (iface);
1390 vt_slot = interface_offset;
1391 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1392 MonoMethod *method;
1394 if (slot_num >= 0 && iface->is_inflated) {
1396 * The imt slot of the method is the same as for its declaring method,
1397 * see the comment in mono_method_get_imt_slot (), so we can
1398 * avoid inflating methods which will be discarded by
1399 * add_imt_builder_entry anyway.
1401 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1402 if (mono_method_get_imt_slot (method) != slot_num) {
1403 vt_slot ++;
1404 continue;
1407 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1408 if (method->is_generic) {
1409 has_generic_virtual = TRUE;
1410 vt_slot ++;
1411 continue;
1414 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1415 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1416 vt_slot ++;
1420 if (extra_interfaces) {
1421 int interface_offset = klass->vtable_size;
1423 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1424 MonoClass* iface = (MonoClass *)list_item->data;
1425 int method_slot_in_interface;
1426 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1427 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1429 if (method->is_generic)
1430 has_generic_virtual = TRUE;
1431 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1433 interface_offset += iface->method.count;
1436 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1437 /* overwrite the imt slot only if we're building all the entries or if
1438 * we're building this specific one
1440 if (slot_num < 0 || i == slot_num) {
1441 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1443 if (entries) {
1444 if (imt_builder [i]) {
1445 MonoImtBuilderEntry *entry;
1447 /* Link entries with imt_builder [i] */
1448 for (entry = entries; entry->next; entry = entry->next) {
1449 #if DEBUG_IMT
1450 MonoMethod *method = (MonoMethod*)entry->key;
1451 char *method_name = mono_method_full_name (method, TRUE);
1452 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1453 g_free (method_name);
1454 #endif
1456 entry->next = imt_builder [i];
1457 entries->children += imt_builder [i]->children + 1;
1459 imt_builder [i] = entries;
1462 if (has_generic_virtual || has_variant_iface) {
1464 * There might be collisions later when the the thunk is expanded.
1466 imt_collisions_bitmap |= (1 << i);
1469 * The IMT thunk might be called with an instance of one of the
1470 * generic virtual methods, so has to fallback to the IMT trampoline.
1472 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1473 } else {
1474 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1476 #if DEBUG_IMT
1477 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1478 #endif
1481 if (imt_builder [i] != NULL) {
1482 int methods_in_slot = imt_builder [i]->children + 1;
1483 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1484 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1485 record_method_count_for_max_collisions = TRUE;
1487 method_count += methods_in_slot;
1491 mono_stats.imt_number_of_methods += method_count;
1492 if (record_method_count_for_max_collisions) {
1493 mono_stats.imt_method_count_when_max_collisions = method_count;
1496 for (i = 0; i < MONO_IMT_SIZE; i++) {
1497 MonoImtBuilderEntry* entry = imt_builder [i];
1498 while (entry != NULL) {
1499 MonoImtBuilderEntry* next = entry->next;
1500 g_free (entry);
1501 entry = next;
1504 free (imt_builder);
1505 /* we OR the bitmap since we may build just a single imt slot at a time */
1506 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1509 static void
1510 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1511 MONO_REQ_GC_NEUTRAL_MODE;
1513 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1517 * mono_vtable_build_imt_slot:
1518 * @vtable: virtual object table struct
1519 * @imt_slot: slot in the IMT table
1521 * Fill the given @imt_slot in the IMT table of @vtable with
1522 * a trampoline or a thunk for the case of collisions.
1523 * This is part of the internal mono API.
1525 * LOCKING: Take the domain lock.
1527 void
1528 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1530 MONO_REQ_GC_NEUTRAL_MODE;
1532 gpointer *imt = (gpointer*)vtable;
1533 imt -= MONO_IMT_SIZE;
1534 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1536 /* no support for extra interfaces: the proxy objects will need
1537 * to build the complete IMT
1538 * Update and heck needs to ahppen inside the proper domain lock, as all
1539 * the changes made to a MonoVTable.
1541 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1542 mono_domain_lock (vtable->domain);
1543 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1544 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1545 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1546 mono_domain_unlock (vtable->domain);
1547 mono_loader_unlock ();
1552 * The first two free list entries both belong to the wait list: The
1553 * first entry is the pointer to the head of the list and the second
1554 * entry points to the last element. That way appending and removing
1555 * the first element are both O(1) operations.
1557 #ifdef MONO_SMALL_CONFIG
1558 #define NUM_FREE_LISTS 6
1559 #else
1560 #define NUM_FREE_LISTS 12
1561 #endif
1562 #define FIRST_FREE_LIST_SIZE 64
1563 #define MAX_WAIT_LENGTH 50
1564 #define THUNK_THRESHOLD 10
1567 * LOCKING: The domain lock must be held.
1569 static void
1570 init_thunk_free_lists (MonoDomain *domain)
1572 MONO_REQ_GC_NEUTRAL_MODE;
1574 if (domain->thunk_free_lists)
1575 return;
1576 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1579 static int
1580 list_index_for_size (int item_size)
1582 int i = 2;
1583 int size = FIRST_FREE_LIST_SIZE;
1585 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1586 i++;
1587 size <<= 1;
1590 return i;
1594 * mono_method_alloc_generic_virtual_thunk:
1595 * @domain: a domain
1596 * @size: size in bytes
1598 * Allocs size bytes to be used for the code of a generic virtual
1599 * thunk. It's either allocated from the domain's code manager or
1600 * reused from a previously invalidated piece.
1602 * LOCKING: The domain lock must be held.
1604 gpointer
1605 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1607 MONO_REQ_GC_NEUTRAL_MODE;
1609 static gboolean inited = FALSE;
1610 static int generic_virtual_thunks_size = 0;
1612 guint32 *p;
1613 int i;
1614 MonoThunkFreeList **l;
1616 init_thunk_free_lists (domain);
1618 size += sizeof (guint32);
1619 if (size < sizeof (MonoThunkFreeList))
1620 size = sizeof (MonoThunkFreeList);
1622 i = list_index_for_size (size);
1623 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1624 if ((*l)->size >= size) {
1625 MonoThunkFreeList *item = *l;
1626 *l = item->next;
1627 return ((guint32*)item) + 1;
1631 /* no suitable item found - search lists of larger sizes */
1632 while (++i < NUM_FREE_LISTS) {
1633 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1634 if (!item)
1635 continue;
1636 g_assert (item->size > size);
1637 domain->thunk_free_lists [i] = item->next;
1638 return ((guint32*)item) + 1;
1641 /* still nothing found - allocate it */
1642 if (!inited) {
1643 mono_counters_register ("Generic virtual thunk bytes",
1644 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1645 inited = TRUE;
1647 generic_virtual_thunks_size += size;
1649 p = (guint32 *)mono_domain_code_reserve (domain, size);
1650 *p = size;
1652 mono_domain_lock (domain);
1653 if (!domain->generic_virtual_thunks)
1654 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1655 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1656 mono_domain_unlock (domain);
1658 return p + 1;
1662 * LOCKING: The domain lock must be held.
1664 static void
1665 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1667 MONO_REQ_GC_NEUTRAL_MODE;
1669 guint32 *p = (guint32 *)code;
1670 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1671 gboolean found = FALSE;
1673 mono_domain_lock (domain);
1674 if (!domain->generic_virtual_thunks)
1675 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1676 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1677 found = TRUE;
1678 mono_domain_unlock (domain);
1680 if (!found)
1681 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1682 return;
1683 init_thunk_free_lists (domain);
1685 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1686 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1687 int length = item->length;
1688 int i;
1690 /* unlink the first item from the wait list */
1691 domain->thunk_free_lists [0] = item->next;
1692 domain->thunk_free_lists [0]->length = length - 1;
1694 i = list_index_for_size (item->size);
1696 /* put it in the free list */
1697 item->next = domain->thunk_free_lists [i];
1698 domain->thunk_free_lists [i] = item;
1701 l->next = NULL;
1702 if (domain->thunk_free_lists [1]) {
1703 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1704 domain->thunk_free_lists [0]->length++;
1705 } else {
1706 g_assert (!domain->thunk_free_lists [0]);
1708 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1709 domain->thunk_free_lists [0]->length = 1;
1713 typedef struct _GenericVirtualCase {
1714 MonoMethod *method;
1715 gpointer code;
1716 int count;
1717 struct _GenericVirtualCase *next;
1718 } GenericVirtualCase;
1721 * get_generic_virtual_entries:
1723 * Return IMT entries for the generic virtual method instances and
1724 * variant interface methods for vtable slot
1725 * VTABLE_SLOT.
1727 static MonoImtBuilderEntry*
1728 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1730 MONO_REQ_GC_NEUTRAL_MODE;
1732 GenericVirtualCase *list;
1733 MonoImtBuilderEntry *entries;
1735 mono_domain_lock (domain);
1736 if (!domain->generic_virtual_cases)
1737 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1739 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1741 entries = NULL;
1742 for (; list; list = list->next) {
1743 MonoImtBuilderEntry *entry;
1745 if (list->count < THUNK_THRESHOLD)
1746 continue;
1748 entry = g_new0 (MonoImtBuilderEntry, 1);
1749 entry->key = list->method;
1750 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1751 entry->has_target_code = 1;
1752 if (entries)
1753 entry->children = entries->children + 1;
1754 entry->next = entries;
1755 entries = entry;
1758 mono_domain_unlock (domain);
1760 /* FIXME: Leaking memory ? */
1761 return entries;
1765 * mono_method_add_generic_virtual_invocation:
1766 * @domain: a domain
1767 * @vtable_slot: pointer to the vtable slot
1768 * @method: the inflated generic virtual method
1769 * @code: the method's code
1771 * Registers a call via unmanaged code to a generic virtual method
1772 * instantiation or variant interface method. If the number of calls reaches a threshold
1773 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1774 * virtual method thunk.
1776 void
1777 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1778 gpointer *vtable_slot,
1779 MonoMethod *method, gpointer code)
1781 MONO_REQ_GC_NEUTRAL_MODE;
1783 static gboolean inited = FALSE;
1784 static int num_added = 0;
1786 GenericVirtualCase *gvc, *list;
1787 MonoImtBuilderEntry *entries;
1788 int i;
1789 GPtrArray *sorted;
1791 mono_domain_lock (domain);
1792 if (!domain->generic_virtual_cases)
1793 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1795 /* Check whether the case was already added */
1796 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1797 gvc = list;
1798 while (gvc) {
1799 if (gvc->method == method)
1800 break;
1801 gvc = gvc->next;
1804 /* If not found, make a new one */
1805 if (!gvc) {
1806 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1807 gvc->method = method;
1808 gvc->code = code;
1809 gvc->count = 0;
1810 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1812 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1814 if (!inited) {
1815 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1816 inited = TRUE;
1818 num_added++;
1821 if (++gvc->count == THUNK_THRESHOLD) {
1822 gpointer *old_thunk = (void **)*vtable_slot;
1823 gpointer vtable_trampoline = NULL;
1824 gpointer imt_trampoline = NULL;
1826 if ((gpointer)vtable_slot < (gpointer)vtable) {
1827 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1828 int imt_slot = MONO_IMT_SIZE + displacement;
1830 /* Force the rebuild of the thunk at the next call */
1831 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1832 *vtable_slot = imt_trampoline;
1833 } else {
1834 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1836 entries = get_generic_virtual_entries (domain, vtable_slot);
1838 sorted = imt_sort_slot_entries (entries);
1840 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1841 vtable_trampoline);
1843 while (entries) {
1844 MonoImtBuilderEntry *next = entries->next;
1845 g_free (entries);
1846 entries = next;
1849 for (i = 0; i < sorted->len; ++i)
1850 g_free (g_ptr_array_index (sorted, i));
1851 g_ptr_array_free (sorted, TRUE);
1854 #ifndef __native_client__
1855 /* We don't re-use any thunks as there is a lot of overhead */
1856 /* to deleting and re-using code in Native Client. */
1857 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1858 invalidate_generic_virtual_thunk (domain, old_thunk);
1859 #endif
1862 mono_domain_unlock (domain);
1865 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1868 * mono_class_vtable:
1869 * @domain: the application domain
1870 * @class: the class to initialize
1872 * VTables are domain specific because we create domain specific code, and
1873 * they contain the domain specific static class data.
1874 * On failure, NULL is returned, and class->exception_type is set.
1876 MonoVTable *
1877 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1879 MonoError error;
1880 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1881 mono_error_cleanup (&error);
1882 return vtable;
1886 * mono_class_vtable_full:
1887 * @domain: the application domain
1888 * @class: the class to initialize
1889 * @error set on failure.
1891 * VTables are domain specific because we create domain specific code, and
1892 * they contain the domain specific static class data.
1894 MonoVTable *
1895 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1897 MONO_REQ_GC_UNSAFE_MODE;
1899 MonoClassRuntimeInfo *runtime_info;
1901 mono_error_init (error);
1903 g_assert (klass);
1905 if (mono_class_has_failure (klass)) {
1906 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1907 return NULL;
1910 /* this check can be inlined in jitted code, too */
1911 runtime_info = klass->runtime_info;
1912 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1913 return runtime_info->domain_vtables [domain->domain_id];
1914 return mono_class_create_runtime_vtable (domain, klass, error);
1918 * mono_class_try_get_vtable:
1919 * @domain: the application domain
1920 * @class: the class to initialize
1922 * This function tries to get the associated vtable from @class if
1923 * it was already created.
1925 MonoVTable *
1926 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1928 MONO_REQ_GC_NEUTRAL_MODE;
1930 MonoClassRuntimeInfo *runtime_info;
1932 g_assert (klass);
1934 runtime_info = klass->runtime_info;
1935 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1936 return runtime_info->domain_vtables [domain->domain_id];
1937 return NULL;
1940 static gpointer*
1941 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1943 MONO_REQ_GC_NEUTRAL_MODE;
1945 size_t alloc_offset;
1948 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1949 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1950 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1952 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1953 g_assert ((imt_table_bytes & 7) == 4);
1954 vtable_size += 4;
1955 alloc_offset = 4;
1956 } else {
1957 alloc_offset = 0;
1960 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1963 static MonoVTable *
1964 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1966 MONO_REQ_GC_UNSAFE_MODE;
1968 MonoVTable *vt;
1969 MonoClassRuntimeInfo *runtime_info, *old_info;
1970 MonoClassField *field;
1971 char *t;
1972 int i, vtable_slots;
1973 size_t imt_table_bytes;
1974 int gc_bits;
1975 guint32 vtable_size, class_size;
1976 gpointer iter;
1977 gpointer *interface_offsets;
1979 mono_error_init (error);
1981 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1982 mono_domain_lock (domain);
1983 runtime_info = klass->runtime_info;
1984 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1985 mono_domain_unlock (domain);
1986 mono_loader_unlock ();
1987 return runtime_info->domain_vtables [domain->domain_id];
1989 if (!klass->inited || mono_class_has_failure (klass)) {
1990 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1991 mono_domain_unlock (domain);
1992 mono_loader_unlock ();
1993 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1994 return NULL;
1998 /* Array types require that their element type be valid*/
1999 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
2000 MonoClass *element_class = klass->element_class;
2001 if (!element_class->inited)
2002 mono_class_init (element_class);
2004 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
2005 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
2006 mono_class_setup_vtable (element_class);
2008 if (mono_class_has_failure (element_class)) {
2009 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2010 if (!mono_class_has_failure (klass))
2011 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
2012 mono_domain_unlock (domain);
2013 mono_loader_unlock ();
2014 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2015 return NULL;
2020 * For some classes, mono_class_init () already computed klass->vtable_size, and
2021 * that is all that is needed because of the vtable trampolines.
2023 if (!klass->vtable_size)
2024 mono_class_setup_vtable (klass);
2026 if (klass->generic_class && !klass->vtable)
2027 mono_class_check_vtable_constraints (klass, NULL);
2029 /* Initialize klass->has_finalize */
2030 mono_class_has_finalizer (klass);
2032 if (mono_class_has_failure (klass)) {
2033 mono_domain_unlock (domain);
2034 mono_loader_unlock ();
2035 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2036 return NULL;
2039 vtable_slots = klass->vtable_size;
2040 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2041 class_size = mono_class_data_size (klass);
2042 if (class_size)
2043 vtable_slots++;
2045 if (klass->interface_offsets_count) {
2046 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2047 mono_stats.imt_number_of_tables++;
2048 mono_stats.imt_tables_size += imt_table_bytes;
2049 } else {
2050 imt_table_bytes = 0;
2053 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2055 mono_stats.used_class_count++;
2056 mono_stats.class_vtable_size += vtable_size;
2058 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2059 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2060 g_assert (!((gsize)vt & 7));
2062 vt->klass = klass;
2063 vt->rank = klass->rank;
2064 vt->domain = domain;
2066 mono_class_compute_gc_descriptor (klass);
2068 * We can't use typed allocation in the non-root domains, since the
2069 * collector needs the GC descriptor stored in the vtable even after
2070 * the mempool containing the vtable is destroyed when the domain is
2071 * unloaded. An alternative might be to allocate vtables in the GC
2072 * heap, but this does not seem to work (it leads to crashes inside
2073 * libgc). If that approach is tried, two gc descriptors need to be
2074 * allocated for each class: one for the root domain, and one for all
2075 * other domains. The second descriptor should contain a bit for the
2076 * vtable field in MonoObject, since we can no longer assume the
2077 * vtable is reachable by other roots after the appdomain is unloaded.
2079 #ifdef HAVE_BOEHM_GC
2080 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2081 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2082 else
2083 #endif
2084 vt->gc_descr = klass->gc_descr;
2086 gc_bits = mono_gc_get_vtable_bits (klass);
2087 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2089 vt->gc_bits = gc_bits;
2091 if (class_size) {
2092 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2093 if (klass->has_static_refs) {
2094 MonoGCDescriptor statics_gc_descr;
2095 int max_set = 0;
2096 gsize default_bitmap [4] = {0};
2097 gsize *bitmap;
2099 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2100 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2101 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2102 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2103 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2104 if (bitmap != default_bitmap)
2105 g_free (bitmap);
2106 } else {
2107 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2109 vt->has_static_fields = TRUE;
2110 mono_stats.class_static_data_size += class_size;
2113 iter = NULL;
2114 while ((field = mono_class_get_fields (klass, &iter))) {
2115 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2116 continue;
2117 if (mono_field_is_deleted (field))
2118 continue;
2119 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2120 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2121 if (special_static != SPECIAL_STATIC_NONE) {
2122 guint32 size, offset;
2123 gint32 align;
2124 gsize default_bitmap [4] = {0};
2125 gsize *bitmap;
2126 int max_set = 0;
2127 int numbits;
2128 MonoClass *fclass;
2129 if (mono_type_is_reference (field->type)) {
2130 default_bitmap [0] = 1;
2131 numbits = 1;
2132 bitmap = default_bitmap;
2133 } else if (mono_type_is_struct (field->type)) {
2134 fclass = mono_class_from_mono_type (field->type);
2135 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2136 numbits = max_set + 1;
2137 } else {
2138 default_bitmap [0] = 0;
2139 numbits = 0;
2140 bitmap = default_bitmap;
2142 size = mono_type_size (field->type, &align);
2143 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2144 if (!domain->special_static_fields)
2145 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2146 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2147 if (bitmap != default_bitmap)
2148 g_free (bitmap);
2150 * This marks the field as special static to speed up the
2151 * checks in mono_field_static_get/set_value ().
2153 field->offset = -1;
2154 continue;
2157 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2158 MonoClass *fklass = mono_class_from_mono_type (field->type);
2159 const char *data = mono_field_get_data (field);
2161 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2162 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2163 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2164 if (!data)
2165 continue;
2166 if (fklass->valuetype) {
2167 memcpy (t, data, mono_class_value_size (fklass, NULL));
2168 } else {
2169 /* it's a pointer type: add check */
2170 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2171 *t = *(char *)data;
2173 continue;
2177 vt->max_interface_id = klass->max_interface_id;
2178 vt->interface_bitmap = klass->interface_bitmap;
2180 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2181 // class->name, klass->interface_offsets_count);
2183 /* Initialize vtable */
2184 if (callbacks.get_vtable_trampoline) {
2185 // This also covers the AOT case
2186 for (i = 0; i < klass->vtable_size; ++i) {
2187 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2189 } else {
2190 mono_class_setup_vtable (klass);
2192 for (i = 0; i < klass->vtable_size; ++i) {
2193 MonoMethod *cm;
2195 cm = klass->vtable [i];
2196 if (cm) {
2197 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2198 if (!is_ok (error)) {
2199 mono_domain_unlock (domain);
2200 mono_loader_unlock ();
2201 return NULL;
2207 if (imt_table_bytes) {
2208 /* Now that the vtable is full, we can actually fill up the IMT */
2209 for (i = 0; i < MONO_IMT_SIZE; ++i)
2210 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2214 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2215 * re-acquire them and check if another thread has created the vtable in the meantime.
2217 /* Special case System.MonoType to avoid infinite recursion */
2218 if (klass != mono_defaults.monotype_class) {
2219 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2220 if (!is_ok (error)) {
2221 mono_domain_unlock (domain);
2222 mono_loader_unlock ();
2223 return NULL;
2226 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2227 /* This is unregistered in
2228 unregister_vtable_reflection_type() in
2229 domain.c. */
2230 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2233 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2235 /* class_vtable_array keeps an array of created vtables
2237 g_ptr_array_add (domain->class_vtable_array, vt);
2238 /* klass->runtime_info is protected by the loader lock, both when
2239 * it it enlarged and when it is stored info.
2243 * Store the vtable in klass->runtime_info.
2244 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2246 mono_memory_barrier ();
2248 old_info = klass->runtime_info;
2249 if (old_info && old_info->max_domain >= domain->domain_id) {
2250 /* someone already created a large enough runtime info */
2251 old_info->domain_vtables [domain->domain_id] = vt;
2252 } else {
2253 int new_size = domain->domain_id;
2254 if (old_info)
2255 new_size = MAX (new_size, old_info->max_domain);
2256 new_size++;
2257 /* make the new size a power of two */
2258 i = 2;
2259 while (new_size > i)
2260 i <<= 1;
2261 new_size = i;
2262 /* this is a bounded memory retention issue: may want to
2263 * handle it differently when we'll have a rcu-like system.
2265 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2266 runtime_info->max_domain = new_size - 1;
2267 /* copy the stuff from the older info */
2268 if (old_info) {
2269 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2271 runtime_info->domain_vtables [domain->domain_id] = vt;
2272 /* keep this last*/
2273 mono_memory_barrier ();
2274 klass->runtime_info = runtime_info;
2277 if (klass == mono_defaults.monotype_class) {
2278 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2279 if (!is_ok (error)) {
2280 mono_domain_unlock (domain);
2281 mono_loader_unlock ();
2282 return NULL;
2285 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2286 /* This is unregistered in
2287 unregister_vtable_reflection_type() in
2288 domain.c. */
2289 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2292 mono_domain_unlock (domain);
2293 mono_loader_unlock ();
2295 /* make sure the parent is initialized */
2296 /*FIXME shouldn't this fail the current type?*/
2297 if (klass->parent)
2298 mono_class_vtable_full (domain, klass->parent, error);
2300 return vt;
2303 #ifndef DISABLE_REMOTING
2305 * mono_class_proxy_vtable:
2306 * @domain: the application domain
2307 * @remove_class: the remote class
2309 * Creates a vtable for transparent proxies. It is basically
2310 * a copy of the real vtable of the class wrapped in @remote_class,
2311 * but all function pointers invoke the remoting functions, and
2312 * vtable->klass points to the transparent proxy class, and not to @class.
2314 static MonoVTable *
2315 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2317 MONO_REQ_GC_UNSAFE_MODE;
2319 MonoError error;
2320 MonoVTable *vt, *pvt;
2321 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2322 MonoClass *k;
2323 GSList *extra_interfaces = NULL;
2324 MonoClass *klass = remote_class->proxy_class;
2325 gpointer *interface_offsets;
2326 uint8_t *bitmap;
2327 int bsize;
2328 size_t imt_table_bytes;
2330 #ifdef COMPRESSED_INTERFACE_BITMAP
2331 int bcsize;
2332 #endif
2334 vt = mono_class_vtable (domain, klass);
2335 g_assert (vt); /*FIXME property handle failure*/
2336 max_interface_id = vt->max_interface_id;
2338 /* Calculate vtable space for extra interfaces */
2339 for (j = 0; j < remote_class->interface_count; j++) {
2340 MonoClass* iclass = remote_class->interfaces[j];
2341 GPtrArray *ifaces;
2342 int method_count;
2344 /*FIXME test for interfaces with variant generic arguments*/
2345 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2346 continue; /* interface implemented by the class */
2347 if (g_slist_find (extra_interfaces, iclass))
2348 continue;
2350 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2352 method_count = mono_class_num_methods (iclass);
2354 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2355 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2356 if (ifaces) {
2357 for (i = 0; i < ifaces->len; ++i) {
2358 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2359 /*FIXME test for interfaces with variant generic arguments*/
2360 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2361 continue; /* interface implemented by the class */
2362 if (g_slist_find (extra_interfaces, ic))
2363 continue;
2364 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2365 method_count += mono_class_num_methods (ic);
2367 g_ptr_array_free (ifaces, TRUE);
2370 extra_interface_vtsize += method_count * sizeof (gpointer);
2371 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2374 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2375 mono_stats.imt_number_of_tables++;
2376 mono_stats.imt_tables_size += imt_table_bytes;
2378 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2380 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2382 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2383 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2384 g_assert (!((gsize)pvt & 7));
2386 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2388 pvt->klass = mono_defaults.transparent_proxy_class;
2389 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2390 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2392 /* initialize vtable */
2393 mono_class_setup_vtable (klass);
2394 for (i = 0; i < klass->vtable_size; ++i) {
2395 MonoMethod *cm;
2397 if ((cm = klass->vtable [i]))
2398 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2399 else
2400 pvt->vtable [i] = NULL;
2403 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2404 /* create trampolines for abstract methods */
2405 for (k = klass; k; k = k->parent) {
2406 MonoMethod* m;
2407 gpointer iter = NULL;
2408 while ((m = mono_class_get_methods (k, &iter)))
2409 if (!pvt->vtable [m->slot])
2410 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2414 pvt->max_interface_id = max_interface_id;
2415 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2416 #ifdef COMPRESSED_INTERFACE_BITMAP
2417 bitmap = (uint8_t *)g_malloc0 (bsize);
2418 #else
2419 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2420 #endif
2422 for (i = 0; i < klass->interface_offsets_count; ++i) {
2423 int interface_id = klass->interfaces_packed [i]->interface_id;
2424 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2427 if (extra_interfaces) {
2428 int slot = klass->vtable_size;
2429 MonoClass* interf;
2430 gpointer iter;
2431 MonoMethod* cm;
2432 GSList *list_item;
2434 /* Create trampolines for the methods of the interfaces */
2435 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2436 interf = (MonoClass *)list_item->data;
2438 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2440 iter = NULL;
2441 j = 0;
2442 while ((cm = mono_class_get_methods (interf, &iter)))
2443 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2445 slot += mono_class_num_methods (interf);
2449 /* Now that the vtable is full, we can actually fill up the IMT */
2450 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2451 if (extra_interfaces) {
2452 g_slist_free (extra_interfaces);
2455 #ifdef COMPRESSED_INTERFACE_BITMAP
2456 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2457 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2458 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2459 g_free (bitmap);
2460 #else
2461 pvt->interface_bitmap = bitmap;
2462 #endif
2463 return pvt;
2466 #endif /* DISABLE_REMOTING */
2469 * mono_class_field_is_special_static:
2471 * Returns whether @field is a thread/context static field.
2473 gboolean
2474 mono_class_field_is_special_static (MonoClassField *field)
2476 MONO_REQ_GC_NEUTRAL_MODE
2478 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2479 return FALSE;
2480 if (mono_field_is_deleted (field))
2481 return FALSE;
2482 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2483 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2484 return TRUE;
2486 return FALSE;
2490 * mono_class_field_get_special_static_type:
2491 * @field: The MonoClassField describing the field.
2493 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2494 * SPECIAL_STATIC_NONE otherwise.
2496 guint32
2497 mono_class_field_get_special_static_type (MonoClassField *field)
2499 MONO_REQ_GC_NEUTRAL_MODE
2501 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2502 return SPECIAL_STATIC_NONE;
2503 if (mono_field_is_deleted (field))
2504 return SPECIAL_STATIC_NONE;
2505 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2506 return field_is_special_static (field->parent, field);
2507 return SPECIAL_STATIC_NONE;
2511 * mono_class_has_special_static_fields:
2513 * Returns whenever @klass has any thread/context static fields.
2515 gboolean
2516 mono_class_has_special_static_fields (MonoClass *klass)
2518 MONO_REQ_GC_NEUTRAL_MODE
2520 MonoClassField *field;
2521 gpointer iter;
2523 iter = NULL;
2524 while ((field = mono_class_get_fields (klass, &iter))) {
2525 g_assert (field->parent == klass);
2526 if (mono_class_field_is_special_static (field))
2527 return TRUE;
2530 return FALSE;
2533 #ifndef DISABLE_REMOTING
2535 * create_remote_class_key:
2536 * Creates an array of pointers that can be used as a hash key for a remote class.
2537 * The first element of the array is the number of pointers.
2539 static gpointer*
2540 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2542 MONO_REQ_GC_NEUTRAL_MODE;
2544 gpointer *key;
2545 int i, j;
2547 if (remote_class == NULL) {
2548 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2549 key = (void **)g_malloc (sizeof(gpointer) * 3);
2550 key [0] = GINT_TO_POINTER (2);
2551 key [1] = mono_defaults.marshalbyrefobject_class;
2552 key [2] = extra_class;
2553 } else {
2554 key = (void **)g_malloc (sizeof(gpointer) * 2);
2555 key [0] = GINT_TO_POINTER (1);
2556 key [1] = extra_class;
2558 } else {
2559 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2560 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2561 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2562 key [1] = remote_class->proxy_class;
2564 // Keep the list of interfaces sorted
2565 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2566 if (extra_class && remote_class->interfaces [i] > extra_class) {
2567 key [j++] = extra_class;
2568 extra_class = NULL;
2570 key [j] = remote_class->interfaces [i];
2572 if (extra_class)
2573 key [j] = extra_class;
2574 } else {
2575 // Replace the old class. The interface list is the same
2576 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2577 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2578 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2579 for (i = 0; i < remote_class->interface_count; i++)
2580 key [2 + i] = remote_class->interfaces [i];
2584 return key;
2588 * copy_remote_class_key:
2590 * Make a copy of KEY in the domain and return the copy.
2592 static gpointer*
2593 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2595 MONO_REQ_GC_NEUTRAL_MODE
2597 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2598 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2600 memcpy (mp_key, key, key_size);
2602 return mp_key;
2606 * mono_remote_class:
2607 * @domain: the application domain
2608 * @class_name: name of the remote class
2609 * @error: set on error
2611 * Creates and initializes a MonoRemoteClass object for a remote type.
2613 * On failure returns NULL and sets @error
2615 MonoRemoteClass*
2616 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2618 MONO_REQ_GC_UNSAFE_MODE;
2620 MonoRemoteClass *rc;
2621 gpointer* key, *mp_key;
2622 char *name;
2624 mono_error_init (error);
2626 key = create_remote_class_key (NULL, proxy_class);
2628 mono_domain_lock (domain);
2629 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2631 if (rc) {
2632 g_free (key);
2633 mono_domain_unlock (domain);
2634 return rc;
2637 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2638 if (!is_ok (error)) {
2639 g_free (key);
2640 mono_domain_unlock (domain);
2641 return NULL;
2644 mp_key = copy_remote_class_key (domain, key);
2645 g_free (key);
2646 key = mp_key;
2648 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2649 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2650 rc->interface_count = 1;
2651 rc->interfaces [0] = proxy_class;
2652 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2653 } else {
2654 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2655 rc->interface_count = 0;
2656 rc->proxy_class = proxy_class;
2659 rc->default_vtable = NULL;
2660 rc->xdomain_vtable = NULL;
2661 rc->proxy_class_name = name;
2662 #ifndef DISABLE_PERFCOUNTERS
2663 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2664 #endif
2666 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2668 mono_domain_unlock (domain);
2669 return rc;
2673 * clone_remote_class:
2674 * Creates a copy of the remote_class, adding the provided class or interface
2676 static MonoRemoteClass*
2677 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2679 MONO_REQ_GC_NEUTRAL_MODE;
2681 MonoRemoteClass *rc;
2682 gpointer* key, *mp_key;
2684 key = create_remote_class_key (remote_class, extra_class);
2685 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2686 if (rc != NULL) {
2687 g_free (key);
2688 return rc;
2691 mp_key = copy_remote_class_key (domain, key);
2692 g_free (key);
2693 key = mp_key;
2695 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2696 int i,j;
2697 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2698 rc->proxy_class = remote_class->proxy_class;
2699 rc->interface_count = remote_class->interface_count + 1;
2701 // Keep the list of interfaces sorted, since the hash key of
2702 // the remote class depends on this
2703 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2704 if (remote_class->interfaces [i] > extra_class && i == j)
2705 rc->interfaces [j++] = extra_class;
2706 rc->interfaces [j] = remote_class->interfaces [i];
2708 if (i == j)
2709 rc->interfaces [j] = extra_class;
2710 } else {
2711 // Replace the old class. The interface array is the same
2712 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2713 rc->proxy_class = extra_class;
2714 rc->interface_count = remote_class->interface_count;
2715 if (rc->interface_count > 0)
2716 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2719 rc->default_vtable = NULL;
2720 rc->xdomain_vtable = NULL;
2721 rc->proxy_class_name = remote_class->proxy_class_name;
2723 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2725 return rc;
2728 gpointer
2729 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2731 MONO_REQ_GC_UNSAFE_MODE;
2733 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2734 mono_domain_lock (domain);
2735 if (rp->target_domain_id != -1) {
2736 if (remote_class->xdomain_vtable == NULL)
2737 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2738 mono_domain_unlock (domain);
2739 mono_loader_unlock ();
2740 return remote_class->xdomain_vtable;
2742 if (remote_class->default_vtable == NULL) {
2743 MonoType *type;
2744 MonoClass *klass;
2745 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2746 klass = mono_class_from_mono_type (type);
2747 #ifndef DISABLE_COM
2748 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2749 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2750 else
2751 #endif
2752 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2755 mono_domain_unlock (domain);
2756 mono_loader_unlock ();
2757 return remote_class->default_vtable;
2761 * mono_upgrade_remote_class:
2762 * @domain: the application domain
2763 * @tproxy: the proxy whose remote class has to be upgraded.
2764 * @klass: class to which the remote class can be casted.
2766 * Updates the vtable of the remote class by adding the necessary method slots
2767 * and interface offsets so it can be safely casted to klass. klass can be a
2768 * class or an interface.
2770 void
2771 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2773 MONO_REQ_GC_UNSAFE_MODE;
2775 MonoTransparentProxy *tproxy;
2776 MonoRemoteClass *remote_class;
2777 gboolean redo_vtable;
2779 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2780 mono_domain_lock (domain);
2782 tproxy = (MonoTransparentProxy*) proxy_object;
2783 remote_class = tproxy->remote_class;
2785 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2786 int i;
2787 redo_vtable = TRUE;
2788 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2789 if (remote_class->interfaces [i] == klass)
2790 redo_vtable = FALSE;
2792 else {
2793 redo_vtable = (remote_class->proxy_class != klass);
2796 if (redo_vtable) {
2797 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2798 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2801 mono_domain_unlock (domain);
2802 mono_loader_unlock ();
2804 #endif /* DISABLE_REMOTING */
2808 * mono_object_get_virtual_method:
2809 * @obj: object to operate on.
2810 * @method: method
2812 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2813 * the instance of a callvirt of method.
2815 MonoMethod*
2816 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2818 MONO_REQ_GC_UNSAFE_MODE;
2820 MonoClass *klass;
2821 MonoMethod **vtable;
2822 gboolean is_proxy = FALSE;
2823 MonoMethod *res = NULL;
2825 klass = mono_object_class (obj);
2826 #ifndef DISABLE_REMOTING
2827 if (klass == mono_defaults.transparent_proxy_class) {
2828 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2829 is_proxy = TRUE;
2831 #endif
2833 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2834 return method;
2836 mono_class_setup_vtable (klass);
2837 vtable = klass->vtable;
2839 if (method->slot == -1) {
2840 /* method->slot might not be set for instances of generic methods */
2841 if (method->is_inflated) {
2842 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2843 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2844 } else {
2845 if (!is_proxy)
2846 g_assert_not_reached ();
2850 /* check method->slot is a valid index: perform isinstance? */
2851 if (method->slot != -1) {
2852 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2853 if (!is_proxy) {
2854 gboolean variance_used = FALSE;
2855 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2856 g_assert (iface_offset > 0);
2857 res = vtable [iface_offset + method->slot];
2859 } else {
2860 res = vtable [method->slot];
2864 #ifndef DISABLE_REMOTING
2865 if (is_proxy) {
2866 /* It may be an interface, abstract class method or generic method */
2867 if (!res || mono_method_signature (res)->generic_param_count)
2868 res = method;
2870 /* generic methods demand invoke_with_check */
2871 if (mono_method_signature (res)->generic_param_count)
2872 res = mono_marshal_get_remoting_invoke_with_check (res);
2873 else {
2874 #ifndef DISABLE_COM
2875 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2876 res = mono_cominterop_get_invoke (res);
2877 else
2878 #endif
2879 res = mono_marshal_get_remoting_invoke (res);
2881 } else
2882 #endif
2884 if (method->is_inflated) {
2885 MonoError error;
2886 /* Have to inflate the result */
2887 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2888 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2892 g_assert (res);
2894 return res;
2897 static MonoObject*
2898 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2900 MONO_REQ_GC_UNSAFE_MODE;
2902 MonoObject *result = NULL;
2904 g_assert (callbacks.runtime_invoke);
2906 mono_error_init (error);
2908 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2909 mono_profiler_method_start_invoke (method);
2911 MONO_ENTER_GC_UNSAFE;
2913 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2915 MONO_EXIT_GC_UNSAFE;
2917 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2918 mono_profiler_method_end_invoke (method);
2920 if (!mono_error_ok (error))
2921 return NULL;
2923 return result;
2927 * mono_runtime_invoke:
2928 * @method: method to invoke
2929 * @obJ: object instance
2930 * @params: arguments to the method
2931 * @exc: exception information.
2933 * Invokes the method represented by @method on the object @obj.
2935 * obj is the 'this' pointer, it should be NULL for static
2936 * methods, a MonoObject* for object instances and a pointer to
2937 * the value type for value types.
2939 * The params array contains the arguments to the method with the
2940 * same convention: MonoObject* pointers for object instances and
2941 * pointers to the value type otherwise.
2943 * From unmanaged code you'll usually use the
2944 * mono_runtime_invoke() variant.
2946 * Note that this function doesn't handle virtual methods for
2947 * you, it will exec the exact method you pass: we still need to
2948 * expose a function to lookup the derived class implementation
2949 * of a virtual method (there are examples of this in the code,
2950 * though).
2952 * You can pass NULL as the exc argument if you don't want to
2953 * catch exceptions, otherwise, *exc will be set to the exception
2954 * thrown, if any. if an exception is thrown, you can't use the
2955 * MonoObject* result from the function.
2957 * If the method returns a value type, it is boxed in an object
2958 * reference.
2960 MonoObject*
2961 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2963 MonoError error;
2964 MonoObject *res;
2965 if (exc) {
2966 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2967 if (*exc == NULL && !mono_error_ok(&error)) {
2968 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2969 } else
2970 mono_error_cleanup (&error);
2971 } else {
2972 res = mono_runtime_invoke_checked (method, obj, params, &error);
2973 mono_error_raise_exception (&error);
2975 return res;
2979 * mono_runtime_try_invoke:
2980 * @method: method to invoke
2981 * @obJ: object instance
2982 * @params: arguments to the method
2983 * @exc: exception information.
2984 * @error: set on error
2986 * Invokes the method represented by @method on the object @obj.
2988 * obj is the 'this' pointer, it should be NULL for static
2989 * methods, a MonoObject* for object instances and a pointer to
2990 * the value type for value types.
2992 * The params array contains the arguments to the method with the
2993 * same convention: MonoObject* pointers for object instances and
2994 * pointers to the value type otherwise.
2996 * From unmanaged code you'll usually use the
2997 * mono_runtime_invoke() variant.
2999 * Note that this function doesn't handle virtual methods for
3000 * you, it will exec the exact method you pass: we still need to
3001 * expose a function to lookup the derived class implementation
3002 * of a virtual method (there are examples of this in the code,
3003 * though).
3005 * For this function, you must not pass NULL as the exc argument if
3006 * you don't want to catch exceptions, use
3007 * mono_runtime_invoke_checked(). If an exception is thrown, you
3008 * can't use the MonoObject* result from the function.
3010 * If this method cannot be invoked, @error will be set and @exc and
3011 * the return value must not be used.
3013 * If the method returns a value type, it is boxed in an object
3014 * reference.
3016 MonoObject*
3017 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3019 MONO_REQ_GC_UNSAFE_MODE;
3021 g_assert (exc != NULL);
3023 if (mono_runtime_get_no_exec ())
3024 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3026 return do_runtime_invoke (method, obj, params, exc, error);
3030 * mono_runtime_invoke_checked:
3031 * @method: method to invoke
3032 * @obJ: object instance
3033 * @params: arguments to the method
3034 * @error: set on error
3036 * Invokes the method represented by @method on the object @obj.
3038 * obj is the 'this' pointer, it should be NULL for static
3039 * methods, a MonoObject* for object instances and a pointer to
3040 * the value type for value types.
3042 * The params array contains the arguments to the method with the
3043 * same convention: MonoObject* pointers for object instances and
3044 * pointers to the value type otherwise.
3046 * From unmanaged code you'll usually use the
3047 * mono_runtime_invoke() variant.
3049 * Note that this function doesn't handle virtual methods for
3050 * you, it will exec the exact method you pass: we still need to
3051 * expose a function to lookup the derived class implementation
3052 * of a virtual method (there are examples of this in the code,
3053 * though).
3055 * If an exception is thrown, you can't use the MonoObject* result
3056 * from the function.
3058 * If this method cannot be invoked, @error will be set. If the
3059 * method throws an exception (and we're in coop mode) the exception
3060 * will be set in @error.
3062 * If the method returns a value type, it is boxed in an object
3063 * reference.
3065 MonoObject*
3066 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3068 MONO_REQ_GC_UNSAFE_MODE;
3070 if (mono_runtime_get_no_exec ())
3071 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3073 return do_runtime_invoke (method, obj, params, NULL, error);
3077 * mono_method_get_unmanaged_thunk:
3078 * @method: method to generate a thunk for.
3080 * Returns an unmanaged->managed thunk that can be used to call
3081 * a managed method directly from C.
3083 * The thunk's C signature closely matches the managed signature:
3085 * C#: public bool Equals (object obj);
3086 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3087 * MonoObject*, MonoException**);
3089 * The 1st ("this") parameter must not be used with static methods:
3091 * C#: public static bool ReferenceEquals (object a, object b);
3092 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3093 * MonoException**);
3095 * The last argument must be a non-null pointer of a MonoException* pointer.
3096 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3097 * exception has been thrown in managed code. Otherwise it will point
3098 * to the MonoException* caught by the thunk. In this case, the result of
3099 * the thunk is undefined:
3101 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3102 * MonoException *ex = NULL;
3103 * Equals func = mono_method_get_unmanaged_thunk (method);
3104 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3105 * if (ex) {
3106 * // handle exception
3109 * The calling convention of the thunk matches the platform's default
3110 * convention. This means that under Windows, C declarations must
3111 * contain the __stdcall attribute:
3113 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3114 * MonoObject*, MonoException**);
3116 * LIMITATIONS
3118 * Value type arguments and return values are treated as they were objects:
3120 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3121 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3123 * Arguments must be properly boxed upon trunk's invocation, while return
3124 * values must be unboxed.
3126 gpointer
3127 mono_method_get_unmanaged_thunk (MonoMethod *method)
3129 MONO_REQ_GC_NEUTRAL_MODE;
3130 MONO_REQ_API_ENTRYPOINT;
3132 MonoError error;
3133 gpointer res;
3135 g_assert (!mono_threads_is_coop_enabled ());
3137 MONO_ENTER_GC_UNSAFE;
3138 method = mono_marshal_get_thunk_invoke_wrapper (method);
3139 res = mono_compile_method_checked (method, &error);
3140 mono_error_cleanup (&error);
3141 MONO_EXIT_GC_UNSAFE;
3143 return res;
3146 void
3147 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3149 MONO_REQ_GC_UNSAFE_MODE;
3151 int t;
3152 if (type->byref) {
3153 /* object fields cannot be byref, so we don't need a
3154 wbarrier here */
3155 gpointer *p = (gpointer*)dest;
3156 *p = value;
3157 return;
3159 t = type->type;
3160 handle_enum:
3161 switch (t) {
3162 case MONO_TYPE_BOOLEAN:
3163 case MONO_TYPE_I1:
3164 case MONO_TYPE_U1: {
3165 guint8 *p = (guint8*)dest;
3166 *p = value ? *(guint8*)value : 0;
3167 return;
3169 case MONO_TYPE_I2:
3170 case MONO_TYPE_U2:
3171 case MONO_TYPE_CHAR: {
3172 guint16 *p = (guint16*)dest;
3173 *p = value ? *(guint16*)value : 0;
3174 return;
3176 #if SIZEOF_VOID_P == 4
3177 case MONO_TYPE_I:
3178 case MONO_TYPE_U:
3179 #endif
3180 case MONO_TYPE_I4:
3181 case MONO_TYPE_U4: {
3182 gint32 *p = (gint32*)dest;
3183 *p = value ? *(gint32*)value : 0;
3184 return;
3186 #if SIZEOF_VOID_P == 8
3187 case MONO_TYPE_I:
3188 case MONO_TYPE_U:
3189 #endif
3190 case MONO_TYPE_I8:
3191 case MONO_TYPE_U8: {
3192 gint64 *p = (gint64*)dest;
3193 *p = value ? *(gint64*)value : 0;
3194 return;
3196 case MONO_TYPE_R4: {
3197 float *p = (float*)dest;
3198 *p = value ? *(float*)value : 0;
3199 return;
3201 case MONO_TYPE_R8: {
3202 double *p = (double*)dest;
3203 *p = value ? *(double*)value : 0;
3204 return;
3206 case MONO_TYPE_STRING:
3207 case MONO_TYPE_SZARRAY:
3208 case MONO_TYPE_CLASS:
3209 case MONO_TYPE_OBJECT:
3210 case MONO_TYPE_ARRAY:
3211 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3212 return;
3213 case MONO_TYPE_FNPTR:
3214 case MONO_TYPE_PTR: {
3215 gpointer *p = (gpointer*)dest;
3216 *p = deref_pointer? *(gpointer*)value: value;
3217 return;
3219 case MONO_TYPE_VALUETYPE:
3220 /* note that 't' and 'type->type' can be different */
3221 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3222 t = mono_class_enum_basetype (type->data.klass)->type;
3223 goto handle_enum;
3224 } else {
3225 MonoClass *klass = mono_class_from_mono_type (type);
3226 int size = mono_class_value_size (klass, NULL);
3227 if (value == NULL)
3228 mono_gc_bzero_atomic (dest, size);
3229 else
3230 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3232 return;
3233 case MONO_TYPE_GENERICINST:
3234 t = type->data.generic_class->container_class->byval_arg.type;
3235 goto handle_enum;
3236 default:
3237 g_error ("got type %x", type->type);
3242 * mono_field_set_value:
3243 * @obj: Instance object
3244 * @field: MonoClassField describing the field to set
3245 * @value: The value to be set
3247 * Sets the value of the field described by @field in the object instance @obj
3248 * to the value passed in @value. This method should only be used for instance
3249 * fields. For static fields, use mono_field_static_set_value.
3251 * The value must be on the native format of the field type.
3253 void
3254 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3256 MONO_REQ_GC_UNSAFE_MODE;
3258 void *dest;
3260 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3262 dest = (char*)obj + field->offset;
3263 mono_copy_value (field->type, dest, value, FALSE);
3267 * mono_field_static_set_value:
3268 * @field: MonoClassField describing the field to set
3269 * @value: The value to be set
3271 * Sets the value of the static field described by @field
3272 * to the value passed in @value.
3274 * The value must be on the native format of the field type.
3276 void
3277 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3279 MONO_REQ_GC_UNSAFE_MODE;
3281 void *dest;
3283 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3284 /* you cant set a constant! */
3285 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3287 if (field->offset == -1) {
3288 /* Special static */
3289 gpointer addr;
3291 mono_domain_lock (vt->domain);
3292 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3293 mono_domain_unlock (vt->domain);
3294 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3295 } else {
3296 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3298 mono_copy_value (field->type, dest, value, FALSE);
3302 * mono_vtable_get_static_field_data:
3304 * Internal use function: return a pointer to the memory holding the static fields
3305 * for a class or NULL if there are no static fields.
3306 * This is exported only for use by the debugger.
3308 void *
3309 mono_vtable_get_static_field_data (MonoVTable *vt)
3311 MONO_REQ_GC_NEUTRAL_MODE
3313 if (!vt->has_static_fields)
3314 return NULL;
3315 return vt->vtable [vt->klass->vtable_size];
3318 static guint8*
3319 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3321 MONO_REQ_GC_UNSAFE_MODE;
3323 guint8 *src;
3325 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3326 if (field->offset == -1) {
3327 /* Special static */
3328 gpointer addr;
3330 mono_domain_lock (vt->domain);
3331 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3332 mono_domain_unlock (vt->domain);
3333 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3334 } else {
3335 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3337 } else {
3338 src = (guint8*)obj + field->offset;
3341 return src;
3345 * mono_field_get_value:
3346 * @obj: Object instance
3347 * @field: MonoClassField describing the field to fetch information from
3348 * @value: pointer to the location where the value will be stored
3350 * Use this routine to get the value of the field @field in the object
3351 * passed.
3353 * The pointer provided by value must be of the field type, for reference
3354 * types this is a MonoObject*, for value types its the actual pointer to
3355 * the value type.
3357 * For example:
3358 * int i;
3359 * mono_field_get_value (obj, int_field, &i);
3361 void
3362 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3364 MONO_REQ_GC_UNSAFE_MODE;
3366 void *src;
3368 g_assert (obj);
3370 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3372 src = (char*)obj + field->offset;
3373 mono_copy_value (field->type, value, src, TRUE);
3377 * mono_field_get_value_object:
3378 * @domain: domain where the object will be created (if boxing)
3379 * @field: MonoClassField describing the field to fetch information from
3380 * @obj: The object instance for the field.
3382 * Returns: a new MonoObject with the value from the given field. If the
3383 * field represents a value type, the value is boxed.
3386 MonoObject *
3387 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3389 MonoError error;
3390 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3391 mono_error_assert_ok (&error);
3392 return result;
3396 * mono_field_get_value_object_checked:
3397 * @domain: domain where the object will be created (if boxing)
3398 * @field: MonoClassField describing the field to fetch information from
3399 * @obj: The object instance for the field.
3400 * @error: Set on error.
3402 * Returns: a new MonoObject with the value from the given field. If the
3403 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3406 MonoObject *
3407 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3409 MONO_REQ_GC_UNSAFE_MODE;
3411 mono_error_init (error);
3413 MonoObject *o;
3414 MonoClass *klass;
3415 MonoVTable *vtable = NULL;
3416 gchar *v;
3417 gboolean is_static = FALSE;
3418 gboolean is_ref = FALSE;
3419 gboolean is_literal = FALSE;
3420 gboolean is_ptr = FALSE;
3421 MonoType *type = mono_field_get_type_checked (field, error);
3423 return_val_if_nok (error, NULL);
3425 switch (type->type) {
3426 case MONO_TYPE_STRING:
3427 case MONO_TYPE_OBJECT:
3428 case MONO_TYPE_CLASS:
3429 case MONO_TYPE_ARRAY:
3430 case MONO_TYPE_SZARRAY:
3431 is_ref = TRUE;
3432 break;
3433 case MONO_TYPE_U1:
3434 case MONO_TYPE_I1:
3435 case MONO_TYPE_BOOLEAN:
3436 case MONO_TYPE_U2:
3437 case MONO_TYPE_I2:
3438 case MONO_TYPE_CHAR:
3439 case MONO_TYPE_U:
3440 case MONO_TYPE_I:
3441 case MONO_TYPE_U4:
3442 case MONO_TYPE_I4:
3443 case MONO_TYPE_R4:
3444 case MONO_TYPE_U8:
3445 case MONO_TYPE_I8:
3446 case MONO_TYPE_R8:
3447 case MONO_TYPE_VALUETYPE:
3448 is_ref = type->byref;
3449 break;
3450 case MONO_TYPE_GENERICINST:
3451 is_ref = !mono_type_generic_inst_is_valuetype (type);
3452 break;
3453 case MONO_TYPE_PTR:
3454 is_ptr = TRUE;
3455 break;
3456 default:
3457 g_error ("type 0x%x not handled in "
3458 "mono_field_get_value_object", type->type);
3459 return NULL;
3462 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3463 is_literal = TRUE;
3465 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3466 is_static = TRUE;
3468 if (!is_literal) {
3469 vtable = mono_class_vtable_full (domain, field->parent, error);
3470 return_val_if_nok (error, NULL);
3472 if (!vtable->initialized) {
3473 mono_runtime_class_init_full (vtable, error);
3474 return_val_if_nok (error, NULL);
3477 } else {
3478 g_assert (obj);
3481 if (is_ref) {
3482 if (is_literal) {
3483 get_default_field_value (domain, field, &o, error);
3484 return_val_if_nok (error, NULL);
3485 } else if (is_static) {
3486 mono_field_static_get_value_checked (vtable, field, &o, error);
3487 return_val_if_nok (error, NULL);
3488 } else {
3489 mono_field_get_value (obj, field, &o);
3491 return o;
3494 if (is_ptr) {
3495 static MonoMethod *m;
3496 gpointer args [2];
3497 gpointer *ptr;
3498 gpointer v;
3500 if (!m) {
3501 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3502 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3503 g_assert (m);
3506 v = &ptr;
3507 if (is_literal) {
3508 get_default_field_value (domain, field, v, error);
3509 return_val_if_nok (error, NULL);
3510 } else if (is_static) {
3511 mono_field_static_get_value_checked (vtable, field, v, error);
3512 return_val_if_nok (error, NULL);
3513 } else {
3514 mono_field_get_value (obj, field, v);
3517 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3518 args [0] = ptr ? *ptr : NULL;
3519 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3520 return_val_if_nok (error, NULL);
3522 o = mono_runtime_invoke_checked (m, NULL, args, error);
3523 return_val_if_nok (error, NULL);
3525 return o;
3528 /* boxed value type */
3529 klass = mono_class_from_mono_type (type);
3531 if (mono_class_is_nullable (klass))
3532 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3534 o = mono_object_new_checked (domain, klass, error);
3535 return_val_if_nok (error, NULL);
3536 v = ((gchar *) o) + sizeof (MonoObject);
3538 if (is_literal) {
3539 get_default_field_value (domain, field, v, error);
3540 return_val_if_nok (error, NULL);
3541 } else if (is_static) {
3542 mono_field_static_get_value_checked (vtable, field, v, error);
3543 return_val_if_nok (error, NULL);
3544 } else {
3545 mono_field_get_value (obj, field, v);
3548 return o;
3552 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3554 MONO_REQ_GC_UNSAFE_MODE;
3556 mono_error_init (error);
3557 int retval = 0;
3558 const char *p = blob;
3559 mono_metadata_decode_blob_size (p, &p);
3561 switch (type) {
3562 case MONO_TYPE_BOOLEAN:
3563 case MONO_TYPE_U1:
3564 case MONO_TYPE_I1:
3565 *(guint8 *) value = *p;
3566 break;
3567 case MONO_TYPE_CHAR:
3568 case MONO_TYPE_U2:
3569 case MONO_TYPE_I2:
3570 *(guint16*) value = read16 (p);
3571 break;
3572 case MONO_TYPE_U4:
3573 case MONO_TYPE_I4:
3574 *(guint32*) value = read32 (p);
3575 break;
3576 case MONO_TYPE_U8:
3577 case MONO_TYPE_I8:
3578 *(guint64*) value = read64 (p);
3579 break;
3580 case MONO_TYPE_R4:
3581 readr4 (p, (float*) value);
3582 break;
3583 case MONO_TYPE_R8:
3584 readr8 (p, (double*) value);
3585 break;
3586 case MONO_TYPE_STRING:
3587 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3588 break;
3589 case MONO_TYPE_CLASS:
3590 *(gpointer*) value = NULL;
3591 break;
3592 default:
3593 retval = -1;
3594 g_warning ("type 0x%02x should not be in constant table", type);
3596 return retval;
3599 static void
3600 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3602 MONO_REQ_GC_NEUTRAL_MODE;
3604 MonoTypeEnum def_type;
3605 const char* data;
3607 mono_error_init (error);
3609 data = mono_class_get_field_default_value (field, &def_type);
3610 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3613 void
3614 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3616 MONO_REQ_GC_UNSAFE_MODE;
3618 void *src;
3620 mono_error_init (error);
3622 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3624 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3625 get_default_field_value (vt->domain, field, value, error);
3626 return;
3629 if (field->offset == -1) {
3630 /* Special static */
3631 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3632 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3633 } else {
3634 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3636 mono_copy_value (field->type, value, src, TRUE);
3640 * mono_field_static_get_value:
3641 * @vt: vtable to the object
3642 * @field: MonoClassField describing the field to fetch information from
3643 * @value: where the value is returned
3645 * Use this routine to get the value of the static field @field value.
3647 * The pointer provided by value must be of the field type, for reference
3648 * types this is a MonoObject*, for value types its the actual pointer to
3649 * the value type.
3651 * For example:
3652 * int i;
3653 * mono_field_static_get_value (vt, int_field, &i);
3655 void
3656 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3658 MONO_REQ_GC_NEUTRAL_MODE;
3660 MonoError error;
3661 mono_field_static_get_value_checked (vt, field, value, &error);
3662 mono_error_cleanup (&error);
3666 * mono_field_static_get_value_checked:
3667 * @vt: vtable to the object
3668 * @field: MonoClassField describing the field to fetch information from
3669 * @value: where the value is returned
3670 * @error: set on error
3672 * Use this routine to get the value of the static field @field value.
3674 * The pointer provided by value must be of the field type, for reference
3675 * types this is a MonoObject*, for value types its the actual pointer to
3676 * the value type.
3678 * For example:
3679 * int i;
3680 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3681 * if (!is_ok (error)) { ... }
3683 * On failure sets @error.
3685 void
3686 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3688 MONO_REQ_GC_NEUTRAL_MODE;
3690 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3694 * mono_property_set_value:
3695 * @prop: MonoProperty to set
3696 * @obj: instance object on which to act
3697 * @params: parameters to pass to the propery
3698 * @exc: optional exception
3700 * Invokes the property's set method with the given arguments on the
3701 * object instance obj (or NULL for static properties).
3703 * You can pass NULL as the exc argument if you don't want to
3704 * catch exceptions, otherwise, *exc will be set to the exception
3705 * thrown, if any. if an exception is thrown, you can't use the
3706 * MonoObject* result from the function.
3708 void
3709 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3711 MONO_REQ_GC_UNSAFE_MODE;
3713 MonoError error;
3714 do_runtime_invoke (prop->set, obj, params, exc, &error);
3715 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3716 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3717 } else {
3718 mono_error_cleanup (&error);
3723 * mono_property_set_value_checked:
3724 * @prop: MonoProperty to set
3725 * @obj: instance object on which to act
3726 * @params: parameters to pass to the propery
3727 * @error: set on error
3729 * Invokes the property's set method with the given arguments on the
3730 * object instance obj (or NULL for static properties).
3732 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3733 * If an exception is thrown, it will be caught and returned via @error.
3735 gboolean
3736 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3738 MONO_REQ_GC_UNSAFE_MODE;
3740 MonoObject *exc;
3742 mono_error_init (error);
3743 do_runtime_invoke (prop->set, obj, params, &exc, error);
3744 if (exc != NULL && is_ok (error))
3745 mono_error_set_exception_instance (error, (MonoException*)exc);
3746 return is_ok (error);
3750 * mono_property_get_value:
3751 * @prop: MonoProperty to fetch
3752 * @obj: instance object on which to act
3753 * @params: parameters to pass to the propery
3754 * @exc: optional exception
3756 * Invokes the property's get method with the given arguments on the
3757 * object instance obj (or NULL for static properties).
3759 * You can pass NULL as the exc argument if you don't want to
3760 * catch exceptions, otherwise, *exc will be set to the exception
3761 * thrown, if any. if an exception is thrown, you can't use the
3762 * MonoObject* result from the function.
3764 * Returns: the value from invoking the get method on the property.
3766 MonoObject*
3767 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3769 MONO_REQ_GC_UNSAFE_MODE;
3771 MonoError error;
3772 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3773 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3774 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3775 } else {
3776 mono_error_cleanup (&error); /* FIXME don't raise here */
3779 return val;
3783 * mono_property_get_value_checked:
3784 * @prop: MonoProperty to fetch
3785 * @obj: instance object on which to act
3786 * @params: parameters to pass to the propery
3787 * @error: set on error
3789 * Invokes the property's get method with the given arguments on the
3790 * object instance obj (or NULL for static properties).
3792 * If an exception is thrown, you can't use the
3793 * MonoObject* result from the function. The exception will be propagated via @error.
3795 * Returns: the value from invoking the get method on the property. On
3796 * failure returns NULL and sets @error.
3798 MonoObject*
3799 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3801 MONO_REQ_GC_UNSAFE_MODE;
3803 MonoObject *exc;
3804 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3805 if (exc != NULL && !is_ok (error))
3806 mono_error_set_exception_instance (error, (MonoException*) exc);
3807 if (!is_ok (error))
3808 val = NULL;
3809 return val;
3814 * mono_nullable_init:
3815 * @buf: The nullable structure to initialize.
3816 * @value: the value to initialize from
3817 * @klass: the type for the object
3819 * Initialize the nullable structure pointed to by @buf from @value which
3820 * should be a boxed value type. The size of @buf should be able to hold
3821 * as much data as the @klass->instance_size (which is the number of bytes
3822 * that will be copies).
3824 * Since Nullables have variable structure, we can not define a C
3825 * structure for them.
3827 void
3828 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3830 MONO_REQ_GC_UNSAFE_MODE;
3832 MonoClass *param_class = klass->cast_class;
3834 mono_class_setup_fields_locking (klass);
3835 g_assert (klass->fields_inited);
3837 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3838 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3840 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3841 if (value) {
3842 if (param_class->has_references)
3843 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3844 else
3845 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3846 } else {
3847 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3852 * mono_nullable_box:
3853 * @buf: The buffer representing the data to be boxed
3854 * @klass: the type to box it as.
3855 * @error: set on oerr
3857 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3858 * @buf. On failure returns NULL and sets @error
3860 MonoObject*
3861 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3863 MONO_REQ_GC_UNSAFE_MODE;
3865 mono_error_init (error);
3866 MonoClass *param_class = klass->cast_class;
3868 mono_class_setup_fields_locking (klass);
3869 g_assert (klass->fields_inited);
3871 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3872 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3874 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3875 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3876 return_val_if_nok (error, NULL);
3877 if (param_class->has_references)
3878 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3879 else
3880 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3881 return o;
3883 else
3884 return NULL;
3888 * mono_get_delegate_invoke:
3889 * @klass: The delegate class
3891 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3893 MonoMethod *
3894 mono_get_delegate_invoke (MonoClass *klass)
3896 MONO_REQ_GC_NEUTRAL_MODE;
3898 MonoMethod *im;
3900 /* This is called at runtime, so avoid the slower search in metadata */
3901 mono_class_setup_methods (klass);
3902 if (mono_class_has_failure (klass))
3903 return NULL;
3904 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3905 return im;
3909 * mono_get_delegate_begin_invoke:
3910 * @klass: The delegate class
3912 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3914 MonoMethod *
3915 mono_get_delegate_begin_invoke (MonoClass *klass)
3917 MONO_REQ_GC_NEUTRAL_MODE;
3919 MonoMethod *im;
3921 /* This is called at runtime, so avoid the slower search in metadata */
3922 mono_class_setup_methods (klass);
3923 if (mono_class_has_failure (klass))
3924 return NULL;
3925 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3926 return im;
3930 * mono_get_delegate_end_invoke:
3931 * @klass: The delegate class
3933 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3935 MonoMethod *
3936 mono_get_delegate_end_invoke (MonoClass *klass)
3938 MONO_REQ_GC_NEUTRAL_MODE;
3940 MonoMethod *im;
3942 /* This is called at runtime, so avoid the slower search in metadata */
3943 mono_class_setup_methods (klass);
3944 if (mono_class_has_failure (klass))
3945 return NULL;
3946 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3947 return im;
3951 * mono_runtime_delegate_invoke:
3952 * @delegate: pointer to a delegate object.
3953 * @params: parameters for the delegate.
3954 * @exc: Pointer to the exception result.
3956 * Invokes the delegate method @delegate with the parameters provided.
3958 * You can pass NULL as the exc argument if you don't want to
3959 * catch exceptions, otherwise, *exc will be set to the exception
3960 * thrown, if any. if an exception is thrown, you can't use the
3961 * MonoObject* result from the function.
3963 MonoObject*
3964 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3966 MONO_REQ_GC_UNSAFE_MODE;
3968 MonoError error;
3969 MonoMethod *im;
3970 MonoClass *klass = delegate->vtable->klass;
3971 MonoObject *o;
3973 im = mono_get_delegate_invoke (klass);
3974 if (!im)
3975 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3977 if (exc) {
3978 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3979 if (*exc == NULL && !mono_error_ok (&error))
3980 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3981 else
3982 mono_error_cleanup (&error);
3983 } else {
3984 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3985 mono_error_raise_exception (&error); /* FIXME don't raise here */
3988 return o;
3991 static char **main_args = NULL;
3992 static int num_main_args = 0;
3995 * mono_runtime_get_main_args:
3997 * Returns: a MonoArray with the arguments passed to the main program
3999 MonoArray*
4000 mono_runtime_get_main_args (void)
4002 MONO_REQ_GC_UNSAFE_MODE;
4003 MonoError error;
4004 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4005 mono_error_assert_ok (&error);
4006 return result;
4010 * mono_runtime_get_main_args:
4011 * @error: set on error
4013 * Returns: a MonoArray with the arguments passed to the main
4014 * program. On failure returns NULL and sets @error.
4016 MonoArray*
4017 mono_runtime_get_main_args_checked (MonoError *error)
4019 MonoArray *res;
4020 int i;
4021 MonoDomain *domain = mono_domain_get ();
4023 mono_error_init (error);
4025 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4026 return_val_if_nok (error, NULL);
4028 for (i = 0; i < num_main_args; ++i)
4029 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4031 return res;
4034 static void
4035 free_main_args (void)
4037 MONO_REQ_GC_NEUTRAL_MODE;
4039 int i;
4041 for (i = 0; i < num_main_args; ++i)
4042 g_free (main_args [i]);
4043 g_free (main_args);
4044 num_main_args = 0;
4045 main_args = NULL;
4049 * mono_runtime_set_main_args:
4050 * @argc: number of arguments from the command line
4051 * @argv: array of strings from the command line
4053 * Set the command line arguments from an embedding application that doesn't otherwise call
4054 * mono_runtime_run_main ().
4057 mono_runtime_set_main_args (int argc, char* argv[])
4059 MONO_REQ_GC_NEUTRAL_MODE;
4061 int i;
4063 free_main_args ();
4064 main_args = g_new0 (char*, argc);
4065 num_main_args = argc;
4067 for (i = 0; i < argc; ++i) {
4068 gchar *utf8_arg;
4070 utf8_arg = mono_utf8_from_external (argv[i]);
4071 if (utf8_arg == NULL) {
4072 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4073 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4074 exit (-1);
4077 main_args [i] = utf8_arg;
4080 return 0;
4084 * mono_runtime_run_main:
4085 * @method: the method to start the application with (usually Main)
4086 * @argc: number of arguments from the command line
4087 * @argv: array of strings from the command line
4088 * @exc: excetption results
4090 * Execute a standard Main() method (argc/argv contains the
4091 * executable name). This method also sets the command line argument value
4092 * needed by System.Environment.
4097 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4098 MonoObject **exc)
4100 MONO_REQ_GC_UNSAFE_MODE;
4102 MonoError error;
4103 int i;
4104 MonoArray *args = NULL;
4105 MonoDomain *domain = mono_domain_get ();
4106 gchar *utf8_fullpath;
4107 MonoMethodSignature *sig;
4109 g_assert (method != NULL);
4111 mono_thread_set_main (mono_thread_current ());
4113 main_args = g_new0 (char*, argc);
4114 num_main_args = argc;
4116 if (!g_path_is_absolute (argv [0])) {
4117 gchar *basename = g_path_get_basename (argv [0]);
4118 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4119 basename,
4120 NULL);
4122 utf8_fullpath = mono_utf8_from_external (fullpath);
4123 if(utf8_fullpath == NULL) {
4124 /* Printing the arg text will cause glib to
4125 * whinge about "Invalid UTF-8", but at least
4126 * its relevant, and shows the problem text
4127 * string.
4129 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4130 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4131 exit (-1);
4134 g_free (fullpath);
4135 g_free (basename);
4136 } else {
4137 utf8_fullpath = mono_utf8_from_external (argv[0]);
4138 if(utf8_fullpath == NULL) {
4139 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4140 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4141 exit (-1);
4145 main_args [0] = utf8_fullpath;
4147 for (i = 1; i < argc; ++i) {
4148 gchar *utf8_arg;
4150 utf8_arg=mono_utf8_from_external (argv[i]);
4151 if(utf8_arg==NULL) {
4152 /* Ditto the comment about Invalid UTF-8 here */
4153 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4154 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4155 exit (-1);
4158 main_args [i] = utf8_arg;
4160 argc--;
4161 argv++;
4163 sig = mono_method_signature (method);
4164 if (!sig) {
4165 g_print ("Unable to load Main method.\n");
4166 exit (-1);
4169 if (sig->param_count) {
4170 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4171 mono_error_assert_ok (&error);
4172 for (i = 0; i < argc; ++i) {
4173 /* The encodings should all work, given that
4174 * we've checked all these args for the
4175 * main_args array.
4177 gchar *str = mono_utf8_from_external (argv [i]);
4178 MonoString *arg = mono_string_new (domain, str);
4179 mono_array_setref (args, i, arg);
4180 g_free (str);
4182 } else {
4183 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4184 mono_error_assert_ok (&error);
4187 mono_assembly_set_main (method->klass->image->assembly);
4189 return mono_runtime_exec_main (method, args, exc);
4192 static MonoObject*
4193 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4195 static MonoMethod *serialize_method;
4197 MonoError error;
4198 void *params [1];
4199 MonoObject *array;
4201 if (!serialize_method) {
4202 MonoClass *klass = mono_class_get_remoting_services_class ();
4203 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4206 if (!serialize_method) {
4207 *failure = TRUE;
4208 return NULL;
4211 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4213 params [0] = obj;
4214 *exc = NULL;
4216 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4217 if (*exc == NULL && !mono_error_ok (&error))
4218 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4219 else
4220 mono_error_cleanup (&error);
4222 if (*exc)
4223 *failure = TRUE;
4225 return array;
4228 static MonoObject*
4229 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4231 MONO_REQ_GC_UNSAFE_MODE;
4233 static MonoMethod *deserialize_method;
4235 MonoError error;
4236 void *params [1];
4237 MonoObject *result;
4239 if (!deserialize_method) {
4240 MonoClass *klass = mono_class_get_remoting_services_class ();
4241 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4243 if (!deserialize_method) {
4244 *failure = TRUE;
4245 return NULL;
4248 params [0] = obj;
4249 *exc = NULL;
4251 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4252 if (*exc == NULL && !mono_error_ok (&error))
4253 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4254 else
4255 mono_error_cleanup (&error);
4257 if (*exc)
4258 *failure = TRUE;
4260 return result;
4263 #ifndef DISABLE_REMOTING
4264 static MonoObject*
4265 make_transparent_proxy (MonoObject *obj, MonoError *error)
4267 MONO_REQ_GC_UNSAFE_MODE;
4269 static MonoMethod *get_proxy_method;
4271 MonoDomain *domain = mono_domain_get ();
4272 MonoRealProxy *real_proxy;
4273 MonoReflectionType *reflection_type;
4274 MonoTransparentProxy *transparent_proxy;
4276 mono_error_init (error);
4278 if (!get_proxy_method)
4279 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4281 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4283 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4284 return_val_if_nok (error, NULL);
4285 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4286 return_val_if_nok (error, NULL);
4288 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4289 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4291 MonoObject *exc = NULL;
4293 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4294 if (exc != NULL && is_ok (error))
4295 mono_error_set_exception_instance (error, (MonoException*)exc);
4297 return (MonoObject*) transparent_proxy;
4299 #endif /* DISABLE_REMOTING */
4302 * mono_object_xdomain_representation
4303 * @obj: an object
4304 * @target_domain: a domain
4305 * @error: set on error.
4307 * Creates a representation of obj in the domain target_domain. This
4308 * is either a copy of obj arrived through via serialization and
4309 * deserialization or a proxy, depending on whether the object is
4310 * serializable or marshal by ref. obj must not be in target_domain.
4312 * If the object cannot be represented in target_domain, NULL is
4313 * returned and @error is set appropriately.
4315 MonoObject*
4316 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4318 MONO_REQ_GC_UNSAFE_MODE;
4320 mono_error_init (error);
4321 MonoObject *deserialized = NULL;
4323 #ifndef DISABLE_REMOTING
4324 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4325 deserialized = make_transparent_proxy (obj, error);
4327 else
4328 #endif
4330 gboolean failure = FALSE;
4331 MonoDomain *domain = mono_domain_get ();
4332 MonoObject *serialized;
4333 MonoObject *exc = NULL;
4335 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4336 serialized = serialize_object (obj, &failure, &exc);
4337 mono_domain_set_internal_with_options (target_domain, FALSE);
4338 if (!failure)
4339 deserialized = deserialize_object (serialized, &failure, &exc);
4340 if (domain != target_domain)
4341 mono_domain_set_internal_with_options (domain, FALSE);
4342 if (failure)
4343 mono_error_set_exception_instance (error, (MonoException*)exc);
4346 return deserialized;
4349 /* Used in call_unhandled_exception_delegate */
4350 static MonoObject *
4351 create_unhandled_exception_eventargs (MonoObject *exc)
4353 MONO_REQ_GC_UNSAFE_MODE;
4355 MonoError error;
4356 MonoClass *klass;
4357 gpointer args [2];
4358 MonoMethod *method = NULL;
4359 MonoBoolean is_terminating = TRUE;
4360 MonoObject *obj;
4362 klass = mono_class_get_unhandled_exception_event_args_class ();
4363 mono_class_init (klass);
4365 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4366 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4367 g_assert (method);
4369 args [0] = exc;
4370 args [1] = &is_terminating;
4372 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4373 mono_error_raise_exception (&error); /* FIXME don't raise here */
4375 mono_runtime_invoke_checked (method, obj, args, &error);
4376 mono_error_raise_exception (&error); /* FIXME don't raise here */
4378 return obj;
4381 /* Used in mono_unhandled_exception */
4382 static void
4383 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4384 MONO_REQ_GC_UNSAFE_MODE;
4386 MonoObject *e = NULL;
4387 gpointer pa [2];
4388 MonoDomain *current_domain = mono_domain_get ();
4390 if (domain != current_domain)
4391 mono_domain_set_internal_with_options (domain, FALSE);
4393 g_assert (domain == mono_object_domain (domain->domain));
4395 if (mono_object_domain (exc) != domain) {
4396 MonoError error;
4398 exc = mono_object_xdomain_representation (exc, domain, &error);
4399 if (!exc) {
4400 if (!is_ok (&error)) {
4401 MonoError inner_error;
4402 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4403 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4404 mono_error_assert_ok (&inner_error);
4405 } else {
4406 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4407 "System.Runtime.Serialization", "SerializationException",
4408 "Could not serialize unhandled exception.");
4412 g_assert (mono_object_domain (exc) == domain);
4414 pa [0] = domain->domain;
4415 pa [1] = create_unhandled_exception_eventargs (exc);
4416 mono_runtime_delegate_invoke (delegate, pa, &e);
4418 if (domain != current_domain)
4419 mono_domain_set_internal_with_options (current_domain, FALSE);
4421 if (e) {
4422 MonoError error;
4423 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4424 if (!mono_error_ok (&error)) {
4425 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4426 mono_error_cleanup (&error);
4427 } else {
4428 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4429 g_free (msg);
4434 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4437 * mono_runtime_unhandled_exception_policy_set:
4438 * @policy: the new policy
4440 * This is a VM internal routine.
4442 * Sets the runtime policy for handling unhandled exceptions.
4444 void
4445 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4446 runtime_unhandled_exception_policy = policy;
4450 * mono_runtime_unhandled_exception_policy_get:
4452 * This is a VM internal routine.
4454 * Gets the runtime policy for handling unhandled exceptions.
4456 MonoRuntimeUnhandledExceptionPolicy
4457 mono_runtime_unhandled_exception_policy_get (void) {
4458 return runtime_unhandled_exception_policy;
4462 * mono_unhandled_exception:
4463 * @exc: exception thrown
4465 * This is a VM internal routine.
4467 * We call this function when we detect an unhandled exception
4468 * in the default domain.
4470 * It invokes the * UnhandledException event in AppDomain or prints
4471 * a warning to the console
4473 void
4474 mono_unhandled_exception (MonoObject *exc)
4476 MONO_REQ_GC_UNSAFE_MODE;
4478 MonoError error;
4479 MonoClassField *field;
4480 MonoDomain *current_domain, *root_domain;
4481 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4483 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4484 return;
4486 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4487 g_assert (field);
4489 current_domain = mono_domain_get ();
4490 root_domain = mono_get_root_domain ();
4492 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4493 mono_error_raise_exception (&error); /* FIXME don't raise here */
4494 if (current_domain != root_domain) {
4495 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4496 mono_error_raise_exception (&error); /* FIXME don't raise here */
4499 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4500 mono_print_unhandled_exception (exc);
4501 } else {
4502 if (root_appdomain_delegate)
4503 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4504 if (current_appdomain_delegate)
4505 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4508 /* set exitcode only if we will abort the process */
4509 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4510 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4512 mono_environment_exitcode_set (1);
4517 * mono_runtime_exec_managed_code:
4518 * @domain: Application domain
4519 * @main_func: function to invoke from the execution thread
4520 * @main_args: parameter to the main_func
4522 * Launch a new thread to execute a function
4524 * main_func is called back from the thread with main_args as the
4525 * parameter. The callback function is expected to start Main()
4526 * eventually. This function then waits for all managed threads to
4527 * finish.
4528 * It is not necesseray anymore to execute managed code in a subthread,
4529 * so this function should not be used anymore by default: just
4530 * execute the code and then call mono_thread_manage ().
4532 void
4533 mono_runtime_exec_managed_code (MonoDomain *domain,
4534 MonoMainThreadFunc main_func,
4535 gpointer main_args)
4537 MonoError error;
4538 mono_thread_create_checked (domain, main_func, main_args, &error);
4539 mono_error_assert_ok (&error);
4541 mono_thread_manage ();
4545 * Execute a standard Main() method (args doesn't contain the
4546 * executable name).
4549 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4551 MONO_REQ_GC_UNSAFE_MODE;
4553 MonoError error;
4554 MonoDomain *domain;
4555 gpointer pa [1];
4556 int rval;
4557 MonoCustomAttrInfo* cinfo;
4558 gboolean has_stathread_attribute;
4559 MonoInternalThread* thread = mono_thread_internal_current ();
4561 g_assert (args);
4563 pa [0] = args;
4565 domain = mono_object_domain (args);
4566 if (!domain->entry_assembly) {
4567 gchar *str;
4568 MonoAssembly *assembly;
4570 assembly = method->klass->image->assembly;
4571 domain->entry_assembly = assembly;
4572 /* Domains created from another domain already have application_base and configuration_file set */
4573 if (domain->setup->application_base == NULL) {
4574 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4577 if (domain->setup->configuration_file == NULL) {
4578 str = g_strconcat (assembly->image->name, ".config", NULL);
4579 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4580 g_free (str);
4581 mono_domain_set_options_from_config (domain);
4585 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4586 mono_error_cleanup (&error); /* FIXME warn here? */
4587 if (cinfo) {
4588 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4589 if (!cinfo->cached)
4590 mono_custom_attrs_free (cinfo);
4591 } else {
4592 has_stathread_attribute = FALSE;
4594 if (has_stathread_attribute) {
4595 thread->apartment_state = ThreadApartmentState_STA;
4596 } else {
4597 thread->apartment_state = ThreadApartmentState_MTA;
4599 mono_thread_init_apartment_state ();
4601 /* FIXME: check signature of method */
4602 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4603 MonoObject *res;
4604 if (exc) {
4605 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4606 if (*exc == NULL && !mono_error_ok (&error))
4607 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4608 else
4609 mono_error_cleanup (&error);
4610 } else {
4611 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4612 mono_error_raise_exception (&error); /* FIXME don't raise here */
4615 if (!exc || !*exc)
4616 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4617 else
4618 rval = -1;
4620 mono_environment_exitcode_set (rval);
4621 } else {
4622 if (exc) {
4623 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4624 if (*exc == NULL && !mono_error_ok (&error))
4625 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4626 else
4627 mono_error_cleanup (&error);
4628 } else {
4629 mono_runtime_invoke_checked (method, NULL, pa, &error);
4630 mono_error_raise_exception (&error); /* FIXME don't raise here */
4633 if (!exc || !*exc)
4634 rval = 0;
4635 else {
4636 /* If the return type of Main is void, only
4637 * set the exitcode if an exception was thrown
4638 * (we don't want to blow away an
4639 * explicitly-set exit code)
4641 rval = -1;
4642 mono_environment_exitcode_set (rval);
4646 return rval;
4650 * mono_runtime_invoke_array:
4651 * @method: method to invoke
4652 * @obJ: object instance
4653 * @params: arguments to the method
4654 * @exc: exception information.
4656 * Invokes the method represented by @method on the object @obj.
4658 * obj is the 'this' pointer, it should be NULL for static
4659 * methods, a MonoObject* for object instances and a pointer to
4660 * the value type for value types.
4662 * The params array contains the arguments to the method with the
4663 * same convention: MonoObject* pointers for object instances and
4664 * pointers to the value type otherwise. The _invoke_array
4665 * variant takes a C# object[] as the params argument (MonoArray
4666 * *params): in this case the value types are boxed inside the
4667 * respective reference representation.
4669 * From unmanaged code you'll usually use the
4670 * mono_runtime_invoke_checked() variant.
4672 * Note that this function doesn't handle virtual methods for
4673 * you, it will exec the exact method you pass: we still need to
4674 * expose a function to lookup the derived class implementation
4675 * of a virtual method (there are examples of this in the code,
4676 * though).
4678 * You can pass NULL as the exc argument if you don't want to
4679 * catch exceptions, otherwise, *exc will be set to the exception
4680 * thrown, if any. if an exception is thrown, you can't use the
4681 * MonoObject* result from the function.
4683 * If the method returns a value type, it is boxed in an object
4684 * reference.
4686 MonoObject*
4687 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4688 MonoObject **exc)
4690 MONO_REQ_GC_UNSAFE_MODE;
4692 MonoError error;
4693 MonoMethodSignature *sig = mono_method_signature (method);
4694 gpointer *pa = NULL;
4695 MonoObject *res;
4696 int i;
4697 gboolean has_byref_nullables = FALSE;
4699 if (NULL != params) {
4700 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4701 for (i = 0; i < mono_array_length (params); i++) {
4702 MonoType *t = sig->params [i];
4704 again:
4705 switch (t->type) {
4706 case MONO_TYPE_U1:
4707 case MONO_TYPE_I1:
4708 case MONO_TYPE_BOOLEAN:
4709 case MONO_TYPE_U2:
4710 case MONO_TYPE_I2:
4711 case MONO_TYPE_CHAR:
4712 case MONO_TYPE_U:
4713 case MONO_TYPE_I:
4714 case MONO_TYPE_U4:
4715 case MONO_TYPE_I4:
4716 case MONO_TYPE_U8:
4717 case MONO_TYPE_I8:
4718 case MONO_TYPE_R4:
4719 case MONO_TYPE_R8:
4720 case MONO_TYPE_VALUETYPE:
4721 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4722 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4723 pa [i] = mono_array_get (params, MonoObject*, i);
4724 if (t->byref)
4725 has_byref_nullables = TRUE;
4726 } else {
4727 /* MS seems to create the objects if a null is passed in */
4728 if (!mono_array_get (params, MonoObject*, i)) {
4729 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4730 mono_error_raise_exception (&error); /* FIXME don't raise here */
4731 mono_array_setref (params, i, o);
4734 if (t->byref) {
4736 * We can't pass the unboxed vtype byref to the callee, since
4737 * that would mean the callee would be able to modify boxed
4738 * primitive types. So we (and MS) make a copy of the boxed
4739 * object, pass that to the callee, and replace the original
4740 * boxed object in the arg array with the copy.
4742 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4743 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), &error);
4744 mono_error_raise_exception (&error); /* FIXME don't raise here */
4745 mono_array_setref (params, i, copy);
4748 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4750 break;
4751 case MONO_TYPE_STRING:
4752 case MONO_TYPE_OBJECT:
4753 case MONO_TYPE_CLASS:
4754 case MONO_TYPE_ARRAY:
4755 case MONO_TYPE_SZARRAY:
4756 if (t->byref)
4757 pa [i] = mono_array_addr (params, MonoObject*, i);
4758 // FIXME: I need to check this code path
4759 else
4760 pa [i] = mono_array_get (params, MonoObject*, i);
4761 break;
4762 case MONO_TYPE_GENERICINST:
4763 if (t->byref)
4764 t = &t->data.generic_class->container_class->this_arg;
4765 else
4766 t = &t->data.generic_class->container_class->byval_arg;
4767 goto again;
4768 case MONO_TYPE_PTR: {
4769 MonoObject *arg;
4771 /* The argument should be an IntPtr */
4772 arg = mono_array_get (params, MonoObject*, i);
4773 if (arg == NULL) {
4774 pa [i] = NULL;
4775 } else {
4776 g_assert (arg->vtable->klass == mono_defaults.int_class);
4777 pa [i] = ((MonoIntPtr*)arg)->m_value;
4779 break;
4781 default:
4782 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4787 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4788 void *o = obj;
4790 if (mono_class_is_nullable (method->klass)) {
4791 /* Need to create a boxed vtype instead */
4792 g_assert (!obj);
4794 if (!params)
4795 return NULL;
4796 else {
4797 MonoObject *result = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], &error);
4798 mono_error_raise_exception (&error); /* FIXME don't raise here */
4799 return result;
4803 if (!obj) {
4804 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4805 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4806 #ifndef DISABLE_REMOTING
4807 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4808 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4810 #endif
4811 if (method->klass->valuetype)
4812 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4813 else
4814 o = obj;
4815 } else if (method->klass->valuetype) {
4816 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, &error);
4817 mono_error_raise_exception (&error); /* FIXME don't raise here */
4820 if (exc) {
4821 mono_runtime_try_invoke (method, o, pa, exc, &error);
4822 if (*exc == NULL && !mono_error_ok (&error))
4823 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4824 else
4825 mono_error_cleanup (&error);
4826 } else {
4827 mono_runtime_invoke_checked (method, o, pa, &error);
4828 mono_error_raise_exception (&error); /* FIXME don't raise here */
4831 return (MonoObject *)obj;
4832 } else {
4833 if (mono_class_is_nullable (method->klass)) {
4834 MonoObject *nullable;
4836 /* Convert the unboxed vtype into a Nullable structure */
4837 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4838 mono_error_raise_exception (&error); /* FIXME don't raise here */
4840 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, &error);
4841 mono_error_raise_exception (&error); /* FIXME don't raise here */
4842 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
4843 obj = mono_object_unbox (nullable);
4846 /* obj must be already unboxed if needed */
4847 if (exc) {
4848 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4849 if (*exc == NULL && !mono_error_ok (&error))
4850 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4851 else
4852 mono_error_cleanup (&error);
4853 } else {
4854 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4855 mono_error_raise_exception (&error); /* FIXME don't raise here */
4858 if (sig->ret->type == MONO_TYPE_PTR) {
4859 MonoClass *pointer_class;
4860 static MonoMethod *box_method;
4861 void *box_args [2];
4862 MonoObject *box_exc;
4865 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4866 * convert it to a Pointer object.
4868 pointer_class = mono_class_get_pointer_class ();
4869 if (!box_method)
4870 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4872 g_assert (res->vtable->klass == mono_defaults.int_class);
4873 box_args [0] = ((MonoIntPtr*)res)->m_value;
4874 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4875 mono_error_raise_exception (&error); /* FIXME don't raise here */
4877 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4878 g_assert (box_exc == NULL);
4879 mono_error_assert_ok (&error);
4882 if (has_byref_nullables) {
4884 * The runtime invoke wrapper already converted byref nullables back,
4885 * and stored them in pa, we just need to copy them back to the
4886 * managed array.
4888 for (i = 0; i < mono_array_length (params); i++) {
4889 MonoType *t = sig->params [i];
4891 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4892 mono_array_setref (params, i, pa [i]);
4896 return res;
4901 * mono_object_new:
4902 * @klass: the class of the object that we want to create
4904 * Returns: a newly created object whose definition is
4905 * looked up using @klass. This will not invoke any constructors,
4906 * so the consumer of this routine has to invoke any constructors on
4907 * its own to initialize the object.
4909 * It returns NULL on failure.
4911 MonoObject *
4912 mono_object_new (MonoDomain *domain, MonoClass *klass)
4914 MONO_REQ_GC_UNSAFE_MODE;
4916 MonoError error;
4918 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4920 mono_error_cleanup (&error);
4921 return result;
4924 MonoObject *
4925 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4927 MONO_REQ_GC_UNSAFE_MODE;
4929 MonoError error;
4931 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4933 mono_error_set_pending_exception (&error);
4934 return result;
4938 * mono_object_new_checked:
4939 * @klass: the class of the object that we want to create
4940 * @error: set on error
4942 * Returns: a newly created object whose definition is
4943 * looked up using @klass. This will not invoke any constructors,
4944 * so the consumer of this routine has to invoke any constructors on
4945 * its own to initialize the object.
4947 * It returns NULL on failure and sets @error.
4949 MonoObject *
4950 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4952 MONO_REQ_GC_UNSAFE_MODE;
4954 MonoVTable *vtable;
4956 vtable = mono_class_vtable (domain, klass);
4957 g_assert (vtable); /* FIXME don't swallow the error */
4959 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4960 return o;
4964 * mono_object_new_pinned:
4966 * Same as mono_object_new, but the returned object will be pinned.
4967 * For SGEN, these objects will only be freed at appdomain unload.
4969 MonoObject *
4970 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4972 MONO_REQ_GC_UNSAFE_MODE;
4974 MonoVTable *vtable;
4976 mono_error_init (error);
4978 vtable = mono_class_vtable (domain, klass);
4979 g_assert (vtable); /* FIXME don't swallow the error */
4981 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4983 if (G_UNLIKELY (!o))
4984 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4985 else if (G_UNLIKELY (vtable->klass->has_finalize))
4986 mono_object_register_finalizer (o, error);
4988 return o;
4992 * mono_object_new_specific:
4993 * @vtable: the vtable of the object that we want to create
4995 * Returns: A newly created object with class and domain specified
4996 * by @vtable
4998 MonoObject *
4999 mono_object_new_specific (MonoVTable *vtable)
5001 MonoError error;
5002 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5003 mono_error_cleanup (&error);
5005 return o;
5008 MonoObject *
5009 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5011 MONO_REQ_GC_UNSAFE_MODE;
5013 MonoObject *o;
5015 mono_error_init (error);
5017 /* check for is_com_object for COM Interop */
5018 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5020 gpointer pa [1];
5021 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5023 if (im == NULL) {
5024 MonoClass *klass = mono_class_get_activation_services_class ();
5026 if (!klass->inited)
5027 mono_class_init (klass);
5029 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5030 if (!im) {
5031 mono_error_set_not_supported (error, "Linked away.");
5032 return NULL;
5034 vtable->domain->create_proxy_for_type_method = im;
5037 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5038 if (!mono_error_ok (error))
5039 return NULL;
5041 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5042 if (!mono_error_ok (error))
5043 return NULL;
5045 if (o != NULL)
5046 return o;
5049 return mono_object_new_alloc_specific_checked (vtable, error);
5052 MonoObject *
5053 ves_icall_object_new_specific (MonoVTable *vtable)
5055 MonoError error;
5056 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5057 mono_error_set_pending_exception (&error);
5059 return o;
5063 * mono_object_new_alloc_specific:
5064 * @vtable: virtual table for the object.
5066 * This function allocates a new `MonoObject` with the type derived
5067 * from the @vtable information. If the class of this object has a
5068 * finalizer, then the object will be tracked for finalization.
5070 * This method might raise an exception on errors. Use the
5071 * `mono_object_new_fast_checked` method if you want to manually raise
5072 * the exception.
5074 * Returns: the allocated object.
5076 MonoObject *
5077 mono_object_new_alloc_specific (MonoVTable *vtable)
5079 MonoError error;
5080 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5081 mono_error_cleanup (&error);
5083 return o;
5087 * mono_object_new_alloc_specific_checked:
5088 * @vtable: virtual table for the object.
5089 * @error: holds the error return value.
5091 * This function allocates a new `MonoObject` with the type derived
5092 * from the @vtable information. If the class of this object has a
5093 * finalizer, then the object will be tracked for finalization.
5095 * If there is not enough memory, the @error parameter will be set
5096 * and will contain a user-visible message with the amount of bytes
5097 * that were requested.
5099 * Returns: the allocated object, or NULL if there is not enough memory
5102 MonoObject *
5103 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5105 MONO_REQ_GC_UNSAFE_MODE;
5107 MonoObject *o;
5109 mono_error_init (error);
5111 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5113 if (G_UNLIKELY (!o))
5114 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5115 else if (G_UNLIKELY (vtable->klass->has_finalize))
5116 mono_object_register_finalizer (o, error);
5118 return o;
5122 * mono_object_new_fast:
5123 * @vtable: virtual table for the object.
5125 * This function allocates a new `MonoObject` with the type derived
5126 * from the @vtable information. The returned object is not tracked
5127 * for finalization. If your object implements a finalizer, you should
5128 * use `mono_object_new_alloc_specific` instead.
5130 * This method might raise an exception on errors. Use the
5131 * `mono_object_new_fast_checked` method if you want to manually raise
5132 * the exception.
5134 * Returns: the allocated object.
5136 MonoObject*
5137 mono_object_new_fast (MonoVTable *vtable)
5139 MonoError error;
5140 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5141 mono_error_cleanup (&error);
5143 return o;
5147 * mono_object_new_fast_checked:
5148 * @vtable: virtual table for the object.
5149 * @error: holds the error return value.
5151 * This function allocates a new `MonoObject` with the type derived
5152 * from the @vtable information. The returned object is not tracked
5153 * for finalization. If your object implements a finalizer, you should
5154 * use `mono_object_new_alloc_specific_checked` instead.
5156 * If there is not enough memory, the @error parameter will be set
5157 * and will contain a user-visible message with the amount of bytes
5158 * that were requested.
5160 * Returns: the allocated object, or NULL if there is not enough memory
5163 MonoObject*
5164 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5166 MONO_REQ_GC_UNSAFE_MODE;
5168 MonoObject *o;
5170 mono_error_init (error);
5172 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5174 if (G_UNLIKELY (!o))
5175 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5177 return o;
5180 MonoObject *
5181 ves_icall_object_new_fast (MonoVTable *vtable)
5183 MonoError error;
5184 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5185 mono_error_set_pending_exception (&error);
5187 return o;
5190 MonoObject*
5191 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5193 MONO_REQ_GC_UNSAFE_MODE;
5195 MonoObject *o;
5197 mono_error_init (error);
5199 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5201 if (G_UNLIKELY (!o))
5202 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5203 else if (G_UNLIKELY (vtable->klass->has_finalize))
5204 mono_object_register_finalizer (o, error);
5206 return o;
5210 * mono_class_get_allocation_ftn:
5211 * @vtable: vtable
5212 * @for_box: the object will be used for boxing
5213 * @pass_size_in_words:
5215 * Return the allocation function appropriate for the given class.
5218 void*
5219 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5221 MONO_REQ_GC_NEUTRAL_MODE;
5223 *pass_size_in_words = FALSE;
5225 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5226 return ves_icall_object_new_specific;
5228 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5230 return ves_icall_object_new_fast;
5233 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5234 * of the overhead of parameter passing.
5237 *pass_size_in_words = TRUE;
5238 #ifdef GC_REDIRECT_TO_LOCAL
5239 return GC_local_gcj_fast_malloc;
5240 #else
5241 return GC_gcj_fast_malloc;
5242 #endif
5246 return ves_icall_object_new_specific;
5250 * mono_object_new_from_token:
5251 * @image: Context where the type_token is hosted
5252 * @token: a token of the type that we want to create
5254 * Returns: A newly created object whose definition is
5255 * looked up using @token in the @image image
5257 MonoObject *
5258 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5260 MONO_REQ_GC_UNSAFE_MODE;
5262 MonoError error;
5263 MonoObject *result;
5264 MonoClass *klass;
5266 klass = mono_class_get_checked (image, token, &error);
5267 mono_error_assert_ok (&error);
5269 result = mono_object_new_checked (domain, klass, &error);
5271 mono_error_cleanup (&error);
5272 return result;
5278 * mono_object_clone:
5279 * @obj: the object to clone
5281 * Returns: A newly created object who is a shallow copy of @obj
5283 MonoObject *
5284 mono_object_clone (MonoObject *obj)
5286 MonoError error;
5287 MonoObject *o = mono_object_clone_checked (obj, &error);
5288 mono_error_cleanup (&error);
5290 return o;
5293 MonoObject *
5294 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5296 MONO_REQ_GC_UNSAFE_MODE;
5298 MonoObject *o;
5299 int size;
5301 mono_error_init (error);
5303 size = obj->vtable->klass->instance_size;
5305 if (obj->vtable->klass->rank)
5306 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5308 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5310 if (G_UNLIKELY (!o)) {
5311 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5312 return NULL;
5315 /* If the object doesn't contain references this will do a simple memmove. */
5316 mono_gc_wbarrier_object_copy (o, obj);
5318 if (obj->vtable->klass->has_finalize)
5319 mono_object_register_finalizer (o, error);
5320 return o;
5324 * mono_array_full_copy:
5325 * @src: source array to copy
5326 * @dest: destination array
5328 * Copies the content of one array to another with exactly the same type and size.
5330 void
5331 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5333 MONO_REQ_GC_UNSAFE_MODE;
5335 uintptr_t size;
5336 MonoClass *klass = src->obj.vtable->klass;
5338 g_assert (klass == dest->obj.vtable->klass);
5340 size = mono_array_length (src);
5341 g_assert (size == mono_array_length (dest));
5342 size *= mono_array_element_size (klass);
5343 #ifdef HAVE_SGEN_GC
5344 if (klass->element_class->valuetype) {
5345 if (klass->element_class->has_references)
5346 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5347 else
5348 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5349 } else {
5350 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5352 #else
5353 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5354 #endif
5358 * mono_array_clone_in_domain:
5359 * @domain: the domain in which the array will be cloned into
5360 * @array: the array to clone
5361 * @error: set on error
5363 * This routine returns a copy of the array that is hosted on the
5364 * specified MonoDomain. On failure returns NULL and sets @error.
5366 MonoArray*
5367 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5369 MONO_REQ_GC_UNSAFE_MODE;
5371 MonoArray *o;
5372 uintptr_t size, i;
5373 uintptr_t *sizes;
5374 MonoClass *klass = array->obj.vtable->klass;
5376 mono_error_init (error);
5378 if (array->bounds == NULL) {
5379 size = mono_array_length (array);
5380 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5381 return_val_if_nok (error, NULL);
5383 size *= mono_array_element_size (klass);
5384 #ifdef HAVE_SGEN_GC
5385 if (klass->element_class->valuetype) {
5386 if (klass->element_class->has_references)
5387 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5388 else
5389 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5390 } else {
5391 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5393 #else
5394 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5395 #endif
5396 return o;
5399 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5400 size = mono_array_element_size (klass);
5401 for (i = 0; i < klass->rank; ++i) {
5402 sizes [i] = array->bounds [i].length;
5403 size *= array->bounds [i].length;
5404 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5406 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5407 return_val_if_nok (error, NULL);
5408 #ifdef HAVE_SGEN_GC
5409 if (klass->element_class->valuetype) {
5410 if (klass->element_class->has_references)
5411 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5412 else
5413 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5414 } else {
5415 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5417 #else
5418 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5419 #endif
5421 return o;
5425 * mono_array_clone:
5426 * @array: the array to clone
5428 * Returns: A newly created array who is a shallow copy of @array
5430 MonoArray*
5431 mono_array_clone (MonoArray *array)
5433 MONO_REQ_GC_UNSAFE_MODE;
5435 MonoError error;
5436 MonoArray *result = mono_array_clone_checked (array, &error);
5437 mono_error_cleanup (&error);
5438 return result;
5442 * mono_array_clone_checked:
5443 * @array: the array to clone
5444 * @error: set on error
5446 * Returns: A newly created array who is a shallow copy of @array. On
5447 * failure returns NULL and sets @error.
5449 MonoArray*
5450 mono_array_clone_checked (MonoArray *array, MonoError *error)
5453 MONO_REQ_GC_UNSAFE_MODE;
5454 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5457 /* helper macros to check for overflow when calculating the size of arrays */
5458 #ifdef MONO_BIG_ARRAYS
5459 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5460 #define MYGUINT_MAX MYGUINT64_MAX
5461 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5462 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5463 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5464 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5465 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5466 #else
5467 #define MYGUINT32_MAX 4294967295U
5468 #define MYGUINT_MAX MYGUINT32_MAX
5469 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5470 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5471 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5472 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5473 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5474 #endif
5476 gboolean
5477 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5479 MONO_REQ_GC_NEUTRAL_MODE;
5481 uintptr_t byte_len;
5483 byte_len = mono_array_element_size (klass);
5484 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5485 return FALSE;
5486 byte_len *= len;
5487 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5488 return FALSE;
5489 byte_len += MONO_SIZEOF_MONO_ARRAY;
5491 *res = byte_len;
5493 return TRUE;
5497 * mono_array_new_full:
5498 * @domain: domain where the object is created
5499 * @array_class: array class
5500 * @lengths: lengths for each dimension in the array
5501 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5503 * This routine creates a new array objects with the given dimensions,
5504 * lower bounds and type.
5506 MonoArray*
5507 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5509 MonoError error;
5510 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5511 mono_error_cleanup (&error);
5513 return array;
5516 MonoArray*
5517 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5519 MONO_REQ_GC_UNSAFE_MODE;
5521 uintptr_t byte_len = 0, len, bounds_size;
5522 MonoObject *o;
5523 MonoArray *array;
5524 MonoArrayBounds *bounds;
5525 MonoVTable *vtable;
5526 int i;
5528 mono_error_init (error);
5530 if (!array_class->inited)
5531 mono_class_init (array_class);
5533 len = 1;
5535 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5536 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5537 len = lengths [0];
5538 if (len > MONO_ARRAY_MAX_INDEX) {
5539 mono_error_set_generic_error (error, "System", "OverflowException", "");
5540 return NULL;
5542 bounds_size = 0;
5543 } else {
5544 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5546 for (i = 0; i < array_class->rank; ++i) {
5547 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5548 mono_error_set_generic_error (error, "System", "OverflowException", "");
5549 return NULL;
5551 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5552 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5553 return NULL;
5555 len *= lengths [i];
5559 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5560 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5561 return NULL;
5564 if (bounds_size) {
5565 /* align */
5566 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5567 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5568 return NULL;
5570 byte_len = (byte_len + 3) & ~3;
5571 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5572 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5573 return NULL;
5575 byte_len += bounds_size;
5578 * Following three lines almost taken from mono_object_new ():
5579 * they need to be kept in sync.
5581 vtable = mono_class_vtable_full (domain, array_class, error);
5582 return_val_if_nok (error, NULL);
5584 if (bounds_size)
5585 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5586 else
5587 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5589 if (G_UNLIKELY (!o)) {
5590 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5591 return NULL;
5594 array = (MonoArray*)o;
5596 bounds = array->bounds;
5598 if (bounds_size) {
5599 for (i = 0; i < array_class->rank; ++i) {
5600 bounds [i].length = lengths [i];
5601 if (lower_bounds)
5602 bounds [i].lower_bound = lower_bounds [i];
5606 return array;
5610 * mono_array_new:
5611 * @domain: domain where the object is created
5612 * @eclass: element class
5613 * @n: number of array elements
5615 * This routine creates a new szarray with @n elements of type @eclass.
5617 MonoArray *
5618 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5620 MONO_REQ_GC_UNSAFE_MODE;
5622 MonoError error;
5623 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5624 mono_error_cleanup (&error);
5625 return result;
5629 * mono_array_new_checked:
5630 * @domain: domain where the object is created
5631 * @eclass: element class
5632 * @n: number of array elements
5633 * @error: set on error
5635 * This routine creates a new szarray with @n elements of type @eclass.
5636 * On failure returns NULL and sets @error.
5638 MonoArray *
5639 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5641 MonoClass *ac;
5643 mono_error_init (error);
5645 ac = mono_array_class_get (eclass, 1);
5646 g_assert (ac);
5648 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5649 return_val_if_nok (error, NULL);
5651 return mono_array_new_specific_checked (vtable, n, error);
5654 MonoArray*
5655 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5657 MonoError error;
5658 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5659 mono_error_set_pending_exception (&error);
5661 return arr;
5665 * mono_array_new_specific:
5666 * @vtable: a vtable in the appropriate domain for an initialized class
5667 * @n: number of array elements
5669 * This routine is a fast alternative to mono_array_new() for code which
5670 * can be sure about the domain it operates in.
5672 MonoArray *
5673 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5675 MonoError error;
5676 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5677 mono_error_cleanup (&error);
5679 return arr;
5682 MonoArray*
5683 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5685 MONO_REQ_GC_UNSAFE_MODE;
5687 MonoObject *o;
5688 uintptr_t byte_len;
5690 mono_error_init (error);
5692 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5693 mono_error_set_generic_error (error, "System", "OverflowException", "");
5694 return NULL;
5697 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5698 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5699 return NULL;
5701 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5703 if (G_UNLIKELY (!o)) {
5704 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5705 return NULL;
5708 return (MonoArray*)o;
5711 MonoArray*
5712 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5714 MonoError error;
5715 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5716 mono_error_set_pending_exception (&error);
5718 return arr;
5722 * mono_string_new_utf16:
5723 * @text: a pointer to an utf16 string
5724 * @len: the length of the string
5726 * Returns: A newly created string object which contains @text.
5728 MonoString *
5729 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5731 MONO_REQ_GC_UNSAFE_MODE;
5733 MonoError error;
5734 MonoString *res = NULL;
5735 res = mono_string_new_utf16_checked (domain, text, len, &error);
5736 mono_error_cleanup (&error);
5738 return res;
5742 * mono_string_new_utf16_checked:
5743 * @text: a pointer to an utf16 string
5744 * @len: the length of the string
5745 * @error: written on error.
5747 * Returns: A newly created string object which contains @text.
5748 * On error, returns NULL and sets @error.
5750 MonoString *
5751 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5753 MONO_REQ_GC_UNSAFE_MODE;
5755 MonoString *s;
5757 mono_error_init (error);
5759 s = mono_string_new_size_checked (domain, len, error);
5760 if (s != NULL)
5761 memcpy (mono_string_chars (s), text, len * 2);
5763 return s;
5767 * mono_string_new_utf32:
5768 * @text: a pointer to an utf32 string
5769 * @len: the length of the string
5770 * @error: set on failure.
5772 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5774 static MonoString *
5775 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5777 MONO_REQ_GC_UNSAFE_MODE;
5779 MonoString *s;
5780 mono_unichar2 *utf16_output = NULL;
5781 gint32 utf16_len = 0;
5782 GError *gerror = NULL;
5783 glong items_written;
5785 mono_error_init (error);
5786 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5788 if (gerror)
5789 g_error_free (gerror);
5791 while (utf16_output [utf16_len]) utf16_len++;
5793 s = mono_string_new_size_checked (domain, utf16_len, error);
5794 return_val_if_nok (error, NULL);
5796 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5798 g_free (utf16_output);
5800 return s;
5804 * mono_string_new_utf32:
5805 * @text: a pointer to an utf32 string
5806 * @len: the length of the string
5808 * Returns: A newly created string object which contains @text.
5810 MonoString *
5811 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5813 MonoError error;
5814 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
5815 mono_error_cleanup (&error);
5816 return result;
5820 * mono_string_new_size:
5821 * @text: a pointer to an utf16 string
5822 * @len: the length of the string
5824 * Returns: A newly created string object of @len
5826 MonoString *
5827 mono_string_new_size (MonoDomain *domain, gint32 len)
5829 MonoError error;
5830 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5831 mono_error_cleanup (&error);
5833 return str;
5836 MonoString *
5837 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5839 MONO_REQ_GC_UNSAFE_MODE;
5841 MonoString *s;
5842 MonoVTable *vtable;
5843 size_t size;
5845 mono_error_init (error);
5847 /* check for overflow */
5848 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5849 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5850 return NULL;
5853 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5854 g_assert (size > 0);
5856 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5857 g_assert (vtable);
5859 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5861 if (G_UNLIKELY (!s)) {
5862 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5863 return NULL;
5866 return s;
5870 * mono_string_new_len:
5871 * @text: a pointer to an utf8 string
5872 * @length: number of bytes in @text to consider
5874 * Returns: A newly created string object which contains @text.
5876 MonoString*
5877 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5879 MONO_REQ_GC_UNSAFE_MODE;
5881 MonoError error;
5882 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
5883 mono_error_cleanup (&error);
5884 return result;
5888 * mono_string_new_len_checked:
5889 * @text: a pointer to an utf8 string
5890 * @length: number of bytes in @text to consider
5891 * @error: set on error
5893 * Returns: A newly created string object which contains @text. On
5894 * failure returns NULL and sets @error.
5896 MonoString*
5897 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
5899 MONO_REQ_GC_UNSAFE_MODE;
5901 mono_error_init (error);
5903 GError *eg_error = NULL;
5904 MonoString *o = NULL;
5905 guint16 *ut = NULL;
5906 glong items_written;
5908 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5910 if (!eg_error)
5911 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5912 else
5913 g_error_free (eg_error);
5915 g_free (ut);
5917 return o;
5921 * mono_string_new:
5922 * @text: a pointer to an utf8 string
5924 * Returns: A newly created string object which contains @text.
5926 * This function asserts if it cannot allocate a new string.
5928 * @deprecated Use mono_string_new_checked in new code.
5930 MonoString*
5931 mono_string_new (MonoDomain *domain, const char *text)
5933 MonoError error;
5934 MonoString *res = NULL;
5935 res = mono_string_new_checked (domain, text, &error);
5936 mono_error_assert_ok (&error);
5937 return res;
5941 * mono_string_new_checked:
5942 * @text: a pointer to an utf8 string
5943 * @merror: set on error
5945 * Returns: A newly created string object which contains @text.
5946 * On error returns NULL and sets @merror.
5948 MonoString*
5949 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5951 MONO_REQ_GC_UNSAFE_MODE;
5953 GError *eg_error = NULL;
5954 MonoString *o = NULL;
5955 guint16 *ut;
5956 glong items_written;
5957 int l;
5959 mono_error_init (error);
5961 l = strlen (text);
5963 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5965 if (!eg_error)
5966 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5967 else
5968 g_error_free (eg_error);
5970 g_free (ut);
5972 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5973 #if 0
5974 gunichar2 *str;
5975 const gchar *end;
5976 int len;
5977 MonoString *o = NULL;
5979 if (!g_utf8_validate (text, -1, &end)) {
5980 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5981 goto leave;
5984 len = g_utf8_strlen (text, -1);
5985 o = mono_string_new_size_checked (domain, len, error);
5986 if (!o)
5987 goto leave;
5988 str = mono_string_chars (o);
5990 while (text < end) {
5991 *str++ = g_utf8_get_char (text);
5992 text = g_utf8_next_char (text);
5995 leave:
5996 #endif
5997 return o;
6001 * mono_string_new_wrapper:
6002 * @text: pointer to utf8 characters.
6004 * Helper function to create a string object from @text in the current domain.
6006 MonoString*
6007 mono_string_new_wrapper (const char *text)
6009 MONO_REQ_GC_UNSAFE_MODE;
6011 MonoDomain *domain = mono_domain_get ();
6013 if (text)
6014 return mono_string_new (domain, text);
6016 return NULL;
6020 * mono_value_box:
6021 * @class: the class of the value
6022 * @value: a pointer to the unboxed data
6024 * Returns: A newly created object which contains @value.
6026 MonoObject *
6027 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6029 MonoError error;
6030 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6031 mono_error_cleanup (&error);
6032 return result;
6036 * mono_value_box_checked:
6037 * @domain: the domain of the new object
6038 * @class: the class of the value
6039 * @value: a pointer to the unboxed data
6040 * @error: set on error
6042 * Returns: A newly created object which contains @value. On failure
6043 * returns NULL and sets @error.
6045 MonoObject *
6046 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6048 MONO_REQ_GC_UNSAFE_MODE;
6049 MonoObject *res;
6050 int size;
6051 MonoVTable *vtable;
6053 mono_error_init (error);
6055 g_assert (klass->valuetype);
6056 if (mono_class_is_nullable (klass))
6057 return mono_nullable_box ((guint8 *)value, klass, error);
6059 vtable = mono_class_vtable (domain, klass);
6060 if (!vtable)
6061 return NULL;
6062 size = mono_class_instance_size (klass);
6063 res = mono_object_new_alloc_specific_checked (vtable, error);
6064 return_val_if_nok (error, NULL);
6066 size = size - sizeof (MonoObject);
6068 #ifdef HAVE_SGEN_GC
6069 g_assert (size == mono_class_value_size (klass, NULL));
6070 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6071 #else
6072 #if NO_UNALIGNED_ACCESS
6073 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6074 #else
6075 switch (size) {
6076 case 1:
6077 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6078 break;
6079 case 2:
6080 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6081 break;
6082 case 4:
6083 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6084 break;
6085 case 8:
6086 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6087 break;
6088 default:
6089 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6091 #endif
6092 #endif
6093 if (klass->has_finalize) {
6094 mono_object_register_finalizer (res, error);
6095 return_val_if_nok (error, NULL);
6097 return res;
6101 * mono_value_copy:
6102 * @dest: destination pointer
6103 * @src: source pointer
6104 * @klass: a valuetype class
6106 * Copy a valuetype from @src to @dest. This function must be used
6107 * when @klass contains references fields.
6109 void
6110 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6112 MONO_REQ_GC_UNSAFE_MODE;
6114 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6118 * mono_value_copy_array:
6119 * @dest: destination array
6120 * @dest_idx: index in the @dest array
6121 * @src: source pointer
6122 * @count: number of items
6124 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6125 * This function must be used when @klass contains references fields.
6126 * Overlap is handled.
6128 void
6129 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6131 MONO_REQ_GC_UNSAFE_MODE;
6133 int size = mono_array_element_size (dest->obj.vtable->klass);
6134 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6135 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6136 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6140 * mono_object_get_domain:
6141 * @obj: object to query
6143 * Returns: the MonoDomain where the object is hosted
6145 MonoDomain*
6146 mono_object_get_domain (MonoObject *obj)
6148 MONO_REQ_GC_UNSAFE_MODE;
6150 return mono_object_domain (obj);
6154 * mono_object_get_class:
6155 * @obj: object to query
6157 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6159 * Returns: the MonoClass of the object.
6161 MonoClass*
6162 mono_object_get_class (MonoObject *obj)
6164 MONO_REQ_GC_UNSAFE_MODE;
6166 return mono_object_class (obj);
6169 * mono_object_get_size:
6170 * @o: object to query
6172 * Returns: the size, in bytes, of @o
6174 guint
6175 mono_object_get_size (MonoObject* o)
6177 MONO_REQ_GC_UNSAFE_MODE;
6179 MonoClass* klass = mono_object_class (o);
6180 if (klass == mono_defaults.string_class) {
6181 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6182 } else if (o->vtable->rank) {
6183 MonoArray *array = (MonoArray*)o;
6184 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6185 if (array->bounds) {
6186 size += 3;
6187 size &= ~3;
6188 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6190 return size;
6191 } else {
6192 return mono_class_instance_size (klass);
6197 * mono_object_unbox:
6198 * @obj: object to unbox
6200 * Returns: a pointer to the start of the valuetype boxed in this
6201 * object.
6203 * This method will assert if the object passed is not a valuetype.
6205 gpointer
6206 mono_object_unbox (MonoObject *obj)
6208 MONO_REQ_GC_UNSAFE_MODE;
6210 /* add assert for valuetypes? */
6211 g_assert (obj->vtable->klass->valuetype);
6212 return ((char*)obj) + sizeof (MonoObject);
6216 * mono_object_isinst:
6217 * @obj: an object
6218 * @klass: a pointer to a class
6220 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6222 MonoObject *
6223 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6225 MONO_REQ_GC_UNSAFE_MODE;
6227 MonoError error;
6228 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6229 mono_error_cleanup (&error);
6230 return result;
6235 * mono_object_isinst_checked:
6236 * @obj: an object
6237 * @klass: a pointer to a class
6238 * @error: set on error
6240 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6241 * On failure returns NULL and sets @error.
6243 MonoObject *
6244 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6246 MONO_REQ_GC_UNSAFE_MODE;
6248 mono_error_init (error);
6250 MonoObject *result = NULL;
6252 if (!klass->inited)
6253 mono_class_init (klass);
6255 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6256 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6257 return result;
6260 if (!obj)
6261 return NULL;
6263 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6266 MonoObject *
6267 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6269 MONO_REQ_GC_UNSAFE_MODE;
6271 MonoError error;
6272 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6273 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6274 return result;
6277 MonoObject *
6278 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6280 MONO_REQ_GC_UNSAFE_MODE;
6282 MonoVTable *vt;
6284 mono_error_init (error);
6286 if (!obj)
6287 return NULL;
6289 vt = obj->vtable;
6291 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6292 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6293 return obj;
6296 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6297 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6298 return obj;
6299 } else {
6300 MonoClass *oklass = vt->klass;
6301 if (mono_class_is_transparent_proxy (oklass))
6302 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6304 mono_class_setup_supertypes (klass);
6305 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6306 return obj;
6308 #ifndef DISABLE_REMOTING
6309 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6311 MonoDomain *domain = mono_domain_get ();
6312 MonoObject *res;
6313 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6314 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6315 MonoMethod *im = NULL;
6316 gpointer pa [2];
6318 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6319 if (!im) {
6320 mono_error_set_not_supported (error, "Linked away.");
6321 return NULL;
6323 im = mono_object_get_virtual_method (rp, im);
6324 g_assert (im);
6326 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6327 return_val_if_nok (error, NULL);
6328 pa [1] = obj;
6330 res = mono_runtime_invoke_checked (im, rp, pa, error);
6331 return_val_if_nok (error, NULL);
6333 if (*(MonoBoolean *) mono_object_unbox(res)) {
6334 /* Update the vtable of the remote type, so it can safely cast to this new type */
6335 mono_upgrade_remote_class (domain, obj, klass);
6336 return obj;
6339 #endif /* DISABLE_REMOTING */
6340 return NULL;
6344 * mono_object_castclass_mbyref:
6345 * @obj: an object
6346 * @klass: a pointer to a class
6348 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6350 MonoObject *
6351 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6353 MONO_REQ_GC_UNSAFE_MODE;
6354 MonoError error;
6356 if (!obj) return NULL;
6357 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6358 mono_error_cleanup (&error);
6359 return NULL;
6362 typedef struct {
6363 MonoDomain *orig_domain;
6364 MonoString *ins;
6365 MonoString *res;
6366 } LDStrInfo;
6368 static void
6369 str_lookup (MonoDomain *domain, gpointer user_data)
6371 MONO_REQ_GC_UNSAFE_MODE;
6373 LDStrInfo *info = (LDStrInfo *)user_data;
6374 if (info->res || domain == info->orig_domain)
6375 return;
6376 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6379 static MonoString*
6380 mono_string_get_pinned (MonoString *str, MonoError *error)
6382 MONO_REQ_GC_UNSAFE_MODE;
6384 mono_error_init (error);
6386 /* We only need to make a pinned version of a string if this is a moving GC */
6387 if (!mono_gc_is_moving ())
6388 return str;
6389 int size;
6390 MonoString *news;
6391 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6392 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6393 if (news) {
6394 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6395 news->length = mono_string_length (str);
6396 } else {
6397 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6399 return news;
6402 static MonoString*
6403 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6405 MONO_REQ_GC_UNSAFE_MODE;
6407 MonoGHashTable *ldstr_table;
6408 MonoString *s, *res;
6409 MonoDomain *domain;
6411 mono_error_init (error);
6413 domain = ((MonoObject *)str)->vtable->domain;
6414 ldstr_table = domain->ldstr_table;
6415 ldstr_lock ();
6416 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6417 if (res) {
6418 ldstr_unlock ();
6419 return res;
6421 if (insert) {
6422 /* Allocate outside the lock */
6423 ldstr_unlock ();
6424 s = mono_string_get_pinned (str, error);
6425 return_val_if_nok (error, NULL);
6426 if (s) {
6427 ldstr_lock ();
6428 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6429 if (res) {
6430 ldstr_unlock ();
6431 return res;
6433 mono_g_hash_table_insert (ldstr_table, s, s);
6434 ldstr_unlock ();
6436 return s;
6437 } else {
6438 LDStrInfo ldstr_info;
6439 ldstr_info.orig_domain = domain;
6440 ldstr_info.ins = str;
6441 ldstr_info.res = NULL;
6443 mono_domain_foreach (str_lookup, &ldstr_info);
6444 if (ldstr_info.res) {
6446 * the string was already interned in some other domain:
6447 * intern it in the current one as well.
6449 mono_g_hash_table_insert (ldstr_table, str, str);
6450 ldstr_unlock ();
6451 return str;
6454 ldstr_unlock ();
6455 return NULL;
6459 * mono_string_is_interned:
6460 * @o: String to probe
6462 * Returns whether the string has been interned.
6464 MonoString*
6465 mono_string_is_interned (MonoString *o)
6467 MonoError error;
6468 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6469 /* This function does not fail. */
6470 mono_error_assert_ok (&error);
6471 return result;
6475 * mono_string_intern:
6476 * @o: String to intern
6478 * Interns the string passed.
6479 * Returns: The interned string.
6481 MonoString*
6482 mono_string_intern (MonoString *str)
6484 MonoError error;
6485 MonoString *result = mono_string_intern_checked (str, &error);
6486 mono_error_assert_ok (&error);
6487 return result;
6491 * mono_string_intern_checked:
6492 * @o: String to intern
6493 * @error: set on error.
6495 * Interns the string passed.
6496 * Returns: The interned string. On failure returns NULL and sets @error
6498 MonoString*
6499 mono_string_intern_checked (MonoString *str, MonoError *error)
6501 MONO_REQ_GC_UNSAFE_MODE;
6503 mono_error_init (error);
6505 return mono_string_is_interned_lookup (str, TRUE, error);
6509 * mono_ldstr:
6510 * @domain: the domain where the string will be used.
6511 * @image: a metadata context
6512 * @idx: index into the user string table.
6514 * Implementation for the ldstr opcode.
6515 * Returns: a loaded string from the @image/@idx combination.
6517 MonoString*
6518 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6520 MonoError error;
6521 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6522 mono_error_cleanup (&error);
6523 return result;
6527 * mono_ldstr_checked:
6528 * @domain: the domain where the string will be used.
6529 * @image: a metadata context
6530 * @idx: index into the user string table.
6531 * @error: set on error.
6533 * Implementation for the ldstr opcode.
6534 * Returns: a loaded string from the @image/@idx combination.
6535 * On failure returns NULL and sets @error.
6537 MonoString*
6538 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6540 MONO_REQ_GC_UNSAFE_MODE;
6541 mono_error_init (error);
6543 if (image->dynamic) {
6544 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6545 return str;
6546 } else {
6547 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6548 return NULL; /*FIXME we should probably be raising an exception here*/
6549 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6550 return str;
6555 * mono_ldstr_metadata_sig
6556 * @domain: the domain for the string
6557 * @sig: the signature of a metadata string
6558 * @error: set on error
6560 * Returns: a MonoString for a string stored in the metadata. On
6561 * failure returns NULL and sets @error.
6563 static MonoString*
6564 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6566 MONO_REQ_GC_UNSAFE_MODE;
6568 mono_error_init (error);
6569 const char *str = sig;
6570 MonoString *o, *interned;
6571 size_t len2;
6573 len2 = mono_metadata_decode_blob_size (str, &str);
6574 len2 >>= 1;
6576 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6577 return_val_if_nok (error, NULL);
6578 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6580 int i;
6581 guint16 *p2 = (guint16*)mono_string_chars (o);
6582 for (i = 0; i < len2; ++i) {
6583 *p2 = GUINT16_FROM_LE (*p2);
6584 ++p2;
6587 #endif
6588 ldstr_lock ();
6589 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6590 ldstr_unlock ();
6591 if (interned)
6592 return interned; /* o will get garbage collected */
6594 o = mono_string_get_pinned (o, error);
6595 if (o) {
6596 ldstr_lock ();
6597 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6598 if (!interned) {
6599 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6600 interned = o;
6602 ldstr_unlock ();
6605 return interned;
6609 * mono_string_to_utf8:
6610 * @s: a System.String
6612 * Returns the UTF8 representation for @s.
6613 * The resulting buffer needs to be freed with mono_free().
6615 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6617 char *
6618 mono_string_to_utf8 (MonoString *s)
6620 MONO_REQ_GC_UNSAFE_MODE;
6622 MonoError error;
6623 char *result = mono_string_to_utf8_checked (s, &error);
6625 if (!mono_error_ok (&error))
6626 mono_error_raise_exception (&error);
6627 return result;
6631 * mono_string_to_utf8_checked:
6632 * @s: a System.String
6633 * @error: a MonoError.
6635 * Converts a MonoString to its UTF8 representation. May fail; check
6636 * @error to determine whether the conversion was successful.
6637 * The resulting buffer should be freed with mono_free().
6639 char *
6640 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6642 MONO_REQ_GC_UNSAFE_MODE;
6644 long written = 0;
6645 char *as;
6646 GError *gerror = NULL;
6648 mono_error_init (error);
6650 if (s == NULL)
6651 return NULL;
6653 if (!s->length)
6654 return g_strdup ("");
6656 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6657 if (gerror) {
6658 mono_error_set_argument (error, "string", "%s", gerror->message);
6659 g_error_free (gerror);
6660 return NULL;
6662 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6663 if (s->length > written) {
6664 /* allocate the total length and copy the part of the string that has been converted */
6665 char *as2 = (char *)g_malloc0 (s->length);
6666 memcpy (as2, as, written);
6667 g_free (as);
6668 as = as2;
6671 return as;
6675 * mono_string_to_utf8_ignore:
6676 * @s: a MonoString
6678 * Converts a MonoString to its UTF8 representation. Will ignore
6679 * invalid surrogate pairs.
6680 * The resulting buffer should be freed with mono_free().
6683 char *
6684 mono_string_to_utf8_ignore (MonoString *s)
6686 MONO_REQ_GC_UNSAFE_MODE;
6688 long written = 0;
6689 char *as;
6691 if (s == NULL)
6692 return NULL;
6694 if (!s->length)
6695 return g_strdup ("");
6697 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6699 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6700 if (s->length > written) {
6701 /* allocate the total length and copy the part of the string that has been converted */
6702 char *as2 = (char *)g_malloc0 (s->length);
6703 memcpy (as2, as, written);
6704 g_free (as);
6705 as = as2;
6708 return as;
6712 * mono_string_to_utf8_image_ignore:
6713 * @s: a System.String
6715 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6717 char *
6718 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6720 MONO_REQ_GC_UNSAFE_MODE;
6722 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6726 * mono_string_to_utf8_mp_ignore:
6727 * @s: a System.String
6729 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6731 char *
6732 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6734 MONO_REQ_GC_UNSAFE_MODE;
6736 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6741 * mono_string_to_utf16:
6742 * @s: a MonoString
6744 * Return an null-terminated array of the utf-16 chars
6745 * contained in @s. The result must be freed with g_free().
6746 * This is a temporary helper until our string implementation
6747 * is reworked to always include the null terminating char.
6749 mono_unichar2*
6750 mono_string_to_utf16 (MonoString *s)
6752 MONO_REQ_GC_UNSAFE_MODE;
6754 char *as;
6756 if (s == NULL)
6757 return NULL;
6759 as = (char *)g_malloc ((s->length * 2) + 2);
6760 as [(s->length * 2)] = '\0';
6761 as [(s->length * 2) + 1] = '\0';
6763 if (!s->length) {
6764 return (gunichar2 *)(as);
6767 memcpy (as, mono_string_chars(s), s->length * 2);
6768 return (gunichar2 *)(as);
6772 * mono_string_to_utf32:
6773 * @s: a MonoString
6775 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6776 * contained in @s. The result must be freed with g_free().
6778 mono_unichar4*
6779 mono_string_to_utf32 (MonoString *s)
6781 MONO_REQ_GC_UNSAFE_MODE;
6783 mono_unichar4 *utf32_output = NULL;
6784 GError *error = NULL;
6785 glong items_written;
6787 if (s == NULL)
6788 return NULL;
6790 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6792 if (error)
6793 g_error_free (error);
6795 return utf32_output;
6799 * mono_string_from_utf16:
6800 * @data: the UTF16 string (LPWSTR) to convert
6802 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6804 * Returns: a MonoString.
6806 MonoString *
6807 mono_string_from_utf16 (gunichar2 *data)
6809 MonoError error;
6810 MonoString *result = mono_string_from_utf16_checked (data, &error);
6811 mono_error_cleanup (&error);
6812 return result;
6816 * mono_string_from_utf16_checked:
6817 * @data: the UTF16 string (LPWSTR) to convert
6818 * @error: set on error
6820 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6822 * Returns: a MonoString. On failure sets @error and returns NULL.
6824 MonoString *
6825 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
6828 MONO_REQ_GC_UNSAFE_MODE;
6830 mono_error_init (error);
6831 MonoDomain *domain = mono_domain_get ();
6832 int len = 0;
6834 if (!data)
6835 return NULL;
6837 while (data [len]) len++;
6839 return mono_string_new_utf16_checked (domain, data, len, error);
6843 * mono_string_from_utf32:
6844 * @data: the UTF32 string (LPWSTR) to convert
6846 * Converts a UTF32 (UCS-4)to a MonoString.
6848 * Returns: a MonoString.
6850 MonoString *
6851 mono_string_from_utf32 (mono_unichar4 *data)
6853 MonoError error;
6854 MonoString *result = mono_string_from_utf32_checked (data, &error);
6855 mono_error_cleanup (&error);
6856 return result;
6860 * mono_string_from_utf32_checked:
6861 * @data: the UTF32 string (LPWSTR) to convert
6862 * @error: set on error
6864 * Converts a UTF32 (UCS-4)to a MonoString.
6866 * Returns: a MonoString. On failure returns NULL and sets @error.
6868 MonoString *
6869 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
6871 MONO_REQ_GC_UNSAFE_MODE;
6873 mono_error_init (error);
6874 MonoString* result = NULL;
6875 mono_unichar2 *utf16_output = NULL;
6876 GError *gerror = NULL;
6877 glong items_written;
6878 int len = 0;
6880 if (!data)
6881 return NULL;
6883 while (data [len]) len++;
6885 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
6887 if (gerror)
6888 g_error_free (gerror);
6890 result = mono_string_from_utf16_checked (utf16_output, error);
6891 g_free (utf16_output);
6892 return result;
6895 static char *
6896 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6898 MONO_REQ_GC_UNSAFE_MODE;
6900 char *r;
6901 char *mp_s;
6902 int len;
6904 if (ignore_error) {
6905 r = mono_string_to_utf8_ignore (s);
6906 } else {
6907 r = mono_string_to_utf8_checked (s, error);
6908 if (!mono_error_ok (error))
6909 return NULL;
6912 if (!mp && !image)
6913 return r;
6915 len = strlen (r) + 1;
6916 if (mp)
6917 mp_s = (char *)mono_mempool_alloc (mp, len);
6918 else
6919 mp_s = (char *)mono_image_alloc (image, len);
6921 memcpy (mp_s, r, len);
6923 g_free (r);
6925 return mp_s;
6929 * mono_string_to_utf8_image:
6930 * @s: a System.String
6932 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6934 char *
6935 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6937 MONO_REQ_GC_UNSAFE_MODE;
6939 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6943 * mono_string_to_utf8_mp:
6944 * @s: a System.String
6946 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6948 char *
6949 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6951 MONO_REQ_GC_UNSAFE_MODE;
6953 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6957 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6959 void
6960 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6962 eh_callbacks = *cbs;
6965 MonoRuntimeExceptionHandlingCallbacks *
6966 mono_get_eh_callbacks (void)
6968 return &eh_callbacks;
6972 * mono_raise_exception:
6973 * @ex: exception object
6975 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6977 void
6978 mono_raise_exception (MonoException *ex)
6980 MONO_REQ_GC_UNSAFE_MODE;
6983 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6984 * that will cause gcc to omit the function epilog, causing problems when
6985 * the JIT tries to walk the stack, since the return address on the stack
6986 * will point into the next function in the executable, not this one.
6988 eh_callbacks.mono_raise_exception (ex);
6991 void
6992 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6994 MONO_REQ_GC_UNSAFE_MODE;
6996 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7000 * mono_wait_handle_new:
7001 * @domain: Domain where the object will be created
7002 * @handle: Handle for the wait handle
7003 * @error: set on error.
7005 * Returns: A new MonoWaitHandle created in the given domain for the
7006 * given handle. On failure returns NULL and sets @rror.
7008 MonoWaitHandle *
7009 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7011 MONO_REQ_GC_UNSAFE_MODE;
7013 MonoWaitHandle *res;
7014 gpointer params [1];
7015 static MonoMethod *handle_set;
7017 mono_error_init (error);
7018 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7019 return_val_if_nok (error, NULL);
7021 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7022 if (!handle_set)
7023 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7025 params [0] = &handle;
7027 mono_runtime_invoke_checked (handle_set, res, params, error);
7028 return res;
7031 HANDLE
7032 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7034 MONO_REQ_GC_UNSAFE_MODE;
7036 static MonoClassField *f_safe_handle = NULL;
7037 MonoSafeHandle *sh;
7039 if (!f_safe_handle) {
7040 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7041 g_assert (f_safe_handle);
7044 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7045 return sh->handle;
7049 static MonoObject*
7050 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7052 MONO_REQ_GC_UNSAFE_MODE;
7054 RuntimeInvokeFunction runtime_invoke;
7056 mono_error_init (error);
7058 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7059 MonoMethod *method = mono_get_context_capture_method ();
7060 MonoMethod *wrapper;
7061 if (!method)
7062 return NULL;
7063 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7064 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7065 return_val_if_nok (error, NULL);
7066 domain->capture_context_method = mono_compile_method_checked (method, error);
7067 return_val_if_nok (error, NULL);
7070 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7072 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7075 * mono_async_result_new:
7076 * @domain:domain where the object will be created.
7077 * @handle: wait handle.
7078 * @state: state to pass to AsyncResult
7079 * @data: C closure data.
7080 * @error: set on error.
7082 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7083 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7084 * On failure returns NULL and sets @error.
7087 MonoAsyncResult *
7088 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7090 MONO_REQ_GC_UNSAFE_MODE;
7092 mono_error_init (error);
7093 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7094 return_val_if_nok (error, NULL);
7095 MonoObject *context = mono_runtime_capture_context (domain, error);
7096 return_val_if_nok (error, NULL);
7097 /* we must capture the execution context from the original thread */
7098 if (context) {
7099 MONO_OBJECT_SETREF (res, execution_context, context);
7100 /* note: result may be null if the flow is suppressed */
7103 res->data = (void **)data;
7104 MONO_OBJECT_SETREF (res, object_data, object_data);
7105 MONO_OBJECT_SETREF (res, async_state, state);
7106 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7107 return_val_if_nok (error, NULL);
7108 if (handle != NULL)
7109 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7111 res->sync_completed = FALSE;
7112 res->completed = FALSE;
7114 return res;
7117 MonoObject *
7118 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7120 MONO_REQ_GC_UNSAFE_MODE;
7122 MonoError error;
7123 MonoAsyncCall *ac;
7124 MonoObject *res;
7126 g_assert (ares);
7127 g_assert (ares->async_delegate);
7129 ac = (MonoAsyncCall*) ares->object_data;
7130 if (!ac) {
7131 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
7132 } else {
7133 gpointer wait_event = NULL;
7135 ac->msg->exc = NULL;
7136 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
7137 MONO_OBJECT_SETREF (ac, res, res);
7139 mono_monitor_enter ((MonoObject*) ares);
7140 ares->completed = 1;
7141 if (ares->handle)
7142 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7143 mono_monitor_exit ((MonoObject*) ares);
7145 if (wait_event != NULL)
7146 SetEvent (wait_event);
7148 if (ac->cb_method) {
7149 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7150 if (mono_error_set_pending_exception (&error))
7151 return NULL;
7155 return res;
7158 void
7159 mono_message_init (MonoDomain *domain,
7160 MonoMethodMessage *this_obj,
7161 MonoReflectionMethod *method,
7162 MonoArray *out_args)
7164 MONO_REQ_GC_UNSAFE_MODE;
7166 static MonoClass *object_array_klass;
7167 static MonoClass *byte_array_klass;
7168 static MonoClass *string_array_klass;
7169 MonoError error;
7170 MonoMethodSignature *sig = mono_method_signature (method->method);
7171 MonoString *name;
7172 MonoArray *arr;
7173 int i, j;
7174 char **names;
7175 guint8 arg_type;
7177 if (!object_array_klass) {
7178 MonoClass *klass;
7180 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7181 g_assert (klass);
7182 byte_array_klass = klass;
7184 klass = mono_array_class_get (mono_defaults.string_class, 1);
7185 g_assert (klass);
7186 string_array_klass = klass;
7188 klass = mono_array_class_get (mono_defaults.object_class, 1);
7189 g_assert (klass);
7191 mono_atomic_store_release (&object_array_klass, klass);
7194 MONO_OBJECT_SETREF (this_obj, method, method);
7196 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
7197 mono_error_raise_exception (&error); /* FIXME don't raise here */
7199 MONO_OBJECT_SETREF (this_obj, args, arr);
7201 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
7202 mono_error_raise_exception (&error); /* FIXME don't raise here */
7204 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7206 this_obj->async_result = NULL;
7207 this_obj->call_type = CallType_Sync;
7209 names = g_new (char *, sig->param_count);
7210 mono_method_get_param_names (method->method, (const char **) names);
7212 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
7213 mono_error_raise_exception (&error); /* FIXME don't raise here */
7215 MONO_OBJECT_SETREF (this_obj, names, arr);
7217 for (i = 0; i < sig->param_count; i++) {
7218 name = mono_string_new (domain, names [i]);
7219 mono_array_setref (this_obj->names, i, name);
7222 g_free (names);
7223 for (i = 0, j = 0; i < sig->param_count; i++) {
7224 if (sig->params [i]->byref) {
7225 if (out_args) {
7226 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7227 mono_array_setref (this_obj->args, i, arg);
7228 j++;
7230 arg_type = 2;
7231 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7232 arg_type |= 1;
7233 } else {
7234 arg_type = 1;
7235 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7236 arg_type |= 4;
7238 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7242 #ifndef DISABLE_REMOTING
7244 * mono_remoting_invoke:
7245 * @real_proxy: pointer to a RealProxy object
7246 * @msg: The MonoMethodMessage to execute
7247 * @exc: used to store exceptions
7248 * @out_args: used to store output arguments
7250 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7251 * IMessage interface and it is not trivial to extract results from there. So
7252 * we call an helper method PrivateInvoke instead of calling
7253 * RealProxy::Invoke() directly.
7255 * Returns: the result object.
7257 MonoObject *
7258 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7260 MONO_REQ_GC_UNSAFE_MODE;
7262 MonoObject *o;
7263 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7264 gpointer pa [4];
7266 g_assert (exc);
7268 mono_error_init (error);
7270 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7272 if (!im) {
7273 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7274 if (!im) {
7275 mono_error_set_not_supported (error, "Linked away.");
7276 return NULL;
7278 real_proxy->vtable->domain->private_invoke_method = im;
7281 pa [0] = real_proxy;
7282 pa [1] = msg;
7283 pa [2] = exc;
7284 pa [3] = out_args;
7286 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7287 return_val_if_nok (error, NULL);
7289 return o;
7291 #endif
7293 MonoObject *
7294 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7295 MonoObject **exc, MonoArray **out_args)
7297 MONO_REQ_GC_UNSAFE_MODE;
7299 static MonoClass *object_array_klass;
7300 MonoError error;
7301 MonoDomain *domain;
7302 MonoMethod *method;
7303 MonoMethodSignature *sig;
7304 MonoObject *ret;
7305 MonoArray *arr;
7306 int i, j, outarg_count = 0;
7308 #ifndef DISABLE_REMOTING
7309 if (target && mono_object_is_transparent_proxy (target)) {
7310 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7311 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7312 target = tp->rp->unwrapped_server;
7313 } else {
7314 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
7315 mono_error_raise_exception (&error); /* FIXME don't raise here */
7317 return ret;
7320 #endif
7322 domain = mono_domain_get ();
7323 method = msg->method->method;
7324 sig = mono_method_signature (method);
7326 for (i = 0; i < sig->param_count; i++) {
7327 if (sig->params [i]->byref)
7328 outarg_count++;
7331 if (!object_array_klass) {
7332 MonoClass *klass;
7334 klass = mono_array_class_get (mono_defaults.object_class, 1);
7335 g_assert (klass);
7337 mono_memory_barrier ();
7338 object_array_klass = klass;
7341 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
7342 mono_error_raise_exception (&error); /* FIXME don't raise here */
7344 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7345 *exc = NULL;
7347 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
7349 for (i = 0, j = 0; i < sig->param_count; i++) {
7350 if (sig->params [i]->byref) {
7351 MonoObject* arg;
7352 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7353 mono_array_setref (*out_args, j, arg);
7354 j++;
7358 return ret;
7362 * mono_object_to_string:
7363 * @obj: The object
7364 * @exc: Any exception thrown by ToString (). May be NULL.
7366 * Returns: the result of calling ToString () on an object.
7368 MonoString *
7369 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7371 MONO_REQ_GC_UNSAFE_MODE;
7373 static MonoMethod *to_string = NULL;
7374 MonoError error;
7375 MonoMethod *method;
7376 MonoString *s;
7377 void *target = obj;
7379 g_assert (obj);
7381 if (!to_string)
7382 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7384 method = mono_object_get_virtual_method (obj, to_string);
7386 // Unbox value type if needed
7387 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7388 target = mono_object_unbox (obj);
7391 if (exc) {
7392 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7393 if (*exc == NULL && !mono_error_ok (&error))
7394 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7395 else
7396 mono_error_cleanup (&error);
7397 } else {
7398 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7399 mono_error_raise_exception (&error); /* FIXME don't raise here */
7402 return s;
7406 * mono_print_unhandled_exception:
7407 * @exc: The exception
7409 * Prints the unhandled exception.
7411 void
7412 mono_print_unhandled_exception (MonoObject *exc)
7414 MONO_REQ_GC_UNSAFE_MODE;
7416 MonoString * str;
7417 char *message = (char*)"";
7418 gboolean free_message = FALSE;
7419 MonoError error;
7421 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7422 message = g_strdup ("OutOfMemoryException");
7423 free_message = TRUE;
7424 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7425 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7426 free_message = TRUE;
7427 } else {
7429 if (((MonoException*)exc)->native_trace_ips) {
7430 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7431 free_message = TRUE;
7432 } else {
7433 MonoObject *other_exc = NULL;
7434 str = mono_object_to_string (exc, &other_exc);
7435 if (other_exc) {
7436 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7437 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7439 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7440 original_backtrace, nested_backtrace);
7442 g_free (original_backtrace);
7443 g_free (nested_backtrace);
7444 free_message = TRUE;
7445 } else if (str) {
7446 message = mono_string_to_utf8_checked (str, &error);
7447 if (!mono_error_ok (&error)) {
7448 mono_error_cleanup (&error);
7449 message = (char *) "";
7450 } else {
7451 free_message = TRUE;
7458 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7459 * exc->vtable->klass->name, message);
7461 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7463 if (free_message)
7464 g_free (message);
7468 * mono_delegate_ctor_with_method:
7469 * @this: pointer to an uninitialized delegate object
7470 * @target: target object
7471 * @addr: pointer to native code
7472 * @method: method
7473 * @error: set on error.
7475 * Initialize a delegate and sets a specific method, not the one
7476 * associated with addr. This is useful when sharing generic code.
7477 * In that case addr will most probably not be associated with the
7478 * correct instantiation of the method.
7479 * On failure returns FALSE and sets @error.
7481 gboolean
7482 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7484 MONO_REQ_GC_UNSAFE_MODE;
7486 mono_error_init (error);
7487 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7489 g_assert (this_obj);
7490 g_assert (addr);
7492 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7494 if (method)
7495 delegate->method = method;
7497 mono_stats.delegate_creations++;
7499 #ifndef DISABLE_REMOTING
7500 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7501 g_assert (method);
7502 method = mono_marshal_get_remoting_invoke (method);
7503 delegate->method_ptr = mono_compile_method_checked (method, error);
7504 return_val_if_nok (error, FALSE);
7505 MONO_OBJECT_SETREF (delegate, target, target);
7506 } else
7507 #endif
7509 delegate->method_ptr = addr;
7510 MONO_OBJECT_SETREF (delegate, target, target);
7513 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7514 if (callbacks.init_delegate)
7515 callbacks.init_delegate (delegate);
7516 return TRUE;
7520 * mono_delegate_ctor:
7521 * @this: pointer to an uninitialized delegate object
7522 * @target: target object
7523 * @addr: pointer to native code
7524 * @error: set on error.
7526 * This is used to initialize a delegate.
7527 * On failure returns FALSE and sets @error.
7529 gboolean
7530 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7532 MONO_REQ_GC_UNSAFE_MODE;
7534 mono_error_init (error);
7535 MonoDomain *domain = mono_domain_get ();
7536 MonoJitInfo *ji;
7537 MonoMethod *method = NULL;
7539 g_assert (addr);
7541 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7542 /* Shared code */
7543 if (!ji && domain != mono_get_root_domain ())
7544 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7545 if (ji) {
7546 method = mono_jit_info_get_method (ji);
7547 g_assert (!method->klass->generic_container);
7550 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7554 * mono_method_call_message_new:
7555 * @method: method to encapsulate
7556 * @params: parameters to the method
7557 * @invoke: optional, delegate invoke.
7558 * @cb: async callback delegate.
7559 * @state: state passed to the async callback.
7561 * Translates arguments pointers into a MonoMethodMessage.
7563 MonoMethodMessage *
7564 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7565 MonoDelegate **cb, MonoObject **state)
7567 MONO_REQ_GC_UNSAFE_MODE;
7569 MonoError error;
7571 MonoDomain *domain = mono_domain_get ();
7572 MonoMethodSignature *sig = mono_method_signature (method);
7573 MonoMethodMessage *msg;
7574 int i, count;
7576 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7577 mono_error_raise_exception (&error); /* FIXME don't raise here */
7579 if (invoke) {
7580 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7581 mono_error_raise_exception (&error); /* FIXME don't raise here */
7582 mono_message_init (domain, msg, rm, NULL);
7583 count = sig->param_count - 2;
7584 } else {
7585 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7586 mono_error_raise_exception (&error); /* FIXME don't raise here */
7587 mono_message_init (domain, msg, rm, NULL);
7588 count = sig->param_count;
7591 for (i = 0; i < count; i++) {
7592 gpointer vpos;
7593 MonoClass *klass;
7594 MonoObject *arg;
7596 if (sig->params [i]->byref)
7597 vpos = *((gpointer *)params [i]);
7598 else
7599 vpos = params [i];
7601 klass = mono_class_from_mono_type (sig->params [i]);
7603 if (klass->valuetype) {
7604 arg = mono_value_box_checked (domain, klass, vpos, &error);
7605 mono_error_raise_exception (&error); /* FIXME don't raise here */
7606 } else
7607 arg = *((MonoObject **)vpos);
7609 mono_array_setref (msg->args, i, arg);
7612 if (cb != NULL && state != NULL) {
7613 *cb = *((MonoDelegate **)params [i]);
7614 i++;
7615 *state = *((MonoObject **)params [i]);
7618 return msg;
7622 * mono_method_return_message_restore:
7624 * Restore results from message based processing back to arguments pointers
7626 void
7627 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7629 MONO_REQ_GC_UNSAFE_MODE;
7631 mono_error_init (error);
7633 MonoMethodSignature *sig = mono_method_signature (method);
7634 int i, j, type, size, out_len;
7636 if (out_args == NULL)
7637 return;
7638 out_len = mono_array_length (out_args);
7639 if (out_len == 0)
7640 return;
7642 for (i = 0, j = 0; i < sig->param_count; i++) {
7643 MonoType *pt = sig->params [i];
7645 if (pt->byref) {
7646 char *arg;
7647 if (j >= out_len) {
7648 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7649 return;
7652 arg = (char *)mono_array_get (out_args, gpointer, j);
7653 type = pt->type;
7655 g_assert (type != MONO_TYPE_VOID);
7657 if (MONO_TYPE_IS_REFERENCE (pt)) {
7658 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7659 } else {
7660 if (arg) {
7661 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7662 size = mono_class_value_size (klass, NULL);
7663 if (klass->has_references)
7664 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7665 else
7666 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7667 } else {
7668 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7669 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7673 j++;
7678 #ifndef DISABLE_REMOTING
7681 * mono_load_remote_field:
7682 * @this: pointer to an object
7683 * @klass: klass of the object containing @field
7684 * @field: the field to load
7685 * @res: a storage to store the result
7687 * This method is called by the runtime on attempts to load fields of
7688 * transparent proxy objects. @this points to such TP, @klass is the class of
7689 * the object containing @field. @res is a storage location which can be
7690 * used to store the result.
7692 * Returns: an address pointing to the value of field.
7694 gpointer
7695 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7697 MonoError error;
7698 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7699 mono_error_cleanup (&error);
7700 return result;
7704 * mono_load_remote_field_checked:
7705 * @this: pointer to an object
7706 * @klass: klass of the object containing @field
7707 * @field: the field to load
7708 * @res: a storage to store the result
7709 * @error: set on error
7711 * This method is called by the runtime on attempts to load fields of
7712 * transparent proxy objects. @this points to such TP, @klass is the class of
7713 * the object containing @field. @res is a storage location which can be
7714 * used to store the result.
7716 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
7718 gpointer
7719 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
7721 MONO_REQ_GC_UNSAFE_MODE;
7723 static MonoMethod *getter = NULL;
7725 mono_error_init (error);
7727 MonoDomain *domain = mono_domain_get ();
7728 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7729 MonoClass *field_class;
7730 MonoMethodMessage *msg;
7731 MonoArray *out_args;
7732 MonoObject *exc;
7733 char* full_name;
7735 g_assert (mono_object_is_transparent_proxy (this_obj));
7736 g_assert (res != NULL);
7738 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7739 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7740 return res;
7743 if (!getter) {
7744 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7745 if (!getter) {
7746 mono_error_set_not_supported (error, "Linked away.");
7747 return NULL;
7751 field_class = mono_class_from_mono_type (field->type);
7753 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7754 return_val_if_nok (error, NULL);
7755 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
7756 return_val_if_nok (error, NULL);
7757 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
7758 return_val_if_nok (error, NULL);
7759 mono_message_init (domain, msg, rm, out_args);
7761 full_name = mono_type_get_full_name (klass);
7762 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7763 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7764 g_free (full_name);
7766 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7767 return_val_if_nok (error, NULL);
7769 if (exc) {
7770 mono_error_set_exception_instance (error, (MonoException *)exc);
7771 return NULL;
7774 if (mono_array_length (out_args) == 0)
7775 return NULL;
7777 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
7779 if (field_class->valuetype) {
7780 return ((char *)*res) + sizeof (MonoObject);
7781 } else
7782 return res;
7786 * mono_load_remote_field_new:
7787 * @this:
7788 * @klass:
7789 * @field:
7791 * Missing documentation.
7793 MonoObject *
7794 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7796 MonoError error;
7798 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
7799 mono_error_cleanup (&error);
7800 return result;
7804 * mono_load_remote_field_new_icall:
7805 * @this: pointer to an object
7806 * @klass: klass of the object containing @field
7807 * @field: the field to load
7809 * This method is called by the runtime on attempts to load fields of
7810 * transparent proxy objects. @this points to such TP, @klass is the class of
7811 * the object containing @field.
7813 * Returns: a freshly allocated object containing the value of the
7814 * field. On failure returns NULL and throws an exception.
7816 MonoObject *
7817 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7819 MonoError error;
7820 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
7821 mono_error_set_pending_exception (&error);
7822 return result;
7826 * mono_load_remote_field_new_checked:
7827 * @this: pointer to an object
7828 * @klass: klass of the object containing @field
7829 * @field: the field to load
7830 * @error: set on error.
7832 * This method is called by the runtime on attempts to load fields of
7833 * transparent proxy objects. @this points to such TP, @klass is the class of
7834 * the object containing @field.
7836 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
7838 MonoObject *
7839 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
7841 MONO_REQ_GC_UNSAFE_MODE;
7843 mono_error_init (error);
7845 static MonoMethod *getter = NULL;
7846 MonoDomain *domain = mono_domain_get ();
7847 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7848 MonoClass *field_class;
7849 MonoMethodMessage *msg;
7850 MonoArray *out_args;
7851 MonoObject *exc, *res;
7852 char* full_name;
7854 g_assert (mono_object_is_transparent_proxy (this_obj));
7856 field_class = mono_class_from_mono_type (field->type);
7858 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7859 gpointer val;
7860 if (field_class->valuetype) {
7861 res = mono_object_new_checked (domain, field_class, error);
7862 return_val_if_nok (error, NULL);
7863 val = ((gchar *) res) + sizeof (MonoObject);
7864 } else {
7865 val = &res;
7867 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7868 return res;
7871 if (!getter) {
7872 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7873 if (!getter) {
7874 mono_error_set_not_supported (error, "Linked away.");
7875 return NULL;
7879 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7880 return_val_if_nok (error, NULL);
7881 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
7882 return_val_if_nok (error, NULL);
7884 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
7885 return_val_if_nok (error, NULL);
7886 mono_message_init (domain, msg, rm, out_args);
7888 full_name = mono_type_get_full_name (klass);
7889 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7890 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7891 g_free (full_name);
7893 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7894 return_val_if_nok (error, NULL);
7896 if (exc) {
7897 mono_error_set_exception_instance (error, (MonoException *)exc);
7898 return NULL;
7901 if (mono_array_length (out_args) == 0)
7902 res = NULL;
7903 else
7904 res = mono_array_get (out_args, MonoObject *, 0);
7906 return res;
7910 * mono_store_remote_field:
7911 * @this_obj: pointer to an object
7912 * @klass: klass of the object containing @field
7913 * @field: the field to load
7914 * @val: the value/object to store
7916 * This method is called by the runtime on attempts to store fields of
7917 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7918 * the object containing @field. @val is the new value to store in @field.
7920 void
7921 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7923 MonoError error;
7924 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
7925 mono_error_cleanup (&error);
7929 * mono_store_remote_field_checked:
7930 * @this_obj: pointer to an object
7931 * @klass: klass of the object containing @field
7932 * @field: the field to load
7933 * @val: the value/object to store
7934 * @error: set on error
7936 * This method is called by the runtime on attempts to store fields of
7937 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7938 * the object containing @field. @val is the new value to store in @field.
7940 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
7942 gboolean
7943 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
7946 MONO_REQ_GC_UNSAFE_MODE;
7948 static MonoMethod *setter = NULL;
7950 MonoDomain *domain = mono_domain_get ();
7951 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7952 MonoClass *field_class;
7953 MonoMethodMessage *msg;
7954 MonoArray *out_args;
7955 MonoObject *exc;
7956 MonoObject *arg;
7957 char* full_name;
7959 mono_error_init (error);
7961 g_assert (mono_object_is_transparent_proxy (this_obj));
7963 field_class = mono_class_from_mono_type (field->type);
7965 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7966 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7967 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7968 return TRUE;
7971 if (!setter) {
7972 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7973 if (!setter) {
7974 mono_error_set_not_supported (error, "Linked away.");
7975 return FALSE;
7979 if (field_class->valuetype) {
7980 arg = mono_value_box_checked (domain, field_class, val, error);
7981 return_val_if_nok (error, FALSE);
7982 } else
7983 arg = *((MonoObject **)val);
7986 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7987 return_val_if_nok (error, FALSE);
7988 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
7989 return_val_if_nok (error, FALSE);
7990 mono_message_init (domain, msg, rm, NULL);
7992 full_name = mono_type_get_full_name (klass);
7993 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7994 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7995 mono_array_setref (msg->args, 2, arg);
7996 g_free (full_name);
7998 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7999 return_val_if_nok (error, FALSE);
8001 if (exc) {
8002 mono_error_set_exception_instance (error, (MonoException *)exc);
8003 return FALSE;
8005 return TRUE;
8009 * mono_store_remote_field_new:
8010 * @this_obj:
8011 * @klass:
8012 * @field:
8013 * @arg:
8015 * Missing documentation
8017 void
8018 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8020 MonoError error;
8021 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8022 mono_error_cleanup (&error);
8026 * mono_store_remote_field_new_icall:
8027 * @this_obj:
8028 * @klass:
8029 * @field:
8030 * @arg:
8032 * Missing documentation
8034 void
8035 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8037 MonoError error;
8038 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8039 mono_error_set_pending_exception (&error);
8043 * mono_store_remote_field_new_checked:
8044 * @this_obj:
8045 * @klass:
8046 * @field:
8047 * @arg:
8048 * @error:
8050 * Missing documentation
8052 gboolean
8053 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8055 MONO_REQ_GC_UNSAFE_MODE;
8057 static MonoMethod *setter = NULL;
8058 MonoDomain *domain = mono_domain_get ();
8059 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8060 MonoClass *field_class;
8061 MonoMethodMessage *msg;
8062 MonoArray *out_args;
8063 MonoObject *exc;
8064 char* full_name;
8066 mono_error_init (error);
8068 g_assert (mono_object_is_transparent_proxy (this_obj));
8070 field_class = mono_class_from_mono_type (field->type);
8072 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8073 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8074 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8075 return TRUE;
8078 if (!setter) {
8079 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8080 if (!setter) {
8081 mono_error_set_not_supported (error, "Linked away.");
8082 return FALSE;
8086 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8087 return_val_if_nok (error, FALSE);
8088 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8089 return_val_if_nok (error, FALSE);
8090 mono_message_init (domain, msg, rm, NULL);
8092 full_name = mono_type_get_full_name (klass);
8093 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8094 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8095 mono_array_setref (msg->args, 2, arg);
8096 g_free (full_name);
8098 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8099 return_val_if_nok (error, FALSE);
8101 if (exc) {
8102 mono_error_set_exception_instance (error, (MonoException *)exc);
8103 return FALSE;
8105 return TRUE;
8107 #endif
8110 * mono_create_ftnptr:
8112 * Given a function address, create a function descriptor for it.
8113 * This is only needed on some platforms.
8115 gpointer
8116 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8118 return callbacks.create_ftnptr (domain, addr);
8122 * mono_get_addr_from_ftnptr:
8124 * Given a pointer to a function descriptor, return the function address.
8125 * This is only needed on some platforms.
8127 gpointer
8128 mono_get_addr_from_ftnptr (gpointer descr)
8130 return callbacks.get_addr_from_ftnptr (descr);
8134 * mono_string_chars:
8135 * @s: a MonoString
8137 * Returns a pointer to the UCS16 characters stored in the MonoString
8139 gunichar2 *
8140 mono_string_chars (MonoString *s)
8142 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8144 return s->chars;
8148 * mono_string_length:
8149 * @s: MonoString
8151 * Returns the lenght in characters of the string
8154 mono_string_length (MonoString *s)
8156 MONO_REQ_GC_UNSAFE_MODE;
8158 return s->length;
8162 * mono_array_length:
8163 * @array: a MonoArray*
8165 * Returns the total number of elements in the array. This works for
8166 * both vectors and multidimensional arrays.
8168 uintptr_t
8169 mono_array_length (MonoArray *array)
8171 MONO_REQ_GC_UNSAFE_MODE;
8173 return array->max_length;
8177 * mono_array_addr_with_size:
8178 * @array: a MonoArray*
8179 * @size: size of the array elements
8180 * @idx: index into the array
8182 * Use this function to obtain the address for the @idx item on the
8183 * @array containing elements of size @size.
8185 * This method performs no bounds checking or type checking.
8187 * Returns the address of the @idx element in the array.
8189 char*
8190 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8192 MONO_REQ_GC_UNSAFE_MODE;
8194 return ((char*)(array)->vector) + size * idx;
8198 MonoArray *
8199 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8201 MonoDomain *domain = mono_domain_get ();
8202 MonoArray *res;
8203 int len, i;
8205 mono_error_init (error);
8206 if (!list)
8207 return NULL;
8209 len = g_list_length (list);
8210 res = mono_array_new_checked (domain, eclass, len, error);
8211 return_val_if_nok (error, NULL);
8213 for (i = 0; list; list = list->next, i++)
8214 mono_array_set (res, gpointer, i, list->data);
8216 return res;
8219 #if NEVER_DEFINED
8221 * The following section is purely to declare prototypes and
8222 * document the API, as these C files are processed by our
8223 * tool
8227 * mono_array_set:
8228 * @array: array to alter
8229 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8230 * @index: index into the array
8231 * @value: value to set
8233 * Value Type version: This sets the @index's element of the @array
8234 * with elements of size sizeof(type) to the provided @value.
8236 * This macro does not attempt to perform type checking or bounds checking.
8238 * Use this to set value types in a `MonoArray`.
8240 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8245 * mono_array_setref:
8246 * @array: array to alter
8247 * @index: index into the array
8248 * @value: value to set
8250 * Reference Type version: This sets the @index's element of the
8251 * @array with elements of size sizeof(type) to the provided @value.
8253 * This macro does not attempt to perform type checking or bounds checking.
8255 * Use this to reference types in a `MonoArray`.
8257 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8262 * mono_array_get:
8263 * @array: array on which to operate on
8264 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8265 * @index: index into the array
8267 * Use this macro to retrieve the @index element of an @array and
8268 * extract the value assuming that the elements of the array match
8269 * the provided type value.
8271 * This method can be used with both arrays holding value types and
8272 * reference types. For reference types, the @type parameter should
8273 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8275 * This macro does not attempt to perform type checking or bounds checking.
8277 * Returns: The element at the @index position in the @array.
8279 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8282 #endif