[remoting] Coop handles for proxy objects (#4208)
[mono-project.git] / mono / metadata / object.c
blob422b9a21a27866b418777cc1f748800d3fcc0ac5
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/metadata/w32event.h>
45 #include <mono/utils/strenc.h>
46 #include <mono/utils/mono-counters.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-memory-model.h>
49 #include <mono/utils/checked-build.h>
50 #include <mono/utils/mono-threads.h>
51 #include <mono/utils/mono-threads-coop.h>
52 #include "cominterop.h"
53 #include <mono/io-layer/io-layer.h>
55 static void
56 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
58 static MonoString*
59 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
61 static void
62 free_main_args (void);
64 static char *
65 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
67 static MonoMethod*
68 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
70 /* Class lazy loading functions */
71 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
72 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
73 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
74 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
75 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
78 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
79 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
80 static mono_mutex_t ldstr_section;
83 /**
84 * mono_runtime_object_init:
85 * @this_obj: the object to initialize
87 * This function calls the zero-argument constructor (which must
88 * exist) for the given object.
90 void
91 mono_runtime_object_init (MonoObject *this_obj)
93 MonoError error;
94 mono_runtime_object_init_checked (this_obj, &error);
95 mono_error_assert_ok (&error);
98 /**
99 * mono_runtime_object_init_checked:
100 * @this_obj: the object to initialize
101 * @error: set on error.
103 * This function calls the zero-argument constructor (which must
104 * exist) for the given object and returns TRUE on success, or FALSE
105 * on error and sets @error.
107 gboolean
108 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
110 MONO_REQ_GC_UNSAFE_MODE;
112 MonoMethod *method = NULL;
113 MonoClass *klass = this_obj->vtable->klass;
115 mono_error_init (error);
116 method = mono_class_get_method_from_name (klass, ".ctor", 0);
117 if (!method)
118 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
120 if (method->klass->valuetype)
121 this_obj = (MonoObject *)mono_object_unbox (this_obj);
123 mono_runtime_invoke_checked (method, this_obj, NULL, error);
124 return is_ok (error);
127 /* The pseudo algorithm for type initialization from the spec
128 Note it doesn't say anything about domains - only threads.
130 2. If the type is initialized you are done.
131 2.1. If the type is not yet initialized, try to take an
132 initialization lock.
133 2.2. If successful, record this thread as responsible for
134 initializing the type and proceed to step 2.3.
135 2.2.1. If not, see whether this thread or any thread
136 waiting for this thread to complete already holds the lock.
137 2.2.2. If so, return since blocking would create a deadlock. This thread
138 will now see an incompletely initialized state for the type,
139 but no deadlock will arise.
140 2.2.3 If not, block until the type is initialized then return.
141 2.3 Initialize the parent type and then all interfaces implemented
142 by this type.
143 2.4 Execute the type initialization code for this type.
144 2.5 Mark the type as initialized, release the initialization lock,
145 awaken any threads waiting for this type to be initialized,
146 and return.
150 typedef struct
152 MonoNativeThreadId initializing_tid;
153 guint32 waiting_count;
154 gboolean done;
155 MonoCoopMutex initialization_section;
156 } TypeInitializationLock;
158 /* for locking access to type_initialization_hash and blocked_thread_hash */
159 static MonoCoopMutex type_initialization_section;
161 static inline void
162 mono_type_initialization_lock (void)
164 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
165 mono_coop_mutex_lock (&type_initialization_section);
168 static inline void
169 mono_type_initialization_unlock (void)
171 mono_coop_mutex_unlock (&type_initialization_section);
174 static void
175 mono_type_init_lock (TypeInitializationLock *lock)
177 MONO_REQ_GC_NEUTRAL_MODE;
179 mono_coop_mutex_lock (&lock->initialization_section);
182 static void
183 mono_type_init_unlock (TypeInitializationLock *lock)
185 mono_coop_mutex_unlock (&lock->initialization_section);
188 /* from vtable to lock */
189 static GHashTable *type_initialization_hash;
191 /* from thread id to thread id being waited on */
192 static GHashTable *blocked_thread_hash;
194 /* Main thread */
195 static MonoThread *main_thread;
197 /* Functions supplied by the runtime */
198 static MonoRuntimeCallbacks callbacks;
201 * mono_thread_set_main:
202 * @thread: thread to set as the main thread
204 * This function can be used to instruct the runtime to treat @thread
205 * as the main thread, ie, the thread that would normally execute the Main()
206 * method. This basically means that at the end of @thread, the runtime will
207 * wait for the existing foreground threads to quit and other such details.
209 void
210 mono_thread_set_main (MonoThread *thread)
212 MONO_REQ_GC_UNSAFE_MODE;
214 static gboolean registered = FALSE;
216 if (!registered) {
217 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
218 registered = TRUE;
221 main_thread = thread;
224 MonoThread*
225 mono_thread_get_main (void)
227 MONO_REQ_GC_UNSAFE_MODE;
229 return main_thread;
232 void
233 mono_type_initialization_init (void)
235 mono_coop_mutex_init_recursive (&type_initialization_section);
236 type_initialization_hash = g_hash_table_new (NULL, NULL);
237 blocked_thread_hash = g_hash_table_new (NULL, NULL);
238 mono_os_mutex_init_recursive (&ldstr_section);
241 void
242 mono_type_initialization_cleanup (void)
244 #if 0
245 /* This is causing race conditions with
246 * mono_release_type_locks
248 mono_coop_mutex_destroy (&type_initialization_section);
249 g_hash_table_destroy (type_initialization_hash);
250 type_initialization_hash = NULL;
251 #endif
252 mono_os_mutex_destroy (&ldstr_section);
253 g_hash_table_destroy (blocked_thread_hash);
254 blocked_thread_hash = NULL;
256 free_main_args ();
260 * get_type_init_exception_for_vtable:
262 * Return the stored type initialization exception for VTABLE.
264 static MonoException*
265 get_type_init_exception_for_vtable (MonoVTable *vtable)
267 MONO_REQ_GC_UNSAFE_MODE;
269 MonoError error;
270 MonoDomain *domain = vtable->domain;
271 MonoClass *klass = vtable->klass;
272 MonoException *ex;
273 gchar *full_name;
275 if (!vtable->init_failed)
276 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
279 * If the initializing thread was rudely aborted, the exception is not stored
280 * in the hash.
282 ex = NULL;
283 mono_domain_lock (domain);
284 if (domain->type_init_exception_hash)
285 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
286 mono_domain_unlock (domain);
288 if (!ex) {
289 if (klass->name_space && *klass->name_space)
290 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
291 else
292 full_name = g_strdup (klass->name);
293 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
294 g_free (full_name);
295 return_val_if_nok (&error, NULL);
298 return ex;
302 * mono_runtime_class_init:
303 * @vtable: vtable that needs to be initialized
305 * This routine calls the class constructor for @vtable.
307 void
308 mono_runtime_class_init (MonoVTable *vtable)
310 MONO_REQ_GC_UNSAFE_MODE;
311 MonoError error;
313 mono_runtime_class_init_full (vtable, &error);
314 mono_error_assert_ok (&error);
318 * mono_runtime_class_init_full:
319 * @vtable that neeeds to be initialized
320 * @error set on error
322 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
325 gboolean
326 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
328 MONO_REQ_GC_UNSAFE_MODE;
330 MonoMethod *method = NULL;
331 MonoClass *klass;
332 gchar *full_name;
333 MonoDomain *domain = vtable->domain;
334 TypeInitializationLock *lock;
335 MonoNativeThreadId tid;
336 int do_initialization = 0;
337 MonoDomain *last_domain = NULL;
338 MonoException * pending_tae = NULL;
340 mono_error_init (error);
342 if (vtable->initialized)
343 return TRUE;
345 klass = vtable->klass;
347 if (!klass->image->checked_module_cctor) {
348 mono_image_check_for_module_cctor (klass->image);
349 if (klass->image->has_module_cctor) {
350 MonoClass *module_klass;
351 MonoVTable *module_vtable;
353 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
354 if (!module_klass) {
355 return FALSE;
358 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
359 if (!module_vtable)
360 return FALSE;
361 if (!mono_runtime_class_init_full (module_vtable, error))
362 return FALSE;
365 method = mono_class_get_cctor (klass);
366 if (!method) {
367 vtable->initialized = 1;
368 return TRUE;
371 tid = mono_native_thread_id_get ();
373 mono_type_initialization_lock ();
374 /* double check... */
375 if (vtable->initialized) {
376 mono_type_initialization_unlock ();
377 return TRUE;
379 if (vtable->init_failed) {
380 mono_type_initialization_unlock ();
382 /* The type initialization already failed once, rethrow the same exception */
383 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
384 return FALSE;
386 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
387 if (lock == NULL) {
388 /* This thread will get to do the initialization */
389 if (mono_domain_get () != domain) {
390 /* Transfer into the target domain */
391 last_domain = mono_domain_get ();
392 if (!mono_domain_set (domain, FALSE)) {
393 vtable->initialized = 1;
394 mono_type_initialization_unlock ();
395 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
396 return FALSE;
399 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
400 mono_coop_mutex_init_recursive (&lock->initialization_section);
401 lock->initializing_tid = tid;
402 lock->waiting_count = 1;
403 lock->done = FALSE;
404 /* grab the vtable lock while this thread still owns type_initialization_section */
405 /* This is why type_initialization_lock needs to enter blocking mode */
406 mono_type_init_lock (lock);
407 g_hash_table_insert (type_initialization_hash, vtable, lock);
408 do_initialization = 1;
409 } else {
410 gpointer blocked;
411 TypeInitializationLock *pending_lock;
413 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
414 mono_type_initialization_unlock ();
415 return TRUE;
417 /* see if the thread doing the initialization is already blocked on this thread */
418 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
419 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
420 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
421 if (!pending_lock->done) {
422 mono_type_initialization_unlock ();
423 return TRUE;
424 } else {
425 /* the thread doing the initialization is blocked on this thread,
426 but on a lock that has already been freed. It just hasn't got
427 time to awake */
428 break;
431 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
433 ++lock->waiting_count;
434 /* record the fact that we are waiting on the initializing thread */
435 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
437 mono_type_initialization_unlock ();
439 if (do_initialization) {
440 MonoException *exc = NULL;
442 mono_threads_begin_abort_protected_block ();
443 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
444 mono_threads_end_abort_protected_block ();
446 //exception extracted, error will be set to the right value later
447 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
448 exc = mono_error_convert_to_exception (error);
449 else
450 mono_error_cleanup (error);
452 mono_error_init (error);
454 /* If the initialization failed, mark the class as unusable. */
455 /* Avoid infinite loops */
456 if (!(!exc ||
457 (klass->image == mono_defaults.corlib &&
458 !strcmp (klass->name_space, "System") &&
459 !strcmp (klass->name, "TypeInitializationException")))) {
460 vtable->init_failed = 1;
462 if (klass->name_space && *klass->name_space)
463 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
464 else
465 full_name = g_strdup (klass->name);
467 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
468 g_free (full_name);
470 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
473 * Store the exception object so it could be thrown on subsequent
474 * accesses.
476 mono_domain_lock (domain);
477 if (!domain->type_init_exception_hash)
478 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");
479 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
480 mono_domain_unlock (domain);
483 if (last_domain)
484 mono_domain_set (last_domain, TRUE);
485 lock->done = TRUE;
486 mono_type_init_unlock (lock);
487 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
488 pending_tae = exc;
489 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
490 if (!pending_tae && mono_get_eh_callbacks ()->mono_above_abort_threshold ())
491 pending_tae = mono_thread_try_resume_interruption ();
492 } else {
493 /* this just blocks until the initializing thread is done */
494 mono_type_init_lock (lock);
495 mono_type_init_unlock (lock);
498 mono_type_initialization_lock ();
499 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
500 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
501 --lock->waiting_count;
502 if (lock->waiting_count == 0) {
503 mono_coop_mutex_destroy (&lock->initialization_section);
504 g_hash_table_remove (type_initialization_hash, vtable);
505 g_free (lock);
507 mono_memory_barrier ();
508 if (!vtable->init_failed)
509 vtable->initialized = 1;
510 mono_type_initialization_unlock ();
512 //TAE wins over TIE
513 if (pending_tae)
514 mono_error_set_exception_instance (error, pending_tae);
515 else if (vtable->init_failed) {
516 /* Either we were the initializing thread or we waited for the initialization */
517 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
518 return FALSE;
520 return TRUE;
523 static
524 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
526 MONO_REQ_GC_NEUTRAL_MODE;
528 MonoVTable *vtable = (MonoVTable*)key;
530 TypeInitializationLock *lock = (TypeInitializationLock*) value;
531 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
532 lock->done = TRUE;
534 * Have to set this since it cannot be set by the normal code in
535 * mono_runtime_class_init (). In this case, the exception object is not stored,
536 * and get_type_init_exception_for_class () needs to be aware of this.
538 vtable->init_failed = 1;
539 mono_type_init_unlock (lock);
540 --lock->waiting_count;
541 if (lock->waiting_count == 0) {
542 mono_coop_mutex_destroy (&lock->initialization_section);
543 g_free (lock);
544 return TRUE;
547 return FALSE;
550 void
551 mono_release_type_locks (MonoInternalThread *thread)
553 MONO_REQ_GC_UNSAFE_MODE;
555 mono_type_initialization_lock ();
556 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
557 mono_type_initialization_unlock ();
560 #ifndef DISABLE_REMOTING
562 static gpointer
563 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
565 if (!callbacks.create_remoting_trampoline)
566 g_error ("remoting not installed");
567 return callbacks.create_remoting_trampoline (domain, method, target, error);
570 #endif
572 static MonoImtTrampolineBuilder imt_trampoline_builder;
573 static gboolean always_build_imt_trampolines;
575 #if (MONO_IMT_SIZE > 32)
576 #error "MONO_IMT_SIZE cannot be larger than 32"
577 #endif
579 void
580 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
582 memcpy (&callbacks, cbs, sizeof (*cbs));
585 MonoRuntimeCallbacks*
586 mono_get_runtime_callbacks (void)
588 return &callbacks;
591 void
592 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
594 imt_trampoline_builder = func;
597 void
598 mono_set_always_build_imt_trampolines (gboolean value)
600 always_build_imt_trampolines = value;
604 * mono_compile_method:
605 * @method: The method to compile.
607 * This JIT-compiles the method, and returns the pointer to the native code
608 * produced.
610 gpointer
611 mono_compile_method (MonoMethod *method)
613 MonoError error;
614 gpointer result = mono_compile_method_checked (method, &error);
615 mono_error_cleanup (&error);
616 return result;
620 * mono_compile_method:
621 * @method: The method to compile.
622 * @error: set on error.
624 * This JIT-compiles the method, and returns the pointer to the native code
625 * produced. On failure returns NULL and sets @error.
627 gpointer
628 mono_compile_method_checked (MonoMethod *method, MonoError *error)
630 gpointer res;
632 MONO_REQ_GC_NEUTRAL_MODE
634 mono_error_init (error);
636 g_assert (callbacks.compile_method);
637 res = callbacks.compile_method (method, error);
638 return res;
641 gpointer
642 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
644 gpointer res;
646 MONO_REQ_GC_NEUTRAL_MODE;
648 mono_error_init (error);
649 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
650 return res;
653 gpointer
654 mono_runtime_create_delegate_trampoline (MonoClass *klass)
656 MONO_REQ_GC_NEUTRAL_MODE
658 g_assert (callbacks.create_delegate_trampoline);
659 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
663 * mono_runtime_free_method:
664 * @domain; domain where the method is hosted
665 * @method: method to release
667 * This routine is invoked to free the resources associated with
668 * a method that has been JIT compiled. This is used to discard
669 * methods that were used only temporarily (for example, used in marshalling)
672 void
673 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
675 MONO_REQ_GC_NEUTRAL_MODE
677 if (callbacks.free_method)
678 callbacks.free_method (domain, method);
680 mono_method_clear_object (domain, method);
682 mono_free_method (method);
686 * The vtables in the root appdomain are assumed to be reachable by other
687 * roots, and we don't use typed allocation in the other domains.
690 /* The sync block is no longer a GC pointer */
691 #define GC_HEADER_BITMAP (0)
693 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
695 static gsize*
696 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
698 MONO_REQ_GC_NEUTRAL_MODE;
700 MonoClassField *field;
701 MonoClass *p;
702 guint32 pos;
703 int max_size;
705 if (static_fields)
706 max_size = mono_class_data_size (klass) / sizeof (gpointer);
707 else
708 max_size = klass->instance_size / sizeof (gpointer);
709 if (max_size > size) {
710 g_assert (offset <= 0);
711 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
712 size = max_size;
715 #ifdef HAVE_SGEN_GC
716 /*An Ephemeron cannot be marked by sgen*/
717 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
718 *max_set = 0;
719 memset (bitmap, 0, size / 8);
720 return bitmap;
722 #endif
724 for (p = klass; p != NULL; p = p->parent) {
725 gpointer iter = NULL;
726 while ((field = mono_class_get_fields (p, &iter))) {
727 MonoType *type;
729 if (static_fields) {
730 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
731 continue;
732 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
733 continue;
734 } else {
735 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
736 continue;
738 /* FIXME: should not happen, flag as type load error */
739 if (field->type->byref)
740 break;
742 if (static_fields && field->offset == -1)
743 /* special static */
744 continue;
746 pos = field->offset / sizeof (gpointer);
747 pos += offset;
749 type = mono_type_get_underlying_type (field->type);
750 switch (type->type) {
751 case MONO_TYPE_I:
752 case MONO_TYPE_PTR:
753 case MONO_TYPE_FNPTR:
754 break;
755 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
756 case MONO_TYPE_U:
757 #ifdef HAVE_SGEN_GC
758 break;
759 #else
760 if (klass->image != mono_defaults.corlib)
761 break;
762 #endif
763 case MONO_TYPE_STRING:
764 case MONO_TYPE_SZARRAY:
765 case MONO_TYPE_CLASS:
766 case MONO_TYPE_OBJECT:
767 case MONO_TYPE_ARRAY:
768 g_assert ((field->offset % sizeof(gpointer)) == 0);
770 g_assert (pos < size || pos <= max_size);
771 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
772 *max_set = MAX (*max_set, pos);
773 break;
774 case MONO_TYPE_GENERICINST:
775 if (!mono_type_generic_inst_is_valuetype (type)) {
776 g_assert ((field->offset % sizeof(gpointer)) == 0);
778 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
779 *max_set = MAX (*max_set, pos);
780 break;
781 } else {
782 /* fall through */
784 case MONO_TYPE_VALUETYPE: {
785 MonoClass *fclass = mono_class_from_mono_type (field->type);
786 if (fclass->has_references) {
787 /* remove the object header */
788 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
790 break;
792 case MONO_TYPE_I1:
793 case MONO_TYPE_U1:
794 case MONO_TYPE_I2:
795 case MONO_TYPE_U2:
796 case MONO_TYPE_I4:
797 case MONO_TYPE_U4:
798 case MONO_TYPE_I8:
799 case MONO_TYPE_U8:
800 case MONO_TYPE_R4:
801 case MONO_TYPE_R8:
802 case MONO_TYPE_BOOLEAN:
803 case MONO_TYPE_CHAR:
804 break;
805 default:
806 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
807 break;
810 if (static_fields)
811 break;
813 return bitmap;
817 * mono_class_compute_bitmap:
819 * Mono internal function to compute a bitmap of reference fields in a class.
821 gsize*
822 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
824 MONO_REQ_GC_NEUTRAL_MODE;
826 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
829 #if 0
831 * similar to the above, but sets the bits in the bitmap for any non-ref field
832 * and ignores static fields
834 static gsize*
835 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
837 MonoClassField *field;
838 MonoClass *p;
839 guint32 pos, pos2;
840 int max_size;
842 max_size = class->instance_size / sizeof (gpointer);
843 if (max_size >= size) {
844 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
847 for (p = class; p != NULL; p = p->parent) {
848 gpointer iter = NULL;
849 while ((field = mono_class_get_fields (p, &iter))) {
850 MonoType *type;
852 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
853 continue;
854 /* FIXME: should not happen, flag as type load error */
855 if (field->type->byref)
856 break;
858 pos = field->offset / sizeof (gpointer);
859 pos += offset;
861 type = mono_type_get_underlying_type (field->type);
862 switch (type->type) {
863 #if SIZEOF_VOID_P == 8
864 case MONO_TYPE_I:
865 case MONO_TYPE_U:
866 case MONO_TYPE_PTR:
867 case MONO_TYPE_FNPTR:
868 #endif
869 case MONO_TYPE_I8:
870 case MONO_TYPE_U8:
871 case MONO_TYPE_R8:
872 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
873 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
874 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
876 /* fall through */
877 #if SIZEOF_VOID_P == 4
878 case MONO_TYPE_I:
879 case MONO_TYPE_U:
880 case MONO_TYPE_PTR:
881 case MONO_TYPE_FNPTR:
882 #endif
883 case MONO_TYPE_I4:
884 case MONO_TYPE_U4:
885 case MONO_TYPE_R4:
886 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
887 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
888 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
890 /* fall through */
891 case MONO_TYPE_CHAR:
892 case MONO_TYPE_I2:
893 case MONO_TYPE_U2:
894 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
895 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
896 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
898 /* fall through */
899 case MONO_TYPE_BOOLEAN:
900 case MONO_TYPE_I1:
901 case MONO_TYPE_U1:
902 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
903 break;
904 case MONO_TYPE_STRING:
905 case MONO_TYPE_SZARRAY:
906 case MONO_TYPE_CLASS:
907 case MONO_TYPE_OBJECT:
908 case MONO_TYPE_ARRAY:
909 break;
910 case MONO_TYPE_GENERICINST:
911 if (!mono_type_generic_inst_is_valuetype (type)) {
912 break;
913 } else {
914 /* fall through */
916 case MONO_TYPE_VALUETYPE: {
917 MonoClass *fclass = mono_class_from_mono_type (field->type);
918 /* remove the object header */
919 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
920 break;
922 default:
923 g_assert_not_reached ();
924 break;
928 return bitmap;
932 * mono_class_insecure_overlapping:
933 * check if a class with explicit layout has references and non-references
934 * fields overlapping.
936 * Returns: TRUE if it is insecure to load the type.
938 gboolean
939 mono_class_insecure_overlapping (MonoClass *klass)
941 int max_set = 0;
942 gsize *bitmap;
943 gsize default_bitmap [4] = {0};
944 gsize *nrbitmap;
945 gsize default_nrbitmap [4] = {0};
946 int i, insecure = FALSE;
947 return FALSE;
949 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
950 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
952 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
953 int idx = i % (sizeof (bitmap [0]) * 8);
954 if (bitmap [idx] & nrbitmap [idx]) {
955 insecure = TRUE;
956 break;
959 if (bitmap != default_bitmap)
960 g_free (bitmap);
961 if (nrbitmap != default_nrbitmap)
962 g_free (nrbitmap);
963 if (insecure) {
964 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
965 return FALSE;
967 return insecure;
969 #endif
971 MonoString*
972 ves_icall_string_alloc (int length)
974 MonoError error;
975 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
976 mono_error_set_pending_exception (&error);
978 return str;
981 /* LOCKING: Acquires the loader lock */
982 void
983 mono_class_compute_gc_descriptor (MonoClass *klass)
985 MONO_REQ_GC_NEUTRAL_MODE;
987 int max_set = 0;
988 gsize *bitmap;
989 gsize default_bitmap [4] = {0};
990 static gboolean gcj_inited = FALSE;
991 MonoGCDescriptor gc_descr;
993 if (!gcj_inited) {
994 mono_loader_lock ();
996 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
997 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
999 gcj_inited = TRUE;
1000 mono_loader_unlock ();
1003 if (!klass->inited)
1004 mono_class_init (klass);
1006 if (klass->gc_descr_inited)
1007 return;
1009 bitmap = default_bitmap;
1010 if (klass == mono_defaults.string_class) {
1011 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1012 } else if (klass->rank) {
1013 mono_class_compute_gc_descriptor (klass->element_class);
1014 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1015 gsize abm = 1;
1016 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1017 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1018 class->name_space, class->name);*/
1019 } else {
1020 /* remove the object header */
1021 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1022 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));
1023 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1024 class->name_space, class->name);*/
1025 if (bitmap != default_bitmap)
1026 g_free (bitmap);
1028 } else {
1029 /*static int count = 0;
1030 if (count++ > 58)
1031 return;*/
1032 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1033 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1035 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1036 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1038 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1039 if (bitmap != default_bitmap)
1040 g_free (bitmap);
1043 /* Publish the data */
1044 mono_loader_lock ();
1045 klass->gc_descr = gc_descr;
1046 mono_memory_barrier ();
1047 klass->gc_descr_inited = TRUE;
1048 mono_loader_unlock ();
1052 * field_is_special_static:
1053 * @fklass: The MonoClass to look up.
1054 * @field: The MonoClassField describing the field.
1056 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1057 * SPECIAL_STATIC_NONE otherwise.
1059 static gint32
1060 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1062 MONO_REQ_GC_NEUTRAL_MODE;
1064 MonoError error;
1065 MonoCustomAttrInfo *ainfo;
1066 int i;
1067 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1068 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1069 if (!ainfo)
1070 return FALSE;
1071 for (i = 0; i < ainfo->num_attrs; ++i) {
1072 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1073 if (klass->image == mono_defaults.corlib) {
1074 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1075 mono_custom_attrs_free (ainfo);
1076 return SPECIAL_STATIC_THREAD;
1078 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1079 mono_custom_attrs_free (ainfo);
1080 return SPECIAL_STATIC_CONTEXT;
1084 mono_custom_attrs_free (ainfo);
1085 return SPECIAL_STATIC_NONE;
1088 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1089 #define mix(a,b,c) { \
1090 a -= c; a ^= rot(c, 4); c += b; \
1091 b -= a; b ^= rot(a, 6); a += c; \
1092 c -= b; c ^= rot(b, 8); b += a; \
1093 a -= c; a ^= rot(c,16); c += b; \
1094 b -= a; b ^= rot(a,19); a += c; \
1095 c -= b; c ^= rot(b, 4); b += a; \
1097 #define final(a,b,c) { \
1098 c ^= b; c -= rot(b,14); \
1099 a ^= c; a -= rot(c,11); \
1100 b ^= a; b -= rot(a,25); \
1101 c ^= b; c -= rot(b,16); \
1102 a ^= c; a -= rot(c,4); \
1103 b ^= a; b -= rot(a,14); \
1104 c ^= b; c -= rot(b,24); \
1108 * mono_method_get_imt_slot:
1110 * The IMT slot is embedded into AOTed code, so this must return the same value
1111 * for the same method across all executions. This means:
1112 * - pointers shouldn't be used as hash values.
1113 * - mono_metadata_str_hash () should be used for hashing strings.
1115 guint32
1116 mono_method_get_imt_slot (MonoMethod *method)
1118 MONO_REQ_GC_NEUTRAL_MODE;
1120 MonoMethodSignature *sig;
1121 int hashes_count;
1122 guint32 *hashes_start, *hashes;
1123 guint32 a, b, c;
1124 int i;
1126 /* This can be used to stress tests the collision code */
1127 //return 0;
1130 * We do this to simplify generic sharing. It will hurt
1131 * performance in cases where a class implements two different
1132 * instantiations of the same generic interface.
1133 * The code in build_imt_slots () depends on this.
1135 if (method->is_inflated)
1136 method = ((MonoMethodInflated*)method)->declaring;
1138 sig = mono_method_signature (method);
1139 hashes_count = sig->param_count + 4;
1140 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1141 hashes = hashes_start;
1143 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1144 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1145 method->klass->name_space, method->klass->name, method->name);
1148 /* Initialize hashes */
1149 hashes [0] = mono_metadata_str_hash (method->klass->name);
1150 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1151 hashes [2] = mono_metadata_str_hash (method->name);
1152 hashes [3] = mono_metadata_type_hash (sig->ret);
1153 for (i = 0; i < sig->param_count; i++) {
1154 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1157 /* Setup internal state */
1158 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1160 /* Handle most of the hashes */
1161 while (hashes_count > 3) {
1162 a += hashes [0];
1163 b += hashes [1];
1164 c += hashes [2];
1165 mix (a,b,c);
1166 hashes_count -= 3;
1167 hashes += 3;
1170 /* Handle the last 3 hashes (all the case statements fall through) */
1171 switch (hashes_count) {
1172 case 3 : c += hashes [2];
1173 case 2 : b += hashes [1];
1174 case 1 : a += hashes [0];
1175 final (a,b,c);
1176 case 0: /* nothing left to add */
1177 break;
1180 g_free (hashes_start);
1181 /* Report the result */
1182 return c % MONO_IMT_SIZE;
1184 #undef rot
1185 #undef mix
1186 #undef final
1188 #define DEBUG_IMT 0
1190 static void
1191 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1192 MONO_REQ_GC_NEUTRAL_MODE;
1194 guint32 imt_slot = mono_method_get_imt_slot (method);
1195 MonoImtBuilderEntry *entry;
1197 if (slot_num >= 0 && imt_slot != slot_num) {
1198 /* we build just a single imt slot and this is not it */
1199 return;
1202 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1203 entry->key = method;
1204 entry->value.vtable_slot = vtable_slot;
1205 entry->next = imt_builder [imt_slot];
1206 if (imt_builder [imt_slot] != NULL) {
1207 entry->children = imt_builder [imt_slot]->children + 1;
1208 if (entry->children == 1) {
1209 mono_stats.imt_slots_with_collisions++;
1210 *imt_collisions_bitmap |= (1 << imt_slot);
1212 } else {
1213 entry->children = 0;
1214 mono_stats.imt_used_slots++;
1216 imt_builder [imt_slot] = entry;
1217 #if DEBUG_IMT
1219 char *method_name = mono_method_full_name (method, TRUE);
1220 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1221 method, method_name, imt_slot, vtable_slot, entry->children);
1222 g_free (method_name);
1224 #endif
1227 #if DEBUG_IMT
1228 static void
1229 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1230 if (e != NULL) {
1231 MonoMethod *method = e->key;
1232 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1233 message,
1234 num,
1235 method,
1236 method->klass->name_space,
1237 method->klass->name,
1238 method->name);
1239 } else {
1240 printf (" * %s: NULL\n", message);
1243 #endif
1245 static int
1246 compare_imt_builder_entries (const void *p1, const void *p2) {
1247 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1248 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1250 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1253 static int
1254 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1256 MONO_REQ_GC_NEUTRAL_MODE;
1258 int count = end - start;
1259 int chunk_start = out_array->len;
1260 if (count < 4) {
1261 int i;
1262 for (i = start; i < end; ++i) {
1263 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1264 item->key = sorted_array [i]->key;
1265 item->value = sorted_array [i]->value;
1266 item->has_target_code = sorted_array [i]->has_target_code;
1267 item->is_equals = TRUE;
1268 if (i < end - 1)
1269 item->check_target_idx = out_array->len + 1;
1270 else
1271 item->check_target_idx = 0;
1272 g_ptr_array_add (out_array, item);
1274 } else {
1275 int middle = start + count / 2;
1276 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1278 item->key = sorted_array [middle]->key;
1279 item->is_equals = FALSE;
1280 g_ptr_array_add (out_array, item);
1281 imt_emit_ir (sorted_array, start, middle, out_array);
1282 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1284 return chunk_start;
1287 static GPtrArray*
1288 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1289 MONO_REQ_GC_NEUTRAL_MODE;
1291 int number_of_entries = entries->children + 1;
1292 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1293 GPtrArray *result = g_ptr_array_new ();
1294 MonoImtBuilderEntry *current_entry;
1295 int i;
1297 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1298 sorted_array [i] = current_entry;
1300 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1302 /*for (i = 0; i < number_of_entries; i++) {
1303 print_imt_entry (" sorted array:", sorted_array [i], i);
1306 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1308 g_free (sorted_array);
1309 return result;
1312 static gpointer
1313 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1315 MONO_REQ_GC_NEUTRAL_MODE;
1317 if (imt_builder_entry != NULL) {
1318 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1319 /* No collision, return the vtable slot contents */
1320 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1321 } else {
1322 /* Collision, build the trampoline */
1323 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1324 gpointer result;
1325 int i;
1326 result = imt_trampoline_builder (vtable, domain,
1327 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1328 for (i = 0; i < imt_ir->len; ++i)
1329 g_free (g_ptr_array_index (imt_ir, i));
1330 g_ptr_array_free (imt_ir, TRUE);
1331 return result;
1333 } else {
1334 if (fail_tramp)
1335 return fail_tramp;
1336 else
1337 /* Empty slot */
1338 return NULL;
1342 static MonoImtBuilderEntry*
1343 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1346 * LOCKING: requires the loader and domain locks.
1349 static void
1350 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1352 MONO_REQ_GC_NEUTRAL_MODE;
1354 int i;
1355 GSList *list_item;
1356 guint32 imt_collisions_bitmap = 0;
1357 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1358 int method_count = 0;
1359 gboolean record_method_count_for_max_collisions = FALSE;
1360 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1362 #if DEBUG_IMT
1363 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1364 #endif
1365 for (i = 0; i < klass->interface_offsets_count; ++i) {
1366 MonoClass *iface = klass->interfaces_packed [i];
1367 int interface_offset = klass->interface_offsets_packed [i];
1368 int method_slot_in_interface, vt_slot;
1370 if (mono_class_has_variant_generic_params (iface))
1371 has_variant_iface = TRUE;
1373 mono_class_setup_methods (iface);
1374 vt_slot = interface_offset;
1375 int mcount = mono_class_get_method_count (iface);
1376 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1377 MonoMethod *method;
1379 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1381 * The imt slot of the method is the same as for its declaring method,
1382 * see the comment in mono_method_get_imt_slot (), so we can
1383 * avoid inflating methods which will be discarded by
1384 * add_imt_builder_entry anyway.
1386 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1387 if (mono_method_get_imt_slot (method) != slot_num) {
1388 vt_slot ++;
1389 continue;
1392 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1393 if (method->is_generic) {
1394 has_generic_virtual = TRUE;
1395 vt_slot ++;
1396 continue;
1399 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1400 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1401 vt_slot ++;
1405 if (extra_interfaces) {
1406 int interface_offset = klass->vtable_size;
1408 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1409 MonoClass* iface = (MonoClass *)list_item->data;
1410 int method_slot_in_interface;
1411 int mcount = mono_class_get_method_count (iface);
1412 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1413 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1415 if (method->is_generic)
1416 has_generic_virtual = TRUE;
1417 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1419 interface_offset += mcount;
1422 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1423 /* overwrite the imt slot only if we're building all the entries or if
1424 * we're building this specific one
1426 if (slot_num < 0 || i == slot_num) {
1427 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1429 if (entries) {
1430 if (imt_builder [i]) {
1431 MonoImtBuilderEntry *entry;
1433 /* Link entries with imt_builder [i] */
1434 for (entry = entries; entry->next; entry = entry->next) {
1435 #if DEBUG_IMT
1436 MonoMethod *method = (MonoMethod*)entry->key;
1437 char *method_name = mono_method_full_name (method, TRUE);
1438 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1439 g_free (method_name);
1440 #endif
1442 entry->next = imt_builder [i];
1443 entries->children += imt_builder [i]->children + 1;
1445 imt_builder [i] = entries;
1448 if (has_generic_virtual || has_variant_iface) {
1450 * There might be collisions later when the the trampoline is expanded.
1452 imt_collisions_bitmap |= (1 << i);
1455 * The IMT trampoline might be called with an instance of one of the
1456 * generic virtual methods, so has to fallback to the IMT trampoline.
1458 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1459 } else {
1460 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1462 #if DEBUG_IMT
1463 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1464 #endif
1467 if (imt_builder [i] != NULL) {
1468 int methods_in_slot = imt_builder [i]->children + 1;
1469 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1470 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1471 record_method_count_for_max_collisions = TRUE;
1473 method_count += methods_in_slot;
1477 mono_stats.imt_number_of_methods += method_count;
1478 if (record_method_count_for_max_collisions) {
1479 mono_stats.imt_method_count_when_max_collisions = method_count;
1482 for (i = 0; i < MONO_IMT_SIZE; i++) {
1483 MonoImtBuilderEntry* entry = imt_builder [i];
1484 while (entry != NULL) {
1485 MonoImtBuilderEntry* next = entry->next;
1486 g_free (entry);
1487 entry = next;
1490 g_free (imt_builder);
1491 /* we OR the bitmap since we may build just a single imt slot at a time */
1492 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1495 static void
1496 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1497 MONO_REQ_GC_NEUTRAL_MODE;
1499 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1503 * mono_vtable_build_imt_slot:
1504 * @vtable: virtual object table struct
1505 * @imt_slot: slot in the IMT table
1507 * Fill the given @imt_slot in the IMT table of @vtable with
1508 * a trampoline or a trampoline for the case of collisions.
1509 * This is part of the internal mono API.
1511 * LOCKING: Take the domain lock.
1513 void
1514 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1516 MONO_REQ_GC_NEUTRAL_MODE;
1518 gpointer *imt = (gpointer*)vtable;
1519 imt -= MONO_IMT_SIZE;
1520 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1522 /* no support for extra interfaces: the proxy objects will need
1523 * to build the complete IMT
1524 * Update and heck needs to ahppen inside the proper domain lock, as all
1525 * the changes made to a MonoVTable.
1527 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1528 mono_domain_lock (vtable->domain);
1529 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1530 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1531 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1532 mono_domain_unlock (vtable->domain);
1533 mono_loader_unlock ();
1536 #define THUNK_THRESHOLD 10
1539 * mono_method_alloc_generic_virtual_trampoline:
1540 * @domain: a domain
1541 * @size: size in bytes
1543 * Allocs size bytes to be used for the code of a generic virtual
1544 * trampoline. It's either allocated from the domain's code manager or
1545 * reused from a previously invalidated piece.
1547 * LOCKING: The domain lock must be held.
1549 gpointer
1550 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1552 MONO_REQ_GC_NEUTRAL_MODE;
1554 static gboolean inited = FALSE;
1555 static int generic_virtual_trampolines_size = 0;
1557 if (!inited) {
1558 mono_counters_register ("Generic virtual trampoline bytes",
1559 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1560 inited = TRUE;
1562 generic_virtual_trampolines_size += size;
1564 return mono_domain_code_reserve (domain, size);
1567 typedef struct _GenericVirtualCase {
1568 MonoMethod *method;
1569 gpointer code;
1570 int count;
1571 struct _GenericVirtualCase *next;
1572 } GenericVirtualCase;
1575 * get_generic_virtual_entries:
1577 * Return IMT entries for the generic virtual method instances and
1578 * variant interface methods for vtable slot
1579 * VTABLE_SLOT.
1581 static MonoImtBuilderEntry*
1582 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1584 MONO_REQ_GC_NEUTRAL_MODE;
1586 GenericVirtualCase *list;
1587 MonoImtBuilderEntry *entries;
1589 mono_domain_lock (domain);
1590 if (!domain->generic_virtual_cases)
1591 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1593 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1595 entries = NULL;
1596 for (; list; list = list->next) {
1597 MonoImtBuilderEntry *entry;
1599 if (list->count < THUNK_THRESHOLD)
1600 continue;
1602 entry = g_new0 (MonoImtBuilderEntry, 1);
1603 entry->key = list->method;
1604 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1605 entry->has_target_code = 1;
1606 if (entries)
1607 entry->children = entries->children + 1;
1608 entry->next = entries;
1609 entries = entry;
1612 mono_domain_unlock (domain);
1614 /* FIXME: Leaking memory ? */
1615 return entries;
1619 * mono_method_add_generic_virtual_invocation:
1620 * @domain: a domain
1621 * @vtable_slot: pointer to the vtable slot
1622 * @method: the inflated generic virtual method
1623 * @code: the method's code
1625 * Registers a call via unmanaged code to a generic virtual method
1626 * instantiation or variant interface method. If the number of calls reaches a threshold
1627 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1628 * virtual method trampoline.
1630 void
1631 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1632 gpointer *vtable_slot,
1633 MonoMethod *method, gpointer code)
1635 MONO_REQ_GC_NEUTRAL_MODE;
1637 static gboolean inited = FALSE;
1638 static int num_added = 0;
1639 static int num_freed = 0;
1641 GenericVirtualCase *gvc, *list;
1642 MonoImtBuilderEntry *entries;
1643 int i;
1644 GPtrArray *sorted;
1646 mono_domain_lock (domain);
1647 if (!domain->generic_virtual_cases)
1648 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1650 if (!inited) {
1651 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1652 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1653 inited = TRUE;
1656 /* Check whether the case was already added */
1657 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1658 gvc = list;
1659 while (gvc) {
1660 if (gvc->method == method)
1661 break;
1662 gvc = gvc->next;
1665 /* If not found, make a new one */
1666 if (!gvc) {
1667 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1668 gvc->method = method;
1669 gvc->code = code;
1670 gvc->count = 0;
1671 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1673 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1675 num_added++;
1678 if (++gvc->count == THUNK_THRESHOLD) {
1679 gpointer *old_thunk = (void **)*vtable_slot;
1680 gpointer vtable_trampoline = NULL;
1681 gpointer imt_trampoline = NULL;
1683 if ((gpointer)vtable_slot < (gpointer)vtable) {
1684 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1685 int imt_slot = MONO_IMT_SIZE + displacement;
1687 /* Force the rebuild of the trampoline at the next call */
1688 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1689 *vtable_slot = imt_trampoline;
1690 } else {
1691 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1693 entries = get_generic_virtual_entries (domain, vtable_slot);
1695 sorted = imt_sort_slot_entries (entries);
1697 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1698 vtable_trampoline);
1700 while (entries) {
1701 MonoImtBuilderEntry *next = entries->next;
1702 g_free (entries);
1703 entries = next;
1706 for (i = 0; i < sorted->len; ++i)
1707 g_free (g_ptr_array_index (sorted, i));
1708 g_ptr_array_free (sorted, TRUE);
1710 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1711 num_freed ++;
1715 mono_domain_unlock (domain);
1718 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1721 * mono_class_vtable:
1722 * @domain: the application domain
1723 * @class: the class to initialize
1725 * VTables are domain specific because we create domain specific code, and
1726 * they contain the domain specific static class data.
1727 * On failure, NULL is returned, and class->exception_type is set.
1729 MonoVTable *
1730 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1732 MonoError error;
1733 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1734 mono_error_cleanup (&error);
1735 return vtable;
1739 * mono_class_vtable_full:
1740 * @domain: the application domain
1741 * @class: the class to initialize
1742 * @error set on failure.
1744 * VTables are domain specific because we create domain specific code, and
1745 * they contain the domain specific static class data.
1747 MonoVTable *
1748 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1750 MONO_REQ_GC_UNSAFE_MODE;
1752 MonoClassRuntimeInfo *runtime_info;
1754 mono_error_init (error);
1756 g_assert (klass);
1758 if (mono_class_has_failure (klass)) {
1759 mono_error_set_for_class_failure (error, klass);
1760 return NULL;
1763 /* this check can be inlined in jitted code, too */
1764 runtime_info = klass->runtime_info;
1765 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1766 return runtime_info->domain_vtables [domain->domain_id];
1767 return mono_class_create_runtime_vtable (domain, klass, error);
1771 * mono_class_try_get_vtable:
1772 * @domain: the application domain
1773 * @class: the class to initialize
1775 * This function tries to get the associated vtable from @class if
1776 * it was already created.
1778 MonoVTable *
1779 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1781 MONO_REQ_GC_NEUTRAL_MODE;
1783 MonoClassRuntimeInfo *runtime_info;
1785 g_assert (klass);
1787 runtime_info = klass->runtime_info;
1788 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1789 return runtime_info->domain_vtables [domain->domain_id];
1790 return NULL;
1793 static gpointer*
1794 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1796 MONO_REQ_GC_NEUTRAL_MODE;
1798 size_t alloc_offset;
1801 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1802 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1803 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1805 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1806 g_assert ((imt_table_bytes & 7) == 4);
1807 vtable_size += 4;
1808 alloc_offset = 4;
1809 } else {
1810 alloc_offset = 0;
1813 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1816 static MonoVTable *
1817 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1819 MONO_REQ_GC_UNSAFE_MODE;
1821 MonoVTable *vt;
1822 MonoClassRuntimeInfo *runtime_info, *old_info;
1823 MonoClassField *field;
1824 char *t;
1825 int i, vtable_slots;
1826 size_t imt_table_bytes;
1827 int gc_bits;
1828 guint32 vtable_size, class_size;
1829 gpointer iter;
1830 gpointer *interface_offsets;
1832 mono_error_init (error);
1834 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1835 mono_domain_lock (domain);
1836 runtime_info = klass->runtime_info;
1837 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1838 mono_domain_unlock (domain);
1839 mono_loader_unlock ();
1840 return runtime_info->domain_vtables [domain->domain_id];
1842 if (!klass->inited || mono_class_has_failure (klass)) {
1843 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1844 mono_domain_unlock (domain);
1845 mono_loader_unlock ();
1846 mono_error_set_for_class_failure (error, klass);
1847 return NULL;
1851 /* Array types require that their element type be valid*/
1852 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1853 MonoClass *element_class = klass->element_class;
1854 if (!element_class->inited)
1855 mono_class_init (element_class);
1857 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1858 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1859 mono_class_setup_vtable (element_class);
1861 if (mono_class_has_failure (element_class)) {
1862 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1863 if (!mono_class_has_failure (klass))
1864 mono_class_set_type_load_failure (klass, "");
1865 mono_domain_unlock (domain);
1866 mono_loader_unlock ();
1867 mono_error_set_for_class_failure (error, klass);
1868 return NULL;
1873 * For some classes, mono_class_init () already computed klass->vtable_size, and
1874 * that is all that is needed because of the vtable trampolines.
1876 if (!klass->vtable_size)
1877 mono_class_setup_vtable (klass);
1879 if (mono_class_is_ginst (klass) && !klass->vtable)
1880 mono_class_check_vtable_constraints (klass, NULL);
1882 /* Initialize klass->has_finalize */
1883 mono_class_has_finalizer (klass);
1885 if (mono_class_has_failure (klass)) {
1886 mono_domain_unlock (domain);
1887 mono_loader_unlock ();
1888 mono_error_set_for_class_failure (error, klass);
1889 return NULL;
1892 vtable_slots = klass->vtable_size;
1893 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1894 class_size = mono_class_data_size (klass);
1895 if (class_size)
1896 vtable_slots++;
1898 if (klass->interface_offsets_count) {
1899 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1900 mono_stats.imt_number_of_tables++;
1901 mono_stats.imt_tables_size += imt_table_bytes;
1902 } else {
1903 imt_table_bytes = 0;
1906 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1908 mono_stats.used_class_count++;
1909 mono_stats.class_vtable_size += vtable_size;
1911 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1912 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1913 g_assert (!((gsize)vt & 7));
1915 vt->klass = klass;
1916 vt->rank = klass->rank;
1917 vt->domain = domain;
1919 mono_class_compute_gc_descriptor (klass);
1921 * We can't use typed allocation in the non-root domains, since the
1922 * collector needs the GC descriptor stored in the vtable even after
1923 * the mempool containing the vtable is destroyed when the domain is
1924 * unloaded. An alternative might be to allocate vtables in the GC
1925 * heap, but this does not seem to work (it leads to crashes inside
1926 * libgc). If that approach is tried, two gc descriptors need to be
1927 * allocated for each class: one for the root domain, and one for all
1928 * other domains. The second descriptor should contain a bit for the
1929 * vtable field in MonoObject, since we can no longer assume the
1930 * vtable is reachable by other roots after the appdomain is unloaded.
1932 #ifdef HAVE_BOEHM_GC
1933 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1934 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1935 else
1936 #endif
1937 vt->gc_descr = klass->gc_descr;
1939 gc_bits = mono_gc_get_vtable_bits (klass);
1940 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1942 vt->gc_bits = gc_bits;
1944 if (class_size) {
1945 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1946 if (klass->has_static_refs) {
1947 MonoGCDescriptor statics_gc_descr;
1948 int max_set = 0;
1949 gsize default_bitmap [4] = {0};
1950 gsize *bitmap;
1952 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1953 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1954 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1955 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1956 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1957 if (bitmap != default_bitmap)
1958 g_free (bitmap);
1959 } else {
1960 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1962 vt->has_static_fields = TRUE;
1963 mono_stats.class_static_data_size += class_size;
1966 iter = NULL;
1967 while ((field = mono_class_get_fields (klass, &iter))) {
1968 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1969 continue;
1970 if (mono_field_is_deleted (field))
1971 continue;
1972 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1973 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1974 if (special_static != SPECIAL_STATIC_NONE) {
1975 guint32 size, offset;
1976 gint32 align;
1977 gsize default_bitmap [4] = {0};
1978 gsize *bitmap;
1979 int max_set = 0;
1980 int numbits;
1981 MonoClass *fclass;
1982 if (mono_type_is_reference (field->type)) {
1983 default_bitmap [0] = 1;
1984 numbits = 1;
1985 bitmap = default_bitmap;
1986 } else if (mono_type_is_struct (field->type)) {
1987 fclass = mono_class_from_mono_type (field->type);
1988 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1989 numbits = max_set + 1;
1990 } else {
1991 default_bitmap [0] = 0;
1992 numbits = 0;
1993 bitmap = default_bitmap;
1995 size = mono_type_size (field->type, &align);
1996 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1997 if (!domain->special_static_fields)
1998 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1999 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2000 if (bitmap != default_bitmap)
2001 g_free (bitmap);
2003 * This marks the field as special static to speed up the
2004 * checks in mono_field_static_get/set_value ().
2006 field->offset = -1;
2007 continue;
2010 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2011 MonoClass *fklass = mono_class_from_mono_type (field->type);
2012 const char *data = mono_field_get_data (field);
2014 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2015 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2016 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2017 if (!data)
2018 continue;
2019 if (fklass->valuetype) {
2020 memcpy (t, data, mono_class_value_size (fklass, NULL));
2021 } else {
2022 /* it's a pointer type: add check */
2023 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2024 *t = *(char *)data;
2026 continue;
2030 vt->max_interface_id = klass->max_interface_id;
2031 vt->interface_bitmap = klass->interface_bitmap;
2033 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2034 // class->name, klass->interface_offsets_count);
2036 /* Initialize vtable */
2037 if (callbacks.get_vtable_trampoline) {
2038 // This also covers the AOT case
2039 for (i = 0; i < klass->vtable_size; ++i) {
2040 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2042 } else {
2043 mono_class_setup_vtable (klass);
2045 for (i = 0; i < klass->vtable_size; ++i) {
2046 MonoMethod *cm;
2048 cm = klass->vtable [i];
2049 if (cm) {
2050 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2051 if (!is_ok (error)) {
2052 mono_domain_unlock (domain);
2053 mono_loader_unlock ();
2054 return NULL;
2060 if (imt_table_bytes) {
2061 /* Now that the vtable is full, we can actually fill up the IMT */
2062 for (i = 0; i < MONO_IMT_SIZE; ++i)
2063 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2067 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2068 * re-acquire them and check if another thread has created the vtable in the meantime.
2070 /* Special case System.MonoType to avoid infinite recursion */
2071 if (klass != mono_defaults.runtimetype_class) {
2072 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2073 if (!is_ok (error)) {
2074 mono_domain_unlock (domain);
2075 mono_loader_unlock ();
2076 return NULL;
2079 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2080 /* This is unregistered in
2081 unregister_vtable_reflection_type() in
2082 domain.c. */
2083 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2086 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2088 /* class_vtable_array keeps an array of created vtables
2090 g_ptr_array_add (domain->class_vtable_array, vt);
2091 /* klass->runtime_info is protected by the loader lock, both when
2092 * it it enlarged and when it is stored info.
2096 * Store the vtable in klass->runtime_info.
2097 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2099 mono_memory_barrier ();
2101 old_info = klass->runtime_info;
2102 if (old_info && old_info->max_domain >= domain->domain_id) {
2103 /* someone already created a large enough runtime info */
2104 old_info->domain_vtables [domain->domain_id] = vt;
2105 } else {
2106 int new_size = domain->domain_id;
2107 if (old_info)
2108 new_size = MAX (new_size, old_info->max_domain);
2109 new_size++;
2110 /* make the new size a power of two */
2111 i = 2;
2112 while (new_size > i)
2113 i <<= 1;
2114 new_size = i;
2115 /* this is a bounded memory retention issue: may want to
2116 * handle it differently when we'll have a rcu-like system.
2118 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2119 runtime_info->max_domain = new_size - 1;
2120 /* copy the stuff from the older info */
2121 if (old_info) {
2122 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2124 runtime_info->domain_vtables [domain->domain_id] = vt;
2125 /* keep this last*/
2126 mono_memory_barrier ();
2127 klass->runtime_info = runtime_info;
2130 if (klass == mono_defaults.runtimetype_class) {
2131 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2132 if (!is_ok (error)) {
2133 mono_domain_unlock (domain);
2134 mono_loader_unlock ();
2135 return NULL;
2138 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2139 /* This is unregistered in
2140 unregister_vtable_reflection_type() in
2141 domain.c. */
2142 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2145 mono_domain_unlock (domain);
2146 mono_loader_unlock ();
2148 /* make sure the parent is initialized */
2149 /*FIXME shouldn't this fail the current type?*/
2150 if (klass->parent)
2151 mono_class_vtable_full (domain, klass->parent, error);
2153 return vt;
2156 #ifndef DISABLE_REMOTING
2158 * mono_class_proxy_vtable:
2159 * @domain: the application domain
2160 * @remove_class: the remote class
2161 * @error: set on error
2163 * Creates a vtable for transparent proxies. It is basically
2164 * a copy of the real vtable of the class wrapped in @remote_class,
2165 * but all function pointers invoke the remoting functions, and
2166 * vtable->klass points to the transparent proxy class, and not to @class.
2168 * On failure returns NULL and sets @error
2170 static MonoVTable *
2171 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2173 MONO_REQ_GC_UNSAFE_MODE;
2175 MonoVTable *vt, *pvt;
2176 int i, j, vtsize, extra_interface_vtsize = 0;
2177 guint32 max_interface_id;
2178 MonoClass *k;
2179 GSList *extra_interfaces = NULL;
2180 MonoClass *klass = remote_class->proxy_class;
2181 gpointer *interface_offsets;
2182 uint8_t *bitmap = NULL;
2183 int bsize;
2184 size_t imt_table_bytes;
2186 #ifdef COMPRESSED_INTERFACE_BITMAP
2187 int bcsize;
2188 #endif
2190 mono_error_init (error);
2192 vt = mono_class_vtable (domain, klass);
2193 g_assert (vt); /*FIXME property handle failure*/
2194 max_interface_id = vt->max_interface_id;
2196 /* Calculate vtable space for extra interfaces */
2197 for (j = 0; j < remote_class->interface_count; j++) {
2198 MonoClass* iclass = remote_class->interfaces[j];
2199 GPtrArray *ifaces;
2200 int method_count;
2202 /*FIXME test for interfaces with variant generic arguments*/
2203 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2204 continue; /* interface implemented by the class */
2205 if (g_slist_find (extra_interfaces, iclass))
2206 continue;
2208 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2210 method_count = mono_class_num_methods (iclass);
2212 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2213 if (!is_ok (error))
2214 goto failure;
2215 if (ifaces) {
2216 for (i = 0; i < ifaces->len; ++i) {
2217 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2218 /*FIXME test for interfaces with variant generic arguments*/
2219 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2220 continue; /* interface implemented by the class */
2221 if (g_slist_find (extra_interfaces, ic))
2222 continue;
2223 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2224 method_count += mono_class_num_methods (ic);
2226 g_ptr_array_free (ifaces, TRUE);
2227 ifaces = NULL;
2230 extra_interface_vtsize += method_count * sizeof (gpointer);
2231 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2234 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2235 mono_stats.imt_number_of_tables++;
2236 mono_stats.imt_tables_size += imt_table_bytes;
2238 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2240 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2242 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2243 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2244 g_assert (!((gsize)pvt & 7));
2246 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2248 pvt->klass = mono_defaults.transparent_proxy_class;
2249 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2250 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2252 /* initialize vtable */
2253 mono_class_setup_vtable (klass);
2254 for (i = 0; i < klass->vtable_size; ++i) {
2255 MonoMethod *cm;
2257 if ((cm = klass->vtable [i])) {
2258 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2259 if (!is_ok (error))
2260 goto failure;
2261 } else
2262 pvt->vtable [i] = NULL;
2265 if (mono_class_is_abstract (klass)) {
2266 /* create trampolines for abstract methods */
2267 for (k = klass; k; k = k->parent) {
2268 MonoMethod* m;
2269 gpointer iter = NULL;
2270 while ((m = mono_class_get_methods (k, &iter)))
2271 if (!pvt->vtable [m->slot]) {
2272 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2273 if (!is_ok (error))
2274 goto failure;
2279 pvt->max_interface_id = max_interface_id;
2280 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2281 #ifdef COMPRESSED_INTERFACE_BITMAP
2282 bitmap = (uint8_t *)g_malloc0 (bsize);
2283 #else
2284 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2285 #endif
2287 for (i = 0; i < klass->interface_offsets_count; ++i) {
2288 int interface_id = klass->interfaces_packed [i]->interface_id;
2289 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2292 if (extra_interfaces) {
2293 int slot = klass->vtable_size;
2294 MonoClass* interf;
2295 gpointer iter;
2296 MonoMethod* cm;
2297 GSList *list_item;
2299 /* Create trampolines for the methods of the interfaces */
2300 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2301 interf = (MonoClass *)list_item->data;
2303 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2305 iter = NULL;
2306 j = 0;
2307 while ((cm = mono_class_get_methods (interf, &iter))) {
2308 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2309 if (!is_ok (error))
2310 goto failure;
2313 slot += mono_class_num_methods (interf);
2317 /* Now that the vtable is full, we can actually fill up the IMT */
2318 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2319 if (extra_interfaces) {
2320 g_slist_free (extra_interfaces);
2323 #ifdef COMPRESSED_INTERFACE_BITMAP
2324 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2325 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2326 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2327 g_free (bitmap);
2328 #else
2329 pvt->interface_bitmap = bitmap;
2330 #endif
2331 return pvt;
2332 failure:
2333 if (extra_interfaces)
2334 g_slist_free (extra_interfaces);
2335 #ifdef COMPRESSED_INTERFACE_BITMAP
2336 g_free (bitmap);
2337 #endif
2338 return NULL;
2341 #endif /* DISABLE_REMOTING */
2344 * mono_class_field_is_special_static:
2346 * Returns whether @field is a thread/context static field.
2348 gboolean
2349 mono_class_field_is_special_static (MonoClassField *field)
2351 MONO_REQ_GC_NEUTRAL_MODE
2353 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2354 return FALSE;
2355 if (mono_field_is_deleted (field))
2356 return FALSE;
2357 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2358 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2359 return TRUE;
2361 return FALSE;
2365 * mono_class_field_get_special_static_type:
2366 * @field: The MonoClassField describing the field.
2368 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2369 * SPECIAL_STATIC_NONE otherwise.
2371 guint32
2372 mono_class_field_get_special_static_type (MonoClassField *field)
2374 MONO_REQ_GC_NEUTRAL_MODE
2376 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2377 return SPECIAL_STATIC_NONE;
2378 if (mono_field_is_deleted (field))
2379 return SPECIAL_STATIC_NONE;
2380 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2381 return field_is_special_static (field->parent, field);
2382 return SPECIAL_STATIC_NONE;
2386 * mono_class_has_special_static_fields:
2388 * Returns whenever @klass has any thread/context static fields.
2390 gboolean
2391 mono_class_has_special_static_fields (MonoClass *klass)
2393 MONO_REQ_GC_NEUTRAL_MODE
2395 MonoClassField *field;
2396 gpointer iter;
2398 iter = NULL;
2399 while ((field = mono_class_get_fields (klass, &iter))) {
2400 g_assert (field->parent == klass);
2401 if (mono_class_field_is_special_static (field))
2402 return TRUE;
2405 return FALSE;
2408 #ifndef DISABLE_REMOTING
2410 * create_remote_class_key:
2411 * Creates an array of pointers that can be used as a hash key for a remote class.
2412 * The first element of the array is the number of pointers.
2414 static gpointer*
2415 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2417 MONO_REQ_GC_NEUTRAL_MODE;
2419 gpointer *key;
2420 int i, j;
2422 if (remote_class == NULL) {
2423 if (mono_class_is_interface (extra_class)) {
2424 key = (void **)g_malloc (sizeof(gpointer) * 3);
2425 key [0] = GINT_TO_POINTER (2);
2426 key [1] = mono_defaults.marshalbyrefobject_class;
2427 key [2] = extra_class;
2428 } else {
2429 key = (void **)g_malloc (sizeof(gpointer) * 2);
2430 key [0] = GINT_TO_POINTER (1);
2431 key [1] = extra_class;
2433 } else {
2434 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2435 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2436 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2437 key [1] = remote_class->proxy_class;
2439 // Keep the list of interfaces sorted
2440 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2441 if (extra_class && remote_class->interfaces [i] > extra_class) {
2442 key [j++] = extra_class;
2443 extra_class = NULL;
2445 key [j] = remote_class->interfaces [i];
2447 if (extra_class)
2448 key [j] = extra_class;
2449 } else {
2450 // Replace the old class. The interface list is the same
2451 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2452 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2453 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2454 for (i = 0; i < remote_class->interface_count; i++)
2455 key [2 + i] = remote_class->interfaces [i];
2459 return key;
2463 * copy_remote_class_key:
2465 * Make a copy of KEY in the domain and return the copy.
2467 static gpointer*
2468 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2470 MONO_REQ_GC_NEUTRAL_MODE
2472 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2473 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2475 memcpy (mp_key, key, key_size);
2477 return mp_key;
2481 * mono_remote_class:
2482 * @domain: the application domain
2483 * @class_name: name of the remote class
2484 * @error: set on error
2486 * Creates and initializes a MonoRemoteClass object for a remote type.
2488 * On failure returns NULL and sets @error
2490 MonoRemoteClass*
2491 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2493 MONO_REQ_GC_UNSAFE_MODE;
2495 MonoRemoteClass *rc;
2496 gpointer* key, *mp_key;
2497 char *name;
2499 mono_error_init (error);
2501 key = create_remote_class_key (NULL, proxy_class);
2503 mono_domain_lock (domain);
2504 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2506 if (rc) {
2507 g_free (key);
2508 mono_domain_unlock (domain);
2509 return rc;
2512 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2513 if (!is_ok (error)) {
2514 g_free (key);
2515 mono_domain_unlock (domain);
2516 return NULL;
2519 mp_key = copy_remote_class_key (domain, key);
2520 g_free (key);
2521 key = mp_key;
2523 if (mono_class_is_interface (proxy_class)) {
2524 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2525 rc->interface_count = 1;
2526 rc->interfaces [0] = proxy_class;
2527 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2528 } else {
2529 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2530 rc->interface_count = 0;
2531 rc->proxy_class = proxy_class;
2534 rc->default_vtable = NULL;
2535 rc->xdomain_vtable = NULL;
2536 rc->proxy_class_name = name;
2537 #ifndef DISABLE_PERFCOUNTERS
2538 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2539 #endif
2541 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2543 mono_domain_unlock (domain);
2544 return rc;
2548 * clone_remote_class:
2549 * Creates a copy of the remote_class, adding the provided class or interface
2551 static MonoRemoteClass*
2552 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2554 MONO_REQ_GC_NEUTRAL_MODE;
2556 MonoRemoteClass *rc;
2557 gpointer* key, *mp_key;
2559 key = create_remote_class_key (remote_class, extra_class);
2560 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2561 if (rc != NULL) {
2562 g_free (key);
2563 return rc;
2566 mp_key = copy_remote_class_key (domain, key);
2567 g_free (key);
2568 key = mp_key;
2570 if (mono_class_is_interface (extra_class)) {
2571 int i,j;
2572 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2573 rc->proxy_class = remote_class->proxy_class;
2574 rc->interface_count = remote_class->interface_count + 1;
2576 // Keep the list of interfaces sorted, since the hash key of
2577 // the remote class depends on this
2578 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2579 if (remote_class->interfaces [i] > extra_class && i == j)
2580 rc->interfaces [j++] = extra_class;
2581 rc->interfaces [j] = remote_class->interfaces [i];
2583 if (i == j)
2584 rc->interfaces [j] = extra_class;
2585 } else {
2586 // Replace the old class. The interface array is the same
2587 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2588 rc->proxy_class = extra_class;
2589 rc->interface_count = remote_class->interface_count;
2590 if (rc->interface_count > 0)
2591 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2594 rc->default_vtable = NULL;
2595 rc->xdomain_vtable = NULL;
2596 rc->proxy_class_name = remote_class->proxy_class_name;
2598 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2600 return rc;
2603 gpointer
2604 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2606 MONO_REQ_GC_UNSAFE_MODE;
2608 mono_error_init (error);
2610 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2611 mono_domain_lock (domain);
2612 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2613 if (target_domain_id != -1) {
2614 if (remote_class->xdomain_vtable == NULL)
2615 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2616 mono_domain_unlock (domain);
2617 mono_loader_unlock ();
2618 return_val_if_nok (error, NULL);
2619 return remote_class->xdomain_vtable;
2621 if (remote_class->default_vtable == NULL) {
2622 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2623 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2625 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2626 MonoClass *klass = mono_class_from_mono_type (type);
2627 #ifndef DISABLE_COM
2628 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)))
2629 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2630 else
2631 #endif
2632 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2633 /* N.B. both branches of the if modify error */
2634 if (!is_ok (error)) {
2635 mono_domain_unlock (domain);
2636 mono_loader_unlock ();
2637 return NULL;
2641 mono_domain_unlock (domain);
2642 mono_loader_unlock ();
2643 return remote_class->default_vtable;
2647 * mono_upgrade_remote_class:
2648 * @domain: the application domain
2649 * @tproxy: the proxy whose remote class has to be upgraded.
2650 * @klass: class to which the remote class can be casted.
2651 * @error: set on error
2653 * Updates the vtable of the remote class by adding the necessary method slots
2654 * and interface offsets so it can be safely casted to klass. klass can be a
2655 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2657 gboolean
2658 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2660 MONO_REQ_GC_UNSAFE_MODE;
2662 mono_error_init (error);
2664 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2665 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2667 gboolean redo_vtable;
2668 if (mono_class_is_interface (klass)) {
2669 int i;
2670 redo_vtable = TRUE;
2671 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2672 if (remote_class->interfaces [i] == klass)
2673 redo_vtable = FALSE;
2675 else {
2676 redo_vtable = (remote_class->proxy_class != klass);
2679 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2680 mono_domain_lock (domain);
2681 if (redo_vtable) {
2682 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2683 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2684 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2685 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2686 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2687 if (!is_ok (error))
2688 goto leave;
2691 leave:
2692 mono_domain_unlock (domain);
2693 mono_loader_unlock ();
2694 return is_ok (error);
2696 #endif /* DISABLE_REMOTING */
2700 * mono_object_get_virtual_method:
2701 * @obj: object to operate on.
2702 * @method: method
2704 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2705 * the instance of a callvirt of method.
2707 MonoMethod*
2708 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2710 MONO_REQ_GC_UNSAFE_MODE;
2711 HANDLE_FUNCTION_ENTER ();
2712 MonoError error;
2713 MONO_HANDLE_DCL (MonoObject, obj);
2714 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2715 mono_error_assert_ok (&error);
2716 HANDLE_FUNCTION_RETURN_VAL (result);
2720 * mono_object_get_virtual_method:
2721 * @obj: object to operate on.
2722 * @method: method
2724 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2725 * the instance of a callvirt of method.
2727 MonoMethod*
2728 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2730 mono_error_init (error);
2732 gboolean is_proxy = FALSE;
2733 MonoClass *klass = mono_handle_class (obj);
2734 #ifndef DISABLE_REMOTING
2735 if (klass == mono_defaults.transparent_proxy_class) {
2736 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2737 klass = remote_class->proxy_class;
2738 is_proxy = TRUE;
2740 #endif
2741 return class_get_virtual_method (klass, method, is_proxy, error);
2744 static MonoMethod*
2745 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2747 mono_error_init (error);
2750 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2751 return method;
2753 mono_class_setup_vtable (klass);
2754 MonoMethod **vtable = klass->vtable;
2756 if (method->slot == -1) {
2757 /* method->slot might not be set for instances of generic methods */
2758 if (method->is_inflated) {
2759 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2760 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2761 } else {
2762 if (!is_proxy)
2763 g_assert_not_reached ();
2767 MonoMethod *res = NULL;
2768 /* check method->slot is a valid index: perform isinstance? */
2769 if (method->slot != -1) {
2770 if (mono_class_is_interface (method->klass)) {
2771 if (!is_proxy) {
2772 gboolean variance_used = FALSE;
2773 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2774 g_assert (iface_offset > 0);
2775 res = vtable [iface_offset + method->slot];
2777 } else {
2778 res = vtable [method->slot];
2782 #ifndef DISABLE_REMOTING
2783 if (is_proxy) {
2784 /* It may be an interface, abstract class method or generic method */
2785 if (!res || mono_method_signature (res)->generic_param_count)
2786 res = method;
2788 /* generic methods demand invoke_with_check */
2789 if (mono_method_signature (res)->generic_param_count)
2790 res = mono_marshal_get_remoting_invoke_with_check (res);
2791 else {
2792 #ifndef DISABLE_COM
2793 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2794 res = mono_cominterop_get_invoke (res);
2795 else
2796 #endif
2797 res = mono_marshal_get_remoting_invoke (res);
2799 } else
2800 #endif
2802 if (method->is_inflated) {
2803 /* Have to inflate the result */
2804 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2808 return res;
2811 static MonoObject*
2812 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2814 MONO_REQ_GC_UNSAFE_MODE;
2816 MonoObject *result = NULL;
2818 g_assert (callbacks.runtime_invoke);
2820 mono_error_init (error);
2822 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2823 mono_profiler_method_start_invoke (method);
2825 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2827 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2828 mono_profiler_method_end_invoke (method);
2830 if (!mono_error_ok (error))
2831 return NULL;
2833 return result;
2837 * mono_runtime_invoke:
2838 * @method: method to invoke
2839 * @obJ: object instance
2840 * @params: arguments to the method
2841 * @exc: exception information.
2843 * Invokes the method represented by @method on the object @obj.
2845 * obj is the 'this' pointer, it should be NULL for static
2846 * methods, a MonoObject* for object instances and a pointer to
2847 * the value type for value types.
2849 * The params array contains the arguments to the method with the
2850 * same convention: MonoObject* pointers for object instances and
2851 * pointers to the value type otherwise.
2853 * From unmanaged code you'll usually use the
2854 * mono_runtime_invoke() variant.
2856 * Note that this function doesn't handle virtual methods for
2857 * you, it will exec the exact method you pass: we still need to
2858 * expose a function to lookup the derived class implementation
2859 * of a virtual method (there are examples of this in the code,
2860 * though).
2862 * You can pass NULL as the exc argument if you don't want to
2863 * catch exceptions, otherwise, *exc will be set to the exception
2864 * thrown, if any. if an exception is thrown, you can't use the
2865 * MonoObject* result from the function.
2867 * If the method returns a value type, it is boxed in an object
2868 * reference.
2870 MonoObject*
2871 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2873 MonoError error;
2874 MonoObject *res;
2875 if (exc) {
2876 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2877 if (*exc == NULL && !mono_error_ok(&error)) {
2878 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2879 } else
2880 mono_error_cleanup (&error);
2881 } else {
2882 res = mono_runtime_invoke_checked (method, obj, params, &error);
2883 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2885 return res;
2889 * mono_runtime_try_invoke:
2890 * @method: method to invoke
2891 * @obJ: object instance
2892 * @params: arguments to the method
2893 * @exc: exception information.
2894 * @error: set on error
2896 * Invokes the method represented by @method on the object @obj.
2898 * obj is the 'this' pointer, it should be NULL for static
2899 * methods, a MonoObject* for object instances and a pointer to
2900 * the value type for value types.
2902 * The params array contains the arguments to the method with the
2903 * same convention: MonoObject* pointers for object instances and
2904 * pointers to the value type otherwise.
2906 * From unmanaged code you'll usually use the
2907 * mono_runtime_invoke() variant.
2909 * Note that this function doesn't handle virtual methods for
2910 * you, it will exec the exact method you pass: we still need to
2911 * expose a function to lookup the derived class implementation
2912 * of a virtual method (there are examples of this in the code,
2913 * though).
2915 * For this function, you must not pass NULL as the exc argument if
2916 * you don't want to catch exceptions, use
2917 * mono_runtime_invoke_checked(). If an exception is thrown, you
2918 * can't use the MonoObject* result from the function.
2920 * If this method cannot be invoked, @error will be set and @exc and
2921 * the return value must not be used.
2923 * If the method returns a value type, it is boxed in an object
2924 * reference.
2926 MonoObject*
2927 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2929 MONO_REQ_GC_UNSAFE_MODE;
2931 g_assert (exc != NULL);
2933 if (mono_runtime_get_no_exec ())
2934 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2936 return do_runtime_invoke (method, obj, params, exc, error);
2940 * mono_runtime_invoke_checked:
2941 * @method: method to invoke
2942 * @obJ: object instance
2943 * @params: arguments to the method
2944 * @error: set on error
2946 * Invokes the method represented by @method on the object @obj.
2948 * obj is the 'this' pointer, it should be NULL for static
2949 * methods, a MonoObject* for object instances and a pointer to
2950 * the value type for value types.
2952 * The params array contains the arguments to the method with the
2953 * same convention: MonoObject* pointers for object instances and
2954 * pointers to the value type otherwise.
2956 * From unmanaged code you'll usually use the
2957 * mono_runtime_invoke() variant.
2959 * Note that this function doesn't handle virtual methods for
2960 * you, it will exec the exact method you pass: we still need to
2961 * expose a function to lookup the derived class implementation
2962 * of a virtual method (there are examples of this in the code,
2963 * though).
2965 * If an exception is thrown, you can't use the MonoObject* result
2966 * from the function.
2968 * If this method cannot be invoked, @error will be set. If the
2969 * method throws an exception (and we're in coop mode) the exception
2970 * will be set in @error.
2972 * If the method returns a value type, it is boxed in an object
2973 * reference.
2975 MonoObject*
2976 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2978 MONO_REQ_GC_UNSAFE_MODE;
2980 if (mono_runtime_get_no_exec ())
2981 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2983 return do_runtime_invoke (method, obj, params, NULL, error);
2987 * mono_method_get_unmanaged_thunk:
2988 * @method: method to generate a thunk for.
2990 * Returns an unmanaged->managed thunk that can be used to call
2991 * a managed method directly from C.
2993 * The thunk's C signature closely matches the managed signature:
2995 * C#: public bool Equals (object obj);
2996 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2997 * MonoObject*, MonoException**);
2999 * The 1st ("this") parameter must not be used with static methods:
3001 * C#: public static bool ReferenceEquals (object a, object b);
3002 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3003 * MonoException**);
3005 * The last argument must be a non-null pointer of a MonoException* pointer.
3006 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3007 * exception has been thrown in managed code. Otherwise it will point
3008 * to the MonoException* caught by the thunk. In this case, the result of
3009 * the thunk is undefined:
3011 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3012 * MonoException *ex = NULL;
3013 * Equals func = mono_method_get_unmanaged_thunk (method);
3014 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3015 * if (ex) {
3016 * // handle exception
3019 * The calling convention of the thunk matches the platform's default
3020 * convention. This means that under Windows, C declarations must
3021 * contain the __stdcall attribute:
3023 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3024 * MonoObject*, MonoException**);
3026 * LIMITATIONS
3028 * Value type arguments and return values are treated as they were objects:
3030 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3031 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3033 * Arguments must be properly boxed upon trunk's invocation, while return
3034 * values must be unboxed.
3036 gpointer
3037 mono_method_get_unmanaged_thunk (MonoMethod *method)
3039 MONO_REQ_GC_NEUTRAL_MODE;
3040 MONO_REQ_API_ENTRYPOINT;
3042 MonoError error;
3043 gpointer res;
3045 g_assert (!mono_threads_is_coop_enabled ());
3047 MONO_ENTER_GC_UNSAFE;
3048 method = mono_marshal_get_thunk_invoke_wrapper (method);
3049 res = mono_compile_method_checked (method, &error);
3050 mono_error_cleanup (&error);
3051 MONO_EXIT_GC_UNSAFE;
3053 return res;
3056 void
3057 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3059 MONO_REQ_GC_UNSAFE_MODE;
3061 int t;
3062 if (type->byref) {
3063 /* object fields cannot be byref, so we don't need a
3064 wbarrier here */
3065 gpointer *p = (gpointer*)dest;
3066 *p = value;
3067 return;
3069 t = type->type;
3070 handle_enum:
3071 switch (t) {
3072 case MONO_TYPE_BOOLEAN:
3073 case MONO_TYPE_I1:
3074 case MONO_TYPE_U1: {
3075 guint8 *p = (guint8*)dest;
3076 *p = value ? *(guint8*)value : 0;
3077 return;
3079 case MONO_TYPE_I2:
3080 case MONO_TYPE_U2:
3081 case MONO_TYPE_CHAR: {
3082 guint16 *p = (guint16*)dest;
3083 *p = value ? *(guint16*)value : 0;
3084 return;
3086 #if SIZEOF_VOID_P == 4
3087 case MONO_TYPE_I:
3088 case MONO_TYPE_U:
3089 #endif
3090 case MONO_TYPE_I4:
3091 case MONO_TYPE_U4: {
3092 gint32 *p = (gint32*)dest;
3093 *p = value ? *(gint32*)value : 0;
3094 return;
3096 #if SIZEOF_VOID_P == 8
3097 case MONO_TYPE_I:
3098 case MONO_TYPE_U:
3099 #endif
3100 case MONO_TYPE_I8:
3101 case MONO_TYPE_U8: {
3102 gint64 *p = (gint64*)dest;
3103 *p = value ? *(gint64*)value : 0;
3104 return;
3106 case MONO_TYPE_R4: {
3107 float *p = (float*)dest;
3108 *p = value ? *(float*)value : 0;
3109 return;
3111 case MONO_TYPE_R8: {
3112 double *p = (double*)dest;
3113 *p = value ? *(double*)value : 0;
3114 return;
3116 case MONO_TYPE_STRING:
3117 case MONO_TYPE_SZARRAY:
3118 case MONO_TYPE_CLASS:
3119 case MONO_TYPE_OBJECT:
3120 case MONO_TYPE_ARRAY:
3121 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3122 return;
3123 case MONO_TYPE_FNPTR:
3124 case MONO_TYPE_PTR: {
3125 gpointer *p = (gpointer*)dest;
3126 *p = deref_pointer? *(gpointer*)value: value;
3127 return;
3129 case MONO_TYPE_VALUETYPE:
3130 /* note that 't' and 'type->type' can be different */
3131 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3132 t = mono_class_enum_basetype (type->data.klass)->type;
3133 goto handle_enum;
3134 } else {
3135 MonoClass *klass = mono_class_from_mono_type (type);
3136 int size = mono_class_value_size (klass, NULL);
3137 if (value == NULL)
3138 mono_gc_bzero_atomic (dest, size);
3139 else
3140 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3142 return;
3143 case MONO_TYPE_GENERICINST:
3144 t = type->data.generic_class->container_class->byval_arg.type;
3145 goto handle_enum;
3146 default:
3147 g_error ("got type %x", type->type);
3152 * mono_field_set_value:
3153 * @obj: Instance object
3154 * @field: MonoClassField describing the field to set
3155 * @value: The value to be set
3157 * Sets the value of the field described by @field in the object instance @obj
3158 * to the value passed in @value. This method should only be used for instance
3159 * fields. For static fields, use mono_field_static_set_value.
3161 * The value must be on the native format of the field type.
3163 void
3164 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3166 MONO_REQ_GC_UNSAFE_MODE;
3168 void *dest;
3170 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3172 dest = (char*)obj + field->offset;
3173 mono_copy_value (field->type, dest, value, FALSE);
3177 * mono_field_static_set_value:
3178 * @field: MonoClassField describing the field to set
3179 * @value: The value to be set
3181 * Sets the value of the static field described by @field
3182 * to the value passed in @value.
3184 * The value must be on the native format of the field type.
3186 void
3187 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3189 MONO_REQ_GC_UNSAFE_MODE;
3191 void *dest;
3193 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3194 /* you cant set a constant! */
3195 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3197 if (field->offset == -1) {
3198 /* Special static */
3199 gpointer addr;
3201 mono_domain_lock (vt->domain);
3202 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3203 mono_domain_unlock (vt->domain);
3204 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3205 } else {
3206 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3208 mono_copy_value (field->type, dest, value, FALSE);
3212 * mono_vtable_get_static_field_data:
3214 * Internal use function: return a pointer to the memory holding the static fields
3215 * for a class or NULL if there are no static fields.
3216 * This is exported only for use by the debugger.
3218 void *
3219 mono_vtable_get_static_field_data (MonoVTable *vt)
3221 MONO_REQ_GC_NEUTRAL_MODE
3223 if (!vt->has_static_fields)
3224 return NULL;
3225 return vt->vtable [vt->klass->vtable_size];
3228 static guint8*
3229 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3231 MONO_REQ_GC_UNSAFE_MODE;
3233 guint8 *src;
3235 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3236 if (field->offset == -1) {
3237 /* Special static */
3238 gpointer addr;
3240 mono_domain_lock (vt->domain);
3241 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3242 mono_domain_unlock (vt->domain);
3243 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3244 } else {
3245 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3247 } else {
3248 src = (guint8*)obj + field->offset;
3251 return src;
3255 * mono_field_get_value:
3256 * @obj: Object instance
3257 * @field: MonoClassField describing the field to fetch information from
3258 * @value: pointer to the location where the value will be stored
3260 * Use this routine to get the value of the field @field in the object
3261 * passed.
3263 * The pointer provided by value must be of the field type, for reference
3264 * types this is a MonoObject*, for value types its the actual pointer to
3265 * the value type.
3267 * For example:
3268 * int i;
3269 * mono_field_get_value (obj, int_field, &i);
3271 void
3272 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3274 MONO_REQ_GC_UNSAFE_MODE;
3276 void *src;
3278 g_assert (obj);
3280 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3282 src = (char*)obj + field->offset;
3283 mono_copy_value (field->type, value, src, TRUE);
3287 * mono_field_get_value_object:
3288 * @domain: domain where the object will be created (if boxing)
3289 * @field: MonoClassField describing the field to fetch information from
3290 * @obj: The object instance for the field.
3292 * Returns: a new MonoObject with the value from the given field. If the
3293 * field represents a value type, the value is boxed.
3296 MonoObject *
3297 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3299 MonoError error;
3300 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3301 mono_error_assert_ok (&error);
3302 return result;
3306 * mono_field_get_value_object_checked:
3307 * @domain: domain where the object will be created (if boxing)
3308 * @field: MonoClassField describing the field to fetch information from
3309 * @obj: The object instance for the field.
3310 * @error: Set on error.
3312 * Returns: a new MonoObject with the value from the given field. If the
3313 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3316 MonoObject *
3317 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3319 MONO_REQ_GC_UNSAFE_MODE;
3321 mono_error_init (error);
3323 MonoObject *o;
3324 MonoClass *klass;
3325 MonoVTable *vtable = NULL;
3326 gchar *v;
3327 gboolean is_static = FALSE;
3328 gboolean is_ref = FALSE;
3329 gboolean is_literal = FALSE;
3330 gboolean is_ptr = FALSE;
3331 MonoType *type = mono_field_get_type_checked (field, error);
3333 return_val_if_nok (error, NULL);
3335 switch (type->type) {
3336 case MONO_TYPE_STRING:
3337 case MONO_TYPE_OBJECT:
3338 case MONO_TYPE_CLASS:
3339 case MONO_TYPE_ARRAY:
3340 case MONO_TYPE_SZARRAY:
3341 is_ref = TRUE;
3342 break;
3343 case MONO_TYPE_U1:
3344 case MONO_TYPE_I1:
3345 case MONO_TYPE_BOOLEAN:
3346 case MONO_TYPE_U2:
3347 case MONO_TYPE_I2:
3348 case MONO_TYPE_CHAR:
3349 case MONO_TYPE_U:
3350 case MONO_TYPE_I:
3351 case MONO_TYPE_U4:
3352 case MONO_TYPE_I4:
3353 case MONO_TYPE_R4:
3354 case MONO_TYPE_U8:
3355 case MONO_TYPE_I8:
3356 case MONO_TYPE_R8:
3357 case MONO_TYPE_VALUETYPE:
3358 is_ref = type->byref;
3359 break;
3360 case MONO_TYPE_GENERICINST:
3361 is_ref = !mono_type_generic_inst_is_valuetype (type);
3362 break;
3363 case MONO_TYPE_PTR:
3364 is_ptr = TRUE;
3365 break;
3366 default:
3367 g_error ("type 0x%x not handled in "
3368 "mono_field_get_value_object", type->type);
3369 return NULL;
3372 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3373 is_literal = TRUE;
3375 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3376 is_static = TRUE;
3378 if (!is_literal) {
3379 vtable = mono_class_vtable_full (domain, field->parent, error);
3380 return_val_if_nok (error, NULL);
3382 if (!vtable->initialized) {
3383 mono_runtime_class_init_full (vtable, error);
3384 return_val_if_nok (error, NULL);
3387 } else {
3388 g_assert (obj);
3391 if (is_ref) {
3392 if (is_literal) {
3393 get_default_field_value (domain, field, &o, error);
3394 return_val_if_nok (error, NULL);
3395 } else if (is_static) {
3396 mono_field_static_get_value_checked (vtable, field, &o, error);
3397 return_val_if_nok (error, NULL);
3398 } else {
3399 mono_field_get_value (obj, field, &o);
3401 return o;
3404 if (is_ptr) {
3405 static MonoMethod *m;
3406 gpointer args [2];
3407 gpointer *ptr;
3408 gpointer v;
3410 if (!m) {
3411 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3412 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3413 g_assert (m);
3416 v = &ptr;
3417 if (is_literal) {
3418 get_default_field_value (domain, field, v, error);
3419 return_val_if_nok (error, NULL);
3420 } else if (is_static) {
3421 mono_field_static_get_value_checked (vtable, field, v, error);
3422 return_val_if_nok (error, NULL);
3423 } else {
3424 mono_field_get_value (obj, field, v);
3427 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3428 args [0] = ptr ? *ptr : NULL;
3429 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3430 return_val_if_nok (error, NULL);
3432 o = mono_runtime_invoke_checked (m, NULL, args, error);
3433 return_val_if_nok (error, NULL);
3435 return o;
3438 /* boxed value type */
3439 klass = mono_class_from_mono_type (type);
3441 if (mono_class_is_nullable (klass))
3442 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3444 o = mono_object_new_checked (domain, klass, error);
3445 return_val_if_nok (error, NULL);
3446 v = ((gchar *) o) + sizeof (MonoObject);
3448 if (is_literal) {
3449 get_default_field_value (domain, field, v, error);
3450 return_val_if_nok (error, NULL);
3451 } else if (is_static) {
3452 mono_field_static_get_value_checked (vtable, field, v, error);
3453 return_val_if_nok (error, NULL);
3454 } else {
3455 mono_field_get_value (obj, field, v);
3458 return o;
3462 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3464 MONO_REQ_GC_UNSAFE_MODE;
3466 mono_error_init (error);
3467 int retval = 0;
3468 const char *p = blob;
3469 mono_metadata_decode_blob_size (p, &p);
3471 switch (type) {
3472 case MONO_TYPE_BOOLEAN:
3473 case MONO_TYPE_U1:
3474 case MONO_TYPE_I1:
3475 *(guint8 *) value = *p;
3476 break;
3477 case MONO_TYPE_CHAR:
3478 case MONO_TYPE_U2:
3479 case MONO_TYPE_I2:
3480 *(guint16*) value = read16 (p);
3481 break;
3482 case MONO_TYPE_U4:
3483 case MONO_TYPE_I4:
3484 *(guint32*) value = read32 (p);
3485 break;
3486 case MONO_TYPE_U8:
3487 case MONO_TYPE_I8:
3488 *(guint64*) value = read64 (p);
3489 break;
3490 case MONO_TYPE_R4:
3491 readr4 (p, (float*) value);
3492 break;
3493 case MONO_TYPE_R8:
3494 readr8 (p, (double*) value);
3495 break;
3496 case MONO_TYPE_STRING:
3497 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3498 break;
3499 case MONO_TYPE_CLASS:
3500 *(gpointer*) value = NULL;
3501 break;
3502 default:
3503 retval = -1;
3504 g_warning ("type 0x%02x should not be in constant table", type);
3506 return retval;
3509 static void
3510 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3512 MONO_REQ_GC_NEUTRAL_MODE;
3514 MonoTypeEnum def_type;
3515 const char* data;
3517 mono_error_init (error);
3519 data = mono_class_get_field_default_value (field, &def_type);
3520 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3523 void
3524 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3526 MONO_REQ_GC_UNSAFE_MODE;
3528 void *src;
3530 mono_error_init (error);
3532 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3534 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3535 get_default_field_value (vt->domain, field, value, error);
3536 return;
3539 if (field->offset == -1) {
3540 /* Special static */
3541 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3542 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3543 } else {
3544 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3546 mono_copy_value (field->type, value, src, TRUE);
3550 * mono_field_static_get_value:
3551 * @vt: vtable to the object
3552 * @field: MonoClassField describing the field to fetch information from
3553 * @value: where the value is returned
3555 * Use this routine to get the value of the static field @field value.
3557 * The pointer provided by value must be of the field type, for reference
3558 * types this is a MonoObject*, for value types its the actual pointer to
3559 * the value type.
3561 * For example:
3562 * int i;
3563 * mono_field_static_get_value (vt, int_field, &i);
3565 void
3566 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3568 MONO_REQ_GC_NEUTRAL_MODE;
3570 MonoError error;
3571 mono_field_static_get_value_checked (vt, field, value, &error);
3572 mono_error_cleanup (&error);
3576 * mono_field_static_get_value_checked:
3577 * @vt: vtable to the object
3578 * @field: MonoClassField describing the field to fetch information from
3579 * @value: where the value is returned
3580 * @error: set on error
3582 * Use this routine to get the value of the static field @field value.
3584 * The pointer provided by value must be of the field type, for reference
3585 * types this is a MonoObject*, for value types its the actual pointer to
3586 * the value type.
3588 * For example:
3589 * int i;
3590 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3591 * if (!is_ok (error)) { ... }
3593 * On failure sets @error.
3595 void
3596 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3598 MONO_REQ_GC_NEUTRAL_MODE;
3600 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3604 * mono_property_set_value:
3605 * @prop: MonoProperty to set
3606 * @obj: instance object on which to act
3607 * @params: parameters to pass to the propery
3608 * @exc: optional exception
3610 * Invokes the property's set method with the given arguments on the
3611 * object instance obj (or NULL for static properties).
3613 * You can pass NULL as the exc argument if you don't want to
3614 * catch exceptions, otherwise, *exc will be set to the exception
3615 * thrown, if any. if an exception is thrown, you can't use the
3616 * MonoObject* result from the function.
3618 void
3619 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3621 MONO_REQ_GC_UNSAFE_MODE;
3623 MonoError error;
3624 do_runtime_invoke (prop->set, obj, params, exc, &error);
3625 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3626 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3627 } else {
3628 mono_error_cleanup (&error);
3633 * mono_property_set_value_checked:
3634 * @prop: MonoProperty to set
3635 * @obj: instance object on which to act
3636 * @params: parameters to pass to the propery
3637 * @error: set on error
3639 * Invokes the property's set method with the given arguments on the
3640 * object instance obj (or NULL for static properties).
3642 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3643 * If an exception is thrown, it will be caught and returned via @error.
3645 gboolean
3646 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3648 MONO_REQ_GC_UNSAFE_MODE;
3650 MonoObject *exc;
3652 mono_error_init (error);
3653 do_runtime_invoke (prop->set, obj, params, &exc, error);
3654 if (exc != NULL && is_ok (error))
3655 mono_error_set_exception_instance (error, (MonoException*)exc);
3656 return is_ok (error);
3660 * mono_property_get_value:
3661 * @prop: MonoProperty to fetch
3662 * @obj: instance object on which to act
3663 * @params: parameters to pass to the propery
3664 * @exc: optional exception
3666 * Invokes the property's get method with the given arguments on the
3667 * object instance obj (or NULL for static properties).
3669 * You can pass NULL as the exc argument if you don't want to
3670 * catch exceptions, otherwise, *exc will be set to the exception
3671 * thrown, if any. if an exception is thrown, you can't use the
3672 * MonoObject* result from the function.
3674 * Returns: the value from invoking the get method on the property.
3676 MonoObject*
3677 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3679 MONO_REQ_GC_UNSAFE_MODE;
3681 MonoError error;
3682 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3683 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3684 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3685 } else {
3686 mono_error_cleanup (&error); /* FIXME don't raise here */
3689 return val;
3693 * mono_property_get_value_checked:
3694 * @prop: MonoProperty to fetch
3695 * @obj: instance object on which to act
3696 * @params: parameters to pass to the propery
3697 * @error: set on error
3699 * Invokes the property's get method with the given arguments on the
3700 * object instance obj (or NULL for static properties).
3702 * If an exception is thrown, you can't use the
3703 * MonoObject* result from the function. The exception will be propagated via @error.
3705 * Returns: the value from invoking the get method on the property. On
3706 * failure returns NULL and sets @error.
3708 MonoObject*
3709 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3711 MONO_REQ_GC_UNSAFE_MODE;
3713 MonoObject *exc;
3714 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3715 if (exc != NULL && !is_ok (error))
3716 mono_error_set_exception_instance (error, (MonoException*) exc);
3717 if (!is_ok (error))
3718 val = NULL;
3719 return val;
3724 * mono_nullable_init:
3725 * @buf: The nullable structure to initialize.
3726 * @value: the value to initialize from
3727 * @klass: the type for the object
3729 * Initialize the nullable structure pointed to by @buf from @value which
3730 * should be a boxed value type. The size of @buf should be able to hold
3731 * as much data as the @klass->instance_size (which is the number of bytes
3732 * that will be copies).
3734 * Since Nullables have variable structure, we can not define a C
3735 * structure for them.
3737 void
3738 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3740 MONO_REQ_GC_UNSAFE_MODE;
3742 MonoClass *param_class = klass->cast_class;
3744 mono_class_setup_fields (klass);
3745 g_assert (klass->fields_inited);
3747 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3748 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3750 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3751 if (value) {
3752 if (param_class->has_references)
3753 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3754 else
3755 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3756 } else {
3757 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3762 * mono_nullable_box:
3763 * @buf: The buffer representing the data to be boxed
3764 * @klass: the type to box it as.
3765 * @error: set on oerr
3767 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3768 * @buf. On failure returns NULL and sets @error
3770 MonoObject*
3771 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3773 MONO_REQ_GC_UNSAFE_MODE;
3775 mono_error_init (error);
3776 MonoClass *param_class = klass->cast_class;
3778 mono_class_setup_fields (klass);
3779 g_assert (klass->fields_inited);
3781 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3782 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3784 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3785 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3786 return_val_if_nok (error, NULL);
3787 if (param_class->has_references)
3788 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3789 else
3790 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3791 return o;
3793 else
3794 return NULL;
3798 * mono_get_delegate_invoke:
3799 * @klass: The delegate class
3801 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3803 MonoMethod *
3804 mono_get_delegate_invoke (MonoClass *klass)
3806 MONO_REQ_GC_NEUTRAL_MODE;
3808 MonoMethod *im;
3810 /* This is called at runtime, so avoid the slower search in metadata */
3811 mono_class_setup_methods (klass);
3812 if (mono_class_has_failure (klass))
3813 return NULL;
3814 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3815 return im;
3819 * mono_get_delegate_begin_invoke:
3820 * @klass: The delegate class
3822 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3824 MonoMethod *
3825 mono_get_delegate_begin_invoke (MonoClass *klass)
3827 MONO_REQ_GC_NEUTRAL_MODE;
3829 MonoMethod *im;
3831 /* This is called at runtime, so avoid the slower search in metadata */
3832 mono_class_setup_methods (klass);
3833 if (mono_class_has_failure (klass))
3834 return NULL;
3835 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3836 return im;
3840 * mono_get_delegate_end_invoke:
3841 * @klass: The delegate class
3843 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3845 MonoMethod *
3846 mono_get_delegate_end_invoke (MonoClass *klass)
3848 MONO_REQ_GC_NEUTRAL_MODE;
3850 MonoMethod *im;
3852 /* This is called at runtime, so avoid the slower search in metadata */
3853 mono_class_setup_methods (klass);
3854 if (mono_class_has_failure (klass))
3855 return NULL;
3856 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3857 return im;
3861 * mono_runtime_delegate_invoke:
3862 * @delegate: pointer to a delegate object.
3863 * @params: parameters for the delegate.
3864 * @exc: Pointer to the exception result.
3866 * Invokes the delegate method @delegate with the parameters provided.
3868 * You can pass NULL as the exc argument if you don't want to
3869 * catch exceptions, otherwise, *exc will be set to the exception
3870 * thrown, if any. if an exception is thrown, you can't use the
3871 * MonoObject* result from the function.
3873 MonoObject*
3874 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3876 MONO_REQ_GC_UNSAFE_MODE;
3878 MonoError error;
3879 if (exc) {
3880 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3881 if (*exc) {
3882 mono_error_cleanup (&error);
3883 return NULL;
3884 } else {
3885 if (!is_ok (&error))
3886 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3887 return result;
3889 } else {
3890 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3891 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3892 return result;
3897 * mono_runtime_delegate_try_invoke:
3898 * @delegate: pointer to a delegate object.
3899 * @params: parameters for the delegate.
3900 * @exc: Pointer to the exception result.
3901 * @error: set on error
3903 * Invokes the delegate method @delegate with the parameters provided.
3905 * You can pass NULL as the exc argument if you don't want to
3906 * catch exceptions, otherwise, *exc will be set to the exception
3907 * thrown, if any. On failure to execute, @error will be set.
3908 * if an exception is thrown, you can't use the
3909 * MonoObject* result from the function.
3911 MonoObject*
3912 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3914 MONO_REQ_GC_UNSAFE_MODE;
3916 mono_error_init (error);
3917 MonoMethod *im;
3918 MonoClass *klass = delegate->vtable->klass;
3919 MonoObject *o;
3921 im = mono_get_delegate_invoke (klass);
3922 if (!im)
3923 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3925 if (exc) {
3926 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3927 } else {
3928 o = mono_runtime_invoke_checked (im, delegate, params, error);
3931 return o;
3935 * mono_runtime_delegate_invoke_checked:
3936 * @delegate: pointer to a delegate object.
3937 * @params: parameters for the delegate.
3938 * @error: set on error
3940 * Invokes the delegate method @delegate with the parameters provided.
3942 * On failure @error will be set and you can't use the MonoObject*
3943 * result from the function.
3945 MonoObject*
3946 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3948 mono_error_init (error);
3949 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3952 static char **main_args = NULL;
3953 static int num_main_args = 0;
3956 * mono_runtime_get_main_args:
3958 * Returns: a MonoArray with the arguments passed to the main program
3960 MonoArray*
3961 mono_runtime_get_main_args (void)
3963 MONO_REQ_GC_UNSAFE_MODE;
3964 MonoError error;
3965 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3966 mono_error_assert_ok (&error);
3967 return result;
3971 * mono_runtime_get_main_args:
3972 * @error: set on error
3974 * Returns: a MonoArray with the arguments passed to the main
3975 * program. On failure returns NULL and sets @error.
3977 MonoArray*
3978 mono_runtime_get_main_args_checked (MonoError *error)
3980 MonoArray *res;
3981 int i;
3982 MonoDomain *domain = mono_domain_get ();
3984 mono_error_init (error);
3986 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3987 return_val_if_nok (error, NULL);
3989 for (i = 0; i < num_main_args; ++i)
3990 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3992 return res;
3995 static void
3996 free_main_args (void)
3998 MONO_REQ_GC_NEUTRAL_MODE;
4000 int i;
4002 for (i = 0; i < num_main_args; ++i)
4003 g_free (main_args [i]);
4004 g_free (main_args);
4005 num_main_args = 0;
4006 main_args = NULL;
4010 * mono_runtime_set_main_args:
4011 * @argc: number of arguments from the command line
4012 * @argv: array of strings from the command line
4014 * Set the command line arguments from an embedding application that doesn't otherwise call
4015 * mono_runtime_run_main ().
4018 mono_runtime_set_main_args (int argc, char* argv[])
4020 MONO_REQ_GC_NEUTRAL_MODE;
4022 int i;
4024 free_main_args ();
4025 main_args = g_new0 (char*, argc);
4026 num_main_args = argc;
4028 for (i = 0; i < argc; ++i) {
4029 gchar *utf8_arg;
4031 utf8_arg = mono_utf8_from_external (argv[i]);
4032 if (utf8_arg == NULL) {
4033 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4034 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4035 exit (-1);
4038 main_args [i] = utf8_arg;
4041 return 0;
4045 * Prepare an array of arguments in order to execute a standard Main()
4046 * method (argc/argv contains the executable name). This method also
4047 * sets the command line argument value needed by System.Environment.
4050 static MonoArray*
4051 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4053 MONO_REQ_GC_UNSAFE_MODE;
4055 MonoError error;
4056 int i;
4057 MonoArray *args = NULL;
4058 MonoDomain *domain = mono_domain_get ();
4059 gchar *utf8_fullpath;
4060 MonoMethodSignature *sig;
4062 g_assert (method != NULL);
4064 mono_thread_set_main (mono_thread_current ());
4066 main_args = g_new0 (char*, argc);
4067 num_main_args = argc;
4069 if (!g_path_is_absolute (argv [0])) {
4070 gchar *basename = g_path_get_basename (argv [0]);
4071 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4072 basename,
4073 NULL);
4075 utf8_fullpath = mono_utf8_from_external (fullpath);
4076 if(utf8_fullpath == NULL) {
4077 /* Printing the arg text will cause glib to
4078 * whinge about "Invalid UTF-8", but at least
4079 * its relevant, and shows the problem text
4080 * string.
4082 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4083 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4084 exit (-1);
4087 g_free (fullpath);
4088 g_free (basename);
4089 } else {
4090 utf8_fullpath = mono_utf8_from_external (argv[0]);
4091 if(utf8_fullpath == NULL) {
4092 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4093 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4094 exit (-1);
4098 main_args [0] = utf8_fullpath;
4100 for (i = 1; i < argc; ++i) {
4101 gchar *utf8_arg;
4103 utf8_arg=mono_utf8_from_external (argv[i]);
4104 if(utf8_arg==NULL) {
4105 /* Ditto the comment about Invalid UTF-8 here */
4106 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4107 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4108 exit (-1);
4111 main_args [i] = utf8_arg;
4113 argc--;
4114 argv++;
4116 sig = mono_method_signature (method);
4117 if (!sig) {
4118 g_print ("Unable to load Main method.\n");
4119 exit (-1);
4122 if (sig->param_count) {
4123 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4124 mono_error_assert_ok (&error);
4125 for (i = 0; i < argc; ++i) {
4126 /* The encodings should all work, given that
4127 * we've checked all these args for the
4128 * main_args array.
4130 gchar *str = mono_utf8_from_external (argv [i]);
4131 MonoString *arg = mono_string_new (domain, str);
4132 mono_array_setref (args, i, arg);
4133 g_free (str);
4135 } else {
4136 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4137 mono_error_assert_ok (&error);
4140 mono_assembly_set_main (method->klass->image->assembly);
4142 return args;
4146 * mono_runtime_run_main:
4147 * @method: the method to start the application with (usually Main)
4148 * @argc: number of arguments from the command line
4149 * @argv: array of strings from the command line
4150 * @exc: excetption results
4152 * Execute a standard Main() method (argc/argv contains the
4153 * executable name). This method also sets the command line argument value
4154 * needed by System.Environment.
4159 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4160 MonoObject **exc)
4162 MONO_REQ_GC_UNSAFE_MODE;
4164 MonoError error;
4165 MonoArray *args = prepare_run_main (method, argc, argv);
4166 int res;
4167 if (exc) {
4168 res = mono_runtime_try_exec_main (method, args, exc);
4169 } else {
4170 res = mono_runtime_exec_main_checked (method, args, &error);
4171 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4173 return res;
4177 * mono_runtime_run_main_checked:
4178 * @method: the method to start the application with (usually Main)
4179 * @argc: number of arguments from the command line
4180 * @argv: array of strings from the command line
4181 * @error: set on error
4183 * Execute a standard Main() method (argc/argv contains the
4184 * executable name). This method also sets the command line argument value
4185 * needed by System.Environment. On failure sets @error.
4190 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4191 MonoError *error)
4193 mono_error_init (error);
4194 MonoArray *args = prepare_run_main (method, argc, argv);
4195 return mono_runtime_exec_main_checked (method, args, error);
4199 * mono_runtime_try_run_main:
4200 * @method: the method to start the application with (usually Main)
4201 * @argc: number of arguments from the command line
4202 * @argv: array of strings from the command line
4203 * @exc: set if Main throws an exception
4204 * @error: set if Main can't be executed
4206 * Execute a standard Main() method (argc/argv contains the executable
4207 * name). This method also sets the command line argument value needed
4208 * by System.Environment. On failure sets @error if Main can't be
4209 * executed or @exc if it threw and exception.
4214 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4215 MonoObject **exc)
4217 g_assert (exc);
4218 MonoArray *args = prepare_run_main (method, argc, argv);
4219 return mono_runtime_try_exec_main (method, args, exc);
4223 static MonoObject*
4224 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4226 static MonoMethod *serialize_method;
4228 MonoError error;
4229 void *params [1];
4230 MonoObject *array;
4232 if (!serialize_method) {
4233 MonoClass *klass = mono_class_get_remoting_services_class ();
4234 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4237 if (!serialize_method) {
4238 *failure = TRUE;
4239 return NULL;
4242 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4244 params [0] = obj;
4245 *exc = NULL;
4247 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4248 if (*exc == NULL && !mono_error_ok (&error))
4249 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4250 else
4251 mono_error_cleanup (&error);
4253 if (*exc)
4254 *failure = TRUE;
4256 return array;
4259 static MonoObject*
4260 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4262 MONO_REQ_GC_UNSAFE_MODE;
4264 static MonoMethod *deserialize_method;
4266 MonoError error;
4267 void *params [1];
4268 MonoObject *result;
4270 if (!deserialize_method) {
4271 MonoClass *klass = mono_class_get_remoting_services_class ();
4272 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4274 if (!deserialize_method) {
4275 *failure = TRUE;
4276 return NULL;
4279 params [0] = obj;
4280 *exc = NULL;
4282 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4283 if (*exc == NULL && !mono_error_ok (&error))
4284 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4285 else
4286 mono_error_cleanup (&error);
4288 if (*exc)
4289 *failure = TRUE;
4291 return result;
4294 #ifndef DISABLE_REMOTING
4295 static MonoObject*
4296 make_transparent_proxy (MonoObject *obj, MonoError *error)
4298 MONO_REQ_GC_UNSAFE_MODE;
4300 static MonoMethod *get_proxy_method;
4302 MonoDomain *domain = mono_domain_get ();
4303 MonoRealProxy *real_proxy;
4304 MonoReflectionType *reflection_type;
4305 MonoTransparentProxy *transparent_proxy;
4307 mono_error_init (error);
4309 if (!get_proxy_method)
4310 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4312 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4314 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4315 return_val_if_nok (error, NULL);
4316 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4317 return_val_if_nok (error, NULL);
4319 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4320 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4322 MonoObject *exc = NULL;
4324 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4325 if (exc != NULL && is_ok (error))
4326 mono_error_set_exception_instance (error, (MonoException*)exc);
4328 return (MonoObject*) transparent_proxy;
4330 #endif /* DISABLE_REMOTING */
4333 * mono_object_xdomain_representation
4334 * @obj: an object
4335 * @target_domain: a domain
4336 * @error: set on error.
4338 * Creates a representation of obj in the domain target_domain. This
4339 * is either a copy of obj arrived through via serialization and
4340 * deserialization or a proxy, depending on whether the object is
4341 * serializable or marshal by ref. obj must not be in target_domain.
4343 * If the object cannot be represented in target_domain, NULL is
4344 * returned and @error is set appropriately.
4346 MonoObject*
4347 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4349 MONO_REQ_GC_UNSAFE_MODE;
4351 mono_error_init (error);
4352 MonoObject *deserialized = NULL;
4354 #ifndef DISABLE_REMOTING
4355 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4356 deserialized = make_transparent_proxy (obj, error);
4358 else
4359 #endif
4361 gboolean failure = FALSE;
4362 MonoDomain *domain = mono_domain_get ();
4363 MonoObject *serialized;
4364 MonoObject *exc = NULL;
4366 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4367 serialized = serialize_object (obj, &failure, &exc);
4368 mono_domain_set_internal_with_options (target_domain, FALSE);
4369 if (!failure)
4370 deserialized = deserialize_object (serialized, &failure, &exc);
4371 if (domain != target_domain)
4372 mono_domain_set_internal_with_options (domain, FALSE);
4373 if (failure)
4374 mono_error_set_exception_instance (error, (MonoException*)exc);
4377 return deserialized;
4380 /* Used in call_unhandled_exception_delegate */
4381 static MonoObject *
4382 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4384 MONO_REQ_GC_UNSAFE_MODE;
4386 mono_error_init (error);
4387 MonoClass *klass;
4388 gpointer args [2];
4389 MonoMethod *method = NULL;
4390 MonoBoolean is_terminating = TRUE;
4391 MonoObject *obj;
4393 klass = mono_class_get_unhandled_exception_event_args_class ();
4394 mono_class_init (klass);
4396 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4397 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4398 g_assert (method);
4400 args [0] = exc;
4401 args [1] = &is_terminating;
4403 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4404 return_val_if_nok (error, NULL);
4406 mono_runtime_invoke_checked (method, obj, args, error);
4407 return_val_if_nok (error, NULL);
4409 return obj;
4412 /* Used in mono_unhandled_exception */
4413 static void
4414 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4415 MONO_REQ_GC_UNSAFE_MODE;
4417 MonoError error;
4418 MonoObject *e = NULL;
4419 gpointer pa [2];
4420 MonoDomain *current_domain = mono_domain_get ();
4422 if (domain != current_domain)
4423 mono_domain_set_internal_with_options (domain, FALSE);
4425 g_assert (domain == mono_object_domain (domain->domain));
4427 if (mono_object_domain (exc) != domain) {
4429 exc = mono_object_xdomain_representation (exc, domain, &error);
4430 if (!exc) {
4431 if (!is_ok (&error)) {
4432 MonoError inner_error;
4433 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4434 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4435 mono_error_assert_ok (&inner_error);
4436 } else {
4437 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4438 "System.Runtime.Serialization", "SerializationException",
4439 "Could not serialize unhandled exception.");
4443 g_assert (mono_object_domain (exc) == domain);
4445 pa [0] = domain->domain;
4446 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4447 mono_error_assert_ok (&error);
4448 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4449 if (!is_ok (&error)) {
4450 if (e == NULL)
4451 e = (MonoObject*)mono_error_convert_to_exception (&error);
4452 else
4453 mono_error_cleanup (&error);
4456 if (domain != current_domain)
4457 mono_domain_set_internal_with_options (current_domain, FALSE);
4459 if (e) {
4460 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4461 if (!mono_error_ok (&error)) {
4462 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4463 mono_error_cleanup (&error);
4464 } else {
4465 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4466 g_free (msg);
4471 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4474 * mono_runtime_unhandled_exception_policy_set:
4475 * @policy: the new policy
4477 * This is a VM internal routine.
4479 * Sets the runtime policy for handling unhandled exceptions.
4481 void
4482 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4483 runtime_unhandled_exception_policy = policy;
4487 * mono_runtime_unhandled_exception_policy_get:
4489 * This is a VM internal routine.
4491 * Gets the runtime policy for handling unhandled exceptions.
4493 MonoRuntimeUnhandledExceptionPolicy
4494 mono_runtime_unhandled_exception_policy_get (void) {
4495 return runtime_unhandled_exception_policy;
4499 * mono_unhandled_exception:
4500 * @exc: exception thrown
4502 * This is a VM internal routine.
4504 * We call this function when we detect an unhandled exception
4505 * in the default domain.
4507 * It invokes the * UnhandledException event in AppDomain or prints
4508 * a warning to the console
4510 void
4511 mono_unhandled_exception (MonoObject *exc)
4513 MONO_REQ_GC_UNSAFE_MODE;
4515 MonoError error;
4516 MonoClassField *field;
4517 MonoDomain *current_domain, *root_domain;
4518 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4520 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4521 return;
4523 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4524 g_assert (field);
4526 current_domain = mono_domain_get ();
4527 root_domain = mono_get_root_domain ();
4529 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4530 mono_error_assert_ok (&error);
4531 if (current_domain != root_domain) {
4532 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4533 mono_error_assert_ok (&error);
4536 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4537 mono_print_unhandled_exception (exc);
4538 } else {
4539 /* unhandled exception callbacks must not be aborted */
4540 mono_threads_begin_abort_protected_block ();
4541 if (root_appdomain_delegate)
4542 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4543 if (current_appdomain_delegate)
4544 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4545 mono_threads_end_abort_protected_block ();
4548 /* set exitcode only if we will abort the process */
4549 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4550 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4552 mono_environment_exitcode_set (1);
4557 * mono_runtime_exec_managed_code:
4558 * @domain: Application domain
4559 * @main_func: function to invoke from the execution thread
4560 * @main_args: parameter to the main_func
4562 * Launch a new thread to execute a function
4564 * main_func is called back from the thread with main_args as the
4565 * parameter. The callback function is expected to start Main()
4566 * eventually. This function then waits for all managed threads to
4567 * finish.
4568 * It is not necesseray anymore to execute managed code in a subthread,
4569 * so this function should not be used anymore by default: just
4570 * execute the code and then call mono_thread_manage ().
4572 void
4573 mono_runtime_exec_managed_code (MonoDomain *domain,
4574 MonoMainThreadFunc main_func,
4575 gpointer main_args)
4577 MonoError error;
4578 mono_thread_create_checked (domain, main_func, main_args, &error);
4579 mono_error_assert_ok (&error);
4581 mono_thread_manage ();
4584 static void
4585 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4587 MonoInternalThread* thread = mono_thread_internal_current ();
4588 MonoCustomAttrInfo* cinfo;
4589 gboolean has_stathread_attribute;
4591 if (!domain->entry_assembly) {
4592 gchar *str;
4593 MonoAssembly *assembly;
4595 assembly = method->klass->image->assembly;
4596 domain->entry_assembly = assembly;
4597 /* Domains created from another domain already have application_base and configuration_file set */
4598 if (domain->setup->application_base == NULL) {
4599 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4602 if (domain->setup->configuration_file == NULL) {
4603 str = g_strconcat (assembly->image->name, ".config", NULL);
4604 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4605 g_free (str);
4606 mono_domain_set_options_from_config (domain);
4610 MonoError cattr_error;
4611 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4612 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4613 if (cinfo) {
4614 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4615 if (!cinfo->cached)
4616 mono_custom_attrs_free (cinfo);
4617 } else {
4618 has_stathread_attribute = FALSE;
4620 if (has_stathread_attribute) {
4621 thread->apartment_state = ThreadApartmentState_STA;
4622 } else {
4623 thread->apartment_state = ThreadApartmentState_MTA;
4625 mono_thread_init_apartment_state ();
4629 static int
4630 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4632 MONO_REQ_GC_UNSAFE_MODE;
4634 gpointer pa [1];
4635 int rval;
4637 mono_error_init (error);
4638 g_assert (args);
4640 pa [0] = args;
4642 /* FIXME: check signature of method */
4643 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4644 MonoObject *res;
4645 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4646 if (is_ok (error))
4647 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4648 else
4649 rval = -1;
4650 mono_environment_exitcode_set (rval);
4651 } else {
4652 mono_runtime_invoke_checked (method, NULL, pa, error);
4654 if (is_ok (error))
4655 rval = 0;
4656 else {
4657 rval = -1;
4660 return rval;
4663 static int
4664 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4666 MONO_REQ_GC_UNSAFE_MODE;
4668 gpointer pa [1];
4669 int rval;
4671 g_assert (args);
4672 g_assert (exc);
4674 pa [0] = args;
4676 /* FIXME: check signature of method */
4677 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4678 MonoError inner_error;
4679 MonoObject *res;
4680 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4681 if (*exc == NULL && !mono_error_ok (&inner_error))
4682 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4683 else
4684 mono_error_cleanup (&inner_error);
4686 if (*exc == NULL)
4687 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4688 else
4689 rval = -1;
4691 mono_environment_exitcode_set (rval);
4692 } else {
4693 MonoError inner_error;
4694 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4695 if (*exc == NULL && !mono_error_ok (&inner_error))
4696 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4697 else
4698 mono_error_cleanup (&inner_error);
4700 if (*exc == NULL)
4701 rval = 0;
4702 else {
4703 /* If the return type of Main is void, only
4704 * set the exitcode if an exception was thrown
4705 * (we don't want to blow away an
4706 * explicitly-set exit code)
4708 rval = -1;
4709 mono_environment_exitcode_set (rval);
4713 return rval;
4717 * Execute a standard Main() method (args doesn't contain the
4718 * executable name).
4721 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4723 MonoError error;
4724 prepare_thread_to_exec_main (mono_object_domain (args), method);
4725 if (exc) {
4726 int rval = do_try_exec_main (method, args, exc);
4727 return rval;
4728 } else {
4729 int rval = do_exec_main_checked (method, args, &error);
4730 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4731 return rval;
4736 * Execute a standard Main() method (args doesn't contain the
4737 * executable name).
4739 * On failure sets @error
4742 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4744 mono_error_init (error);
4745 prepare_thread_to_exec_main (mono_object_domain (args), method);
4746 return do_exec_main_checked (method, args, error);
4750 * Execute a standard Main() method (args doesn't contain the
4751 * executable name).
4753 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4756 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4758 prepare_thread_to_exec_main (mono_object_domain (args), method);
4759 return do_try_exec_main (method, args, exc);
4764 /** invoke_array_extract_argument:
4765 * @params: array of arguments to the method.
4766 * @i: the index of the argument to extract.
4767 * @t: ith type from the method signature.
4768 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4769 * @error: set on error.
4771 * Given an array of method arguments, return the ith one using the corresponding type
4772 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4774 * On failure sets @error and returns NULL.
4776 static gpointer
4777 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4779 MonoType *t_orig = t;
4780 gpointer result = NULL;
4781 mono_error_init (error);
4782 again:
4783 switch (t->type) {
4784 case MONO_TYPE_U1:
4785 case MONO_TYPE_I1:
4786 case MONO_TYPE_BOOLEAN:
4787 case MONO_TYPE_U2:
4788 case MONO_TYPE_I2:
4789 case MONO_TYPE_CHAR:
4790 case MONO_TYPE_U:
4791 case MONO_TYPE_I:
4792 case MONO_TYPE_U4:
4793 case MONO_TYPE_I4:
4794 case MONO_TYPE_U8:
4795 case MONO_TYPE_I8:
4796 case MONO_TYPE_R4:
4797 case MONO_TYPE_R8:
4798 case MONO_TYPE_VALUETYPE:
4799 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4800 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4801 result = mono_array_get (params, MonoObject*, i);
4802 if (t->byref)
4803 *has_byref_nullables = TRUE;
4804 } else {
4805 /* MS seems to create the objects if a null is passed in */
4806 if (!mono_array_get (params, MonoObject*, i)) {
4807 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4808 return_val_if_nok (error, NULL);
4809 mono_array_setref (params, i, o);
4812 if (t->byref) {
4814 * We can't pass the unboxed vtype byref to the callee, since
4815 * that would mean the callee would be able to modify boxed
4816 * primitive types. So we (and MS) make a copy of the boxed
4817 * object, pass that to the callee, and replace the original
4818 * boxed object in the arg array with the copy.
4820 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4821 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4822 return_val_if_nok (error, NULL);
4823 mono_array_setref (params, i, copy);
4826 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4828 break;
4829 case MONO_TYPE_STRING:
4830 case MONO_TYPE_OBJECT:
4831 case MONO_TYPE_CLASS:
4832 case MONO_TYPE_ARRAY:
4833 case MONO_TYPE_SZARRAY:
4834 if (t->byref)
4835 result = mono_array_addr (params, MonoObject*, i);
4836 // FIXME: I need to check this code path
4837 else
4838 result = mono_array_get (params, MonoObject*, i);
4839 break;
4840 case MONO_TYPE_GENERICINST:
4841 if (t->byref)
4842 t = &t->data.generic_class->container_class->this_arg;
4843 else
4844 t = &t->data.generic_class->container_class->byval_arg;
4845 goto again;
4846 case MONO_TYPE_PTR: {
4847 MonoObject *arg;
4849 /* The argument should be an IntPtr */
4850 arg = mono_array_get (params, MonoObject*, i);
4851 if (arg == NULL) {
4852 result = NULL;
4853 } else {
4854 g_assert (arg->vtable->klass == mono_defaults.int_class);
4855 result = ((MonoIntPtr*)arg)->m_value;
4857 break;
4859 default:
4860 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4862 return result;
4865 * mono_runtime_invoke_array:
4866 * @method: method to invoke
4867 * @obJ: object instance
4868 * @params: arguments to the method
4869 * @exc: exception information.
4871 * Invokes the method represented by @method on the object @obj.
4873 * obj is the 'this' pointer, it should be NULL for static
4874 * methods, a MonoObject* for object instances and a pointer to
4875 * the value type for value types.
4877 * The params array contains the arguments to the method with the
4878 * same convention: MonoObject* pointers for object instances and
4879 * pointers to the value type otherwise. The _invoke_array
4880 * variant takes a C# object[] as the params argument (MonoArray
4881 * *params): in this case the value types are boxed inside the
4882 * respective reference representation.
4884 * From unmanaged code you'll usually use the
4885 * mono_runtime_invoke_checked() variant.
4887 * Note that this function doesn't handle virtual methods for
4888 * you, it will exec the exact method you pass: we still need to
4889 * expose a function to lookup the derived class implementation
4890 * of a virtual method (there are examples of this in the code,
4891 * though).
4893 * You can pass NULL as the exc argument if you don't want to
4894 * catch exceptions, otherwise, *exc will be set to the exception
4895 * thrown, if any. if an exception is thrown, you can't use the
4896 * MonoObject* result from the function.
4898 * If the method returns a value type, it is boxed in an object
4899 * reference.
4901 MonoObject*
4902 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4903 MonoObject **exc)
4905 MonoError error;
4906 if (exc) {
4907 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4908 if (*exc) {
4909 mono_error_cleanup (&error);
4910 return NULL;
4911 } else {
4912 if (!is_ok (&error))
4913 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4914 return result;
4916 } else {
4917 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4918 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4919 return result;
4924 * mono_runtime_invoke_array_checked:
4925 * @method: method to invoke
4926 * @obJ: object instance
4927 * @params: arguments to the method
4928 * @error: set on failure.
4930 * Invokes the method represented by @method on the object @obj.
4932 * obj is the 'this' pointer, it should be NULL for static
4933 * methods, a MonoObject* for object instances and a pointer to
4934 * the value type for value types.
4936 * The params array contains the arguments to the method with the
4937 * same convention: MonoObject* pointers for object instances and
4938 * pointers to the value type otherwise. The _invoke_array
4939 * variant takes a C# object[] as the params argument (MonoArray
4940 * *params): in this case the value types are boxed inside the
4941 * respective reference representation.
4943 * From unmanaged code you'll usually use the
4944 * mono_runtime_invoke_checked() variant.
4946 * Note that this function doesn't handle virtual methods for
4947 * you, it will exec the exact method you pass: we still need to
4948 * expose a function to lookup the derived class implementation
4949 * of a virtual method (there are examples of this in the code,
4950 * though).
4952 * On failure or exception, @error will be set. In that case, you
4953 * can't use the MonoObject* result from the function.
4955 * If the method returns a value type, it is boxed in an object
4956 * reference.
4958 MonoObject*
4959 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4960 MonoError *error)
4962 mono_error_init (error);
4963 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4967 * mono_runtime_try_invoke_array:
4968 * @method: method to invoke
4969 * @obJ: object instance
4970 * @params: arguments to the method
4971 * @exc: exception information.
4972 * @error: set on failure.
4974 * Invokes the method represented by @method on the object @obj.
4976 * obj is the 'this' pointer, it should be NULL for static
4977 * methods, a MonoObject* for object instances and a pointer to
4978 * the value type for value types.
4980 * The params array contains the arguments to the method with the
4981 * same convention: MonoObject* pointers for object instances and
4982 * pointers to the value type otherwise. The _invoke_array
4983 * variant takes a C# object[] as the params argument (MonoArray
4984 * *params): in this case the value types are boxed inside the
4985 * respective reference representation.
4987 * From unmanaged code you'll usually use the
4988 * mono_runtime_invoke_checked() variant.
4990 * Note that this function doesn't handle virtual methods for
4991 * you, it will exec the exact method you pass: we still need to
4992 * expose a function to lookup the derived class implementation
4993 * of a virtual method (there are examples of this in the code,
4994 * though).
4996 * You can pass NULL as the exc argument if you don't want to catch
4997 * exceptions, otherwise, *exc will be set to the exception thrown, if
4998 * any. On other failures, @error will be set. If an exception is
4999 * thrown or there's an error, you can't use the MonoObject* result
5000 * from the function.
5002 * If the method returns a value type, it is boxed in an object
5003 * reference.
5005 MonoObject*
5006 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5007 MonoObject **exc, MonoError *error)
5009 MONO_REQ_GC_UNSAFE_MODE;
5011 mono_error_init (error);
5013 MonoMethodSignature *sig = mono_method_signature (method);
5014 gpointer *pa = NULL;
5015 MonoObject *res;
5016 int i;
5017 gboolean has_byref_nullables = FALSE;
5019 if (NULL != params) {
5020 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5021 for (i = 0; i < mono_array_length (params); i++) {
5022 MonoType *t = sig->params [i];
5023 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5024 return_val_if_nok (error, NULL);
5028 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5029 void *o = obj;
5031 if (mono_class_is_nullable (method->klass)) {
5032 /* Need to create a boxed vtype instead */
5033 g_assert (!obj);
5035 if (!params)
5036 return NULL;
5037 else {
5038 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5042 if (!obj) {
5043 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5044 mono_error_assert_ok (error);
5045 g_assert (obj); /*maybe we should raise a TLE instead?*/
5046 #ifndef DISABLE_REMOTING
5047 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5048 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5050 #endif
5051 if (method->klass->valuetype)
5052 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5053 else
5054 o = obj;
5055 } else if (method->klass->valuetype) {
5056 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5057 return_val_if_nok (error, NULL);
5060 if (exc) {
5061 mono_runtime_try_invoke (method, o, pa, exc, error);
5062 } else {
5063 mono_runtime_invoke_checked (method, o, pa, error);
5066 return (MonoObject *)obj;
5067 } else {
5068 if (mono_class_is_nullable (method->klass)) {
5069 MonoObject *nullable;
5071 /* Convert the unboxed vtype into a Nullable structure */
5072 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5073 return_val_if_nok (error, NULL);
5075 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5076 return_val_if_nok (error, NULL);
5077 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5078 obj = mono_object_unbox (nullable);
5081 /* obj must be already unboxed if needed */
5082 if (exc) {
5083 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5084 } else {
5085 res = mono_runtime_invoke_checked (method, obj, pa, error);
5087 return_val_if_nok (error, NULL);
5089 if (sig->ret->type == MONO_TYPE_PTR) {
5090 MonoClass *pointer_class;
5091 static MonoMethod *box_method;
5092 void *box_args [2];
5093 MonoObject *box_exc;
5096 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5097 * convert it to a Pointer object.
5099 pointer_class = mono_class_get_pointer_class ();
5100 if (!box_method)
5101 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5103 g_assert (res->vtable->klass == mono_defaults.int_class);
5104 box_args [0] = ((MonoIntPtr*)res)->m_value;
5105 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5106 return_val_if_nok (error, NULL);
5108 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5109 g_assert (box_exc == NULL);
5110 mono_error_assert_ok (error);
5113 if (has_byref_nullables) {
5115 * The runtime invoke wrapper already converted byref nullables back,
5116 * and stored them in pa, we just need to copy them back to the
5117 * managed array.
5119 for (i = 0; i < mono_array_length (params); i++) {
5120 MonoType *t = sig->params [i];
5122 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5123 mono_array_setref (params, i, pa [i]);
5127 return res;
5132 * mono_object_new:
5133 * @klass: the class of the object that we want to create
5135 * Returns: a newly created object whose definition is
5136 * looked up using @klass. This will not invoke any constructors,
5137 * so the consumer of this routine has to invoke any constructors on
5138 * its own to initialize the object.
5140 * It returns NULL on failure.
5142 MonoObject *
5143 mono_object_new (MonoDomain *domain, MonoClass *klass)
5145 MONO_REQ_GC_UNSAFE_MODE;
5147 MonoError error;
5149 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5151 mono_error_cleanup (&error);
5152 return result;
5155 MonoObject *
5156 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5158 MONO_REQ_GC_UNSAFE_MODE;
5160 MonoError error;
5162 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5164 mono_error_set_pending_exception (&error);
5165 return result;
5169 * mono_object_new_checked:
5170 * @klass: the class of the object that we want to create
5171 * @error: set on error
5173 * Returns: a newly created object whose definition is
5174 * looked up using @klass. This will not invoke any constructors,
5175 * so the consumer of this routine has to invoke any constructors on
5176 * its own to initialize the object.
5178 * It returns NULL on failure and sets @error.
5180 MonoObject *
5181 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5183 MONO_REQ_GC_UNSAFE_MODE;
5185 MonoVTable *vtable;
5187 vtable = mono_class_vtable (domain, klass);
5188 g_assert (vtable); /* FIXME don't swallow the error */
5190 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5191 return o;
5195 * mono_object_new_pinned:
5197 * Same as mono_object_new, but the returned object will be pinned.
5198 * For SGEN, these objects will only be freed at appdomain unload.
5200 MonoObject *
5201 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5203 MONO_REQ_GC_UNSAFE_MODE;
5205 MonoVTable *vtable;
5207 mono_error_init (error);
5209 vtable = mono_class_vtable (domain, klass);
5210 g_assert (vtable); /* FIXME don't swallow the error */
5212 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5214 if (G_UNLIKELY (!o))
5215 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5216 else if (G_UNLIKELY (vtable->klass->has_finalize))
5217 mono_object_register_finalizer (o);
5219 return o;
5223 * mono_object_new_specific:
5224 * @vtable: the vtable of the object that we want to create
5226 * Returns: A newly created object with class and domain specified
5227 * by @vtable
5229 MonoObject *
5230 mono_object_new_specific (MonoVTable *vtable)
5232 MonoError error;
5233 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5234 mono_error_cleanup (&error);
5236 return o;
5239 MonoObject *
5240 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5242 MONO_REQ_GC_UNSAFE_MODE;
5244 MonoObject *o;
5246 mono_error_init (error);
5248 /* check for is_com_object for COM Interop */
5249 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5251 gpointer pa [1];
5252 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5254 if (im == NULL) {
5255 MonoClass *klass = mono_class_get_activation_services_class ();
5257 if (!klass->inited)
5258 mono_class_init (klass);
5260 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5261 if (!im) {
5262 mono_error_set_not_supported (error, "Linked away.");
5263 return NULL;
5265 vtable->domain->create_proxy_for_type_method = im;
5268 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5269 if (!mono_error_ok (error))
5270 return NULL;
5272 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5273 if (!mono_error_ok (error))
5274 return NULL;
5276 if (o != NULL)
5277 return o;
5280 return mono_object_new_alloc_specific_checked (vtable, error);
5283 MonoObject *
5284 ves_icall_object_new_specific (MonoVTable *vtable)
5286 MonoError error;
5287 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5288 mono_error_set_pending_exception (&error);
5290 return o;
5294 * mono_object_new_alloc_specific:
5295 * @vtable: virtual table for the object.
5297 * This function allocates a new `MonoObject` with the type derived
5298 * from the @vtable information. If the class of this object has a
5299 * finalizer, then the object will be tracked for finalization.
5301 * This method might raise an exception on errors. Use the
5302 * `mono_object_new_fast_checked` method if you want to manually raise
5303 * the exception.
5305 * Returns: the allocated object.
5307 MonoObject *
5308 mono_object_new_alloc_specific (MonoVTable *vtable)
5310 MonoError error;
5311 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5312 mono_error_cleanup (&error);
5314 return o;
5318 * mono_object_new_alloc_specific_checked:
5319 * @vtable: virtual table for the object.
5320 * @error: holds the error return value.
5322 * This function allocates a new `MonoObject` with the type derived
5323 * from the @vtable information. If the class of this object has a
5324 * finalizer, then the object will be tracked for finalization.
5326 * If there is not enough memory, the @error parameter will be set
5327 * and will contain a user-visible message with the amount of bytes
5328 * that were requested.
5330 * Returns: the allocated object, or NULL if there is not enough memory
5333 MonoObject *
5334 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5336 MONO_REQ_GC_UNSAFE_MODE;
5338 MonoObject *o;
5340 mono_error_init (error);
5342 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5344 if (G_UNLIKELY (!o))
5345 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5346 else if (G_UNLIKELY (vtable->klass->has_finalize))
5347 mono_object_register_finalizer (o);
5349 return o;
5353 * mono_object_new_fast:
5354 * @vtable: virtual table for the object.
5356 * This function allocates a new `MonoObject` with the type derived
5357 * from the @vtable information. The returned object is not tracked
5358 * for finalization. If your object implements a finalizer, you should
5359 * use `mono_object_new_alloc_specific` instead.
5361 * This method might raise an exception on errors. Use the
5362 * `mono_object_new_fast_checked` method if you want to manually raise
5363 * the exception.
5365 * Returns: the allocated object.
5367 MonoObject*
5368 mono_object_new_fast (MonoVTable *vtable)
5370 MonoError error;
5371 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5372 mono_error_cleanup (&error);
5374 return o;
5378 * mono_object_new_fast_checked:
5379 * @vtable: virtual table for the object.
5380 * @error: holds the error return value.
5382 * This function allocates a new `MonoObject` with the type derived
5383 * from the @vtable information. The returned object is not tracked
5384 * for finalization. If your object implements a finalizer, you should
5385 * use `mono_object_new_alloc_specific_checked` instead.
5387 * If there is not enough memory, the @error parameter will be set
5388 * and will contain a user-visible message with the amount of bytes
5389 * that were requested.
5391 * Returns: the allocated object, or NULL if there is not enough memory
5394 MonoObject*
5395 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5397 MONO_REQ_GC_UNSAFE_MODE;
5399 MonoObject *o;
5401 mono_error_init (error);
5403 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5405 if (G_UNLIKELY (!o))
5406 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5408 return o;
5411 MonoObject *
5412 ves_icall_object_new_fast (MonoVTable *vtable)
5414 MonoError error;
5415 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5416 mono_error_set_pending_exception (&error);
5418 return o;
5421 MonoObject*
5422 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5424 MONO_REQ_GC_UNSAFE_MODE;
5426 MonoObject *o;
5428 mono_error_init (error);
5430 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5432 if (G_UNLIKELY (!o))
5433 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5434 else if (G_UNLIKELY (vtable->klass->has_finalize))
5435 mono_object_register_finalizer (o);
5437 return o;
5441 * mono_class_get_allocation_ftn:
5442 * @vtable: vtable
5443 * @for_box: the object will be used for boxing
5444 * @pass_size_in_words:
5446 * Return the allocation function appropriate for the given class.
5449 void*
5450 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5452 MONO_REQ_GC_NEUTRAL_MODE;
5454 *pass_size_in_words = FALSE;
5456 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5457 return ves_icall_object_new_specific;
5459 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5461 return ves_icall_object_new_fast;
5464 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5465 * of the overhead of parameter passing.
5468 *pass_size_in_words = TRUE;
5469 #ifdef GC_REDIRECT_TO_LOCAL
5470 return GC_local_gcj_fast_malloc;
5471 #else
5472 return GC_gcj_fast_malloc;
5473 #endif
5477 return ves_icall_object_new_specific;
5481 * mono_object_new_from_token:
5482 * @image: Context where the type_token is hosted
5483 * @token: a token of the type that we want to create
5485 * Returns: A newly created object whose definition is
5486 * looked up using @token in the @image image
5488 MonoObject *
5489 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5491 MONO_REQ_GC_UNSAFE_MODE;
5493 MonoError error;
5494 MonoObject *result;
5495 MonoClass *klass;
5497 klass = mono_class_get_checked (image, token, &error);
5498 mono_error_assert_ok (&error);
5500 result = mono_object_new_checked (domain, klass, &error);
5502 mono_error_cleanup (&error);
5503 return result;
5509 * mono_object_clone:
5510 * @obj: the object to clone
5512 * Returns: A newly created object who is a shallow copy of @obj
5514 MonoObject *
5515 mono_object_clone (MonoObject *obj)
5517 MonoError error;
5518 MonoObject *o = mono_object_clone_checked (obj, &error);
5519 mono_error_cleanup (&error);
5521 return o;
5524 MonoObject *
5525 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5527 MONO_REQ_GC_UNSAFE_MODE;
5529 MonoObject *o;
5530 int size;
5532 mono_error_init (error);
5534 size = obj->vtable->klass->instance_size;
5536 if (obj->vtable->klass->rank)
5537 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5539 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5541 if (G_UNLIKELY (!o)) {
5542 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5543 return NULL;
5546 /* If the object doesn't contain references this will do a simple memmove. */
5547 mono_gc_wbarrier_object_copy (o, obj);
5549 if (obj->vtable->klass->has_finalize)
5550 mono_object_register_finalizer (o);
5551 return o;
5555 * mono_array_full_copy:
5556 * @src: source array to copy
5557 * @dest: destination array
5559 * Copies the content of one array to another with exactly the same type and size.
5561 void
5562 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5564 MONO_REQ_GC_UNSAFE_MODE;
5566 uintptr_t size;
5567 MonoClass *klass = src->obj.vtable->klass;
5569 g_assert (klass == dest->obj.vtable->klass);
5571 size = mono_array_length (src);
5572 g_assert (size == mono_array_length (dest));
5573 size *= mono_array_element_size (klass);
5574 #ifdef HAVE_SGEN_GC
5575 if (klass->element_class->valuetype) {
5576 if (klass->element_class->has_references)
5577 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5578 else
5579 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5580 } else {
5581 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5583 #else
5584 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5585 #endif
5589 * mono_array_clone_in_domain:
5590 * @domain: the domain in which the array will be cloned into
5591 * @array: the array to clone
5592 * @error: set on error
5594 * This routine returns a copy of the array that is hosted on the
5595 * specified MonoDomain. On failure returns NULL and sets @error.
5597 MonoArray*
5598 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5600 MONO_REQ_GC_UNSAFE_MODE;
5602 MonoArray *o;
5603 uintptr_t size, i;
5604 uintptr_t *sizes;
5605 MonoClass *klass = array->obj.vtable->klass;
5607 mono_error_init (error);
5609 if (array->bounds == NULL) {
5610 size = mono_array_length (array);
5611 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5612 return_val_if_nok (error, NULL);
5614 size *= mono_array_element_size (klass);
5615 #ifdef HAVE_SGEN_GC
5616 if (klass->element_class->valuetype) {
5617 if (klass->element_class->has_references)
5618 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5619 else
5620 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5621 } else {
5622 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5624 #else
5625 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5626 #endif
5627 return o;
5630 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5631 size = mono_array_element_size (klass);
5632 for (i = 0; i < klass->rank; ++i) {
5633 sizes [i] = array->bounds [i].length;
5634 size *= array->bounds [i].length;
5635 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5637 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5638 return_val_if_nok (error, NULL);
5639 #ifdef HAVE_SGEN_GC
5640 if (klass->element_class->valuetype) {
5641 if (klass->element_class->has_references)
5642 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5643 else
5644 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5645 } else {
5646 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5648 #else
5649 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5650 #endif
5652 return o;
5656 * mono_array_clone:
5657 * @array: the array to clone
5659 * Returns: A newly created array who is a shallow copy of @array
5661 MonoArray*
5662 mono_array_clone (MonoArray *array)
5664 MONO_REQ_GC_UNSAFE_MODE;
5666 MonoError error;
5667 MonoArray *result = mono_array_clone_checked (array, &error);
5668 mono_error_cleanup (&error);
5669 return result;
5673 * mono_array_clone_checked:
5674 * @array: the array to clone
5675 * @error: set on error
5677 * Returns: A newly created array who is a shallow copy of @array. On
5678 * failure returns NULL and sets @error.
5680 MonoArray*
5681 mono_array_clone_checked (MonoArray *array, MonoError *error)
5684 MONO_REQ_GC_UNSAFE_MODE;
5685 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5688 /* helper macros to check for overflow when calculating the size of arrays */
5689 #ifdef MONO_BIG_ARRAYS
5690 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5691 #define MYGUINT_MAX MYGUINT64_MAX
5692 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5693 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5694 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5695 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5696 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5697 #else
5698 #define MYGUINT32_MAX 4294967295U
5699 #define MYGUINT_MAX MYGUINT32_MAX
5700 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5701 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5702 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5703 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5704 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5705 #endif
5707 gboolean
5708 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5710 MONO_REQ_GC_NEUTRAL_MODE;
5712 uintptr_t byte_len;
5714 byte_len = mono_array_element_size (klass);
5715 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5716 return FALSE;
5717 byte_len *= len;
5718 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5719 return FALSE;
5720 byte_len += MONO_SIZEOF_MONO_ARRAY;
5722 *res = byte_len;
5724 return TRUE;
5728 * mono_array_new_full:
5729 * @domain: domain where the object is created
5730 * @array_class: array class
5731 * @lengths: lengths for each dimension in the array
5732 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5734 * This routine creates a new array objects with the given dimensions,
5735 * lower bounds and type.
5737 MonoArray*
5738 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5740 MonoError error;
5741 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5742 mono_error_cleanup (&error);
5744 return array;
5747 MonoArray*
5748 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5750 MONO_REQ_GC_UNSAFE_MODE;
5752 uintptr_t byte_len = 0, len, bounds_size;
5753 MonoObject *o;
5754 MonoArray *array;
5755 MonoArrayBounds *bounds;
5756 MonoVTable *vtable;
5757 int i;
5759 mono_error_init (error);
5761 if (!array_class->inited)
5762 mono_class_init (array_class);
5764 len = 1;
5766 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5767 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5768 len = lengths [0];
5769 if (len > MONO_ARRAY_MAX_INDEX) {
5770 mono_error_set_generic_error (error, "System", "OverflowException", "");
5771 return NULL;
5773 bounds_size = 0;
5774 } else {
5775 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5777 for (i = 0; i < array_class->rank; ++i) {
5778 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5779 mono_error_set_generic_error (error, "System", "OverflowException", "");
5780 return NULL;
5782 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5783 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5784 return NULL;
5786 len *= lengths [i];
5790 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5791 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5792 return NULL;
5795 if (bounds_size) {
5796 /* align */
5797 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5798 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5799 return NULL;
5801 byte_len = (byte_len + 3) & ~3;
5802 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5803 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5804 return NULL;
5806 byte_len += bounds_size;
5809 * Following three lines almost taken from mono_object_new ():
5810 * they need to be kept in sync.
5812 vtable = mono_class_vtable_full (domain, array_class, error);
5813 return_val_if_nok (error, NULL);
5815 if (bounds_size)
5816 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5817 else
5818 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5820 if (G_UNLIKELY (!o)) {
5821 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5822 return NULL;
5825 array = (MonoArray*)o;
5827 bounds = array->bounds;
5829 if (bounds_size) {
5830 for (i = 0; i < array_class->rank; ++i) {
5831 bounds [i].length = lengths [i];
5832 if (lower_bounds)
5833 bounds [i].lower_bound = lower_bounds [i];
5837 return array;
5841 * mono_array_new:
5842 * @domain: domain where the object is created
5843 * @eclass: element class
5844 * @n: number of array elements
5846 * This routine creates a new szarray with @n elements of type @eclass.
5848 MonoArray *
5849 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5851 MONO_REQ_GC_UNSAFE_MODE;
5853 MonoError error;
5854 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5855 mono_error_cleanup (&error);
5856 return result;
5860 * mono_array_new_checked:
5861 * @domain: domain where the object is created
5862 * @eclass: element class
5863 * @n: number of array elements
5864 * @error: set on error
5866 * This routine creates a new szarray with @n elements of type @eclass.
5867 * On failure returns NULL and sets @error.
5869 MonoArray *
5870 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5872 MonoClass *ac;
5874 mono_error_init (error);
5876 ac = mono_array_class_get (eclass, 1);
5877 g_assert (ac);
5879 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5880 return_val_if_nok (error, NULL);
5882 return mono_array_new_specific_checked (vtable, n, error);
5885 MonoArray*
5886 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5888 MonoError error;
5889 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5890 mono_error_set_pending_exception (&error);
5892 return arr;
5896 * mono_array_new_specific:
5897 * @vtable: a vtable in the appropriate domain for an initialized class
5898 * @n: number of array elements
5900 * This routine is a fast alternative to mono_array_new() for code which
5901 * can be sure about the domain it operates in.
5903 MonoArray *
5904 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5906 MonoError error;
5907 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5908 mono_error_cleanup (&error);
5910 return arr;
5913 MonoArray*
5914 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5916 MONO_REQ_GC_UNSAFE_MODE;
5918 MonoObject *o;
5919 uintptr_t byte_len;
5921 mono_error_init (error);
5923 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5924 mono_error_set_generic_error (error, "System", "OverflowException", "");
5925 return NULL;
5928 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5929 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5930 return NULL;
5932 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5934 if (G_UNLIKELY (!o)) {
5935 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5936 return NULL;
5939 return (MonoArray*)o;
5942 MonoArray*
5943 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5945 MonoError error;
5946 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5947 mono_error_set_pending_exception (&error);
5949 return arr;
5953 * mono_string_empty_wrapper:
5955 * Returns: The same empty string instance as the managed string.Empty
5957 MonoString*
5958 mono_string_empty_wrapper (void)
5960 MonoDomain *domain = mono_domain_get ();
5961 return mono_string_empty (domain);
5965 * mono_string_empty:
5967 * Returns: The same empty string instance as the managed string.Empty
5969 MonoString*
5970 mono_string_empty (MonoDomain *domain)
5972 g_assert (domain);
5973 g_assert (domain->empty_string);
5974 return domain->empty_string;
5978 * mono_string_new_utf16:
5979 * @text: a pointer to an utf16 string
5980 * @len: the length of the string
5982 * Returns: A newly created string object which contains @text.
5984 MonoString *
5985 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5987 MONO_REQ_GC_UNSAFE_MODE;
5989 MonoError error;
5990 MonoString *res = NULL;
5991 res = mono_string_new_utf16_checked (domain, text, len, &error);
5992 mono_error_cleanup (&error);
5994 return res;
5998 * mono_string_new_utf16_checked:
5999 * @text: a pointer to an utf16 string
6000 * @len: the length of the string
6001 * @error: written on error.
6003 * Returns: A newly created string object which contains @text.
6004 * On error, returns NULL and sets @error.
6006 MonoString *
6007 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6009 MONO_REQ_GC_UNSAFE_MODE;
6011 MonoString *s;
6013 mono_error_init (error);
6015 s = mono_string_new_size_checked (domain, len, error);
6016 if (s != NULL)
6017 memcpy (mono_string_chars (s), text, len * 2);
6019 return s;
6023 * mono_string_new_utf32:
6024 * @text: a pointer to an utf32 string
6025 * @len: the length of the string
6026 * @error: set on failure.
6028 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6030 static MonoString *
6031 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6033 MONO_REQ_GC_UNSAFE_MODE;
6035 MonoString *s;
6036 mono_unichar2 *utf16_output = NULL;
6037 gint32 utf16_len = 0;
6038 GError *gerror = NULL;
6039 glong items_written;
6041 mono_error_init (error);
6042 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6044 if (gerror)
6045 g_error_free (gerror);
6047 while (utf16_output [utf16_len]) utf16_len++;
6049 s = mono_string_new_size_checked (domain, utf16_len, error);
6050 return_val_if_nok (error, NULL);
6052 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6054 g_free (utf16_output);
6056 return s;
6060 * mono_string_new_utf32:
6061 * @text: a pointer to an utf32 string
6062 * @len: the length of the string
6064 * Returns: A newly created string object which contains @text.
6066 MonoString *
6067 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6069 MonoError error;
6070 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6071 mono_error_cleanup (&error);
6072 return result;
6076 * mono_string_new_size:
6077 * @text: a pointer to an utf16 string
6078 * @len: the length of the string
6080 * Returns: A newly created string object of @len
6082 MonoString *
6083 mono_string_new_size (MonoDomain *domain, gint32 len)
6085 MonoError error;
6086 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6087 mono_error_cleanup (&error);
6089 return str;
6092 MonoString *
6093 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6095 MONO_REQ_GC_UNSAFE_MODE;
6097 MonoString *s;
6098 MonoVTable *vtable;
6099 size_t size;
6101 mono_error_init (error);
6103 /* check for overflow */
6104 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6105 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6106 return NULL;
6109 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6110 g_assert (size > 0);
6112 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6113 g_assert (vtable);
6115 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6117 if (G_UNLIKELY (!s)) {
6118 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6119 return NULL;
6122 return s;
6126 * mono_string_new_len:
6127 * @text: a pointer to an utf8 string
6128 * @length: number of bytes in @text to consider
6130 * Returns: A newly created string object which contains @text.
6132 MonoString*
6133 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6135 MONO_REQ_GC_UNSAFE_MODE;
6137 MonoError error;
6138 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6139 mono_error_cleanup (&error);
6140 return result;
6144 * mono_string_new_len_checked:
6145 * @text: a pointer to an utf8 string
6146 * @length: number of bytes in @text to consider
6147 * @error: set on error
6149 * Returns: A newly created string object which contains @text. On
6150 * failure returns NULL and sets @error.
6152 MonoString*
6153 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6155 MONO_REQ_GC_UNSAFE_MODE;
6157 mono_error_init (error);
6159 GError *eg_error = NULL;
6160 MonoString *o = NULL;
6161 guint16 *ut = NULL;
6162 glong items_written;
6164 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6166 if (!eg_error)
6167 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6168 else
6169 g_error_free (eg_error);
6171 g_free (ut);
6173 return o;
6177 * mono_string_new:
6178 * @text: a pointer to an utf8 string
6180 * Returns: A newly created string object which contains @text.
6182 * This function asserts if it cannot allocate a new string.
6184 * @deprecated Use mono_string_new_checked in new code.
6186 MonoString*
6187 mono_string_new (MonoDomain *domain, const char *text)
6189 MonoError error;
6190 MonoString *res = NULL;
6191 res = mono_string_new_checked (domain, text, &error);
6192 mono_error_assert_ok (&error);
6193 return res;
6197 * mono_string_new_checked:
6198 * @text: a pointer to an utf8 string
6199 * @merror: set on error
6201 * Returns: A newly created string object which contains @text.
6202 * On error returns NULL and sets @merror.
6204 MonoString*
6205 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6207 MONO_REQ_GC_UNSAFE_MODE;
6209 GError *eg_error = NULL;
6210 MonoString *o = NULL;
6211 guint16 *ut;
6212 glong items_written;
6213 int l;
6215 mono_error_init (error);
6217 l = strlen (text);
6219 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6221 if (!eg_error)
6222 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6223 else
6224 g_error_free (eg_error);
6226 g_free (ut);
6228 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6229 #if 0
6230 gunichar2 *str;
6231 const gchar *end;
6232 int len;
6233 MonoString *o = NULL;
6235 if (!g_utf8_validate (text, -1, &end)) {
6236 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6237 goto leave;
6240 len = g_utf8_strlen (text, -1);
6241 o = mono_string_new_size_checked (domain, len, error);
6242 if (!o)
6243 goto leave;
6244 str = mono_string_chars (o);
6246 while (text < end) {
6247 *str++ = g_utf8_get_char (text);
6248 text = g_utf8_next_char (text);
6251 leave:
6252 #endif
6253 return o;
6257 * mono_string_new_wrapper:
6258 * @text: pointer to utf8 characters.
6260 * Helper function to create a string object from @text in the current domain.
6262 MonoString*
6263 mono_string_new_wrapper (const char *text)
6265 MONO_REQ_GC_UNSAFE_MODE;
6267 MonoDomain *domain = mono_domain_get ();
6269 if (text)
6270 return mono_string_new (domain, text);
6272 return NULL;
6276 * mono_value_box:
6277 * @class: the class of the value
6278 * @value: a pointer to the unboxed data
6280 * Returns: A newly created object which contains @value.
6282 MonoObject *
6283 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6285 MonoError error;
6286 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6287 mono_error_cleanup (&error);
6288 return result;
6292 * mono_value_box_checked:
6293 * @domain: the domain of the new object
6294 * @class: the class of the value
6295 * @value: a pointer to the unboxed data
6296 * @error: set on error
6298 * Returns: A newly created object which contains @value. On failure
6299 * returns NULL and sets @error.
6301 MonoObject *
6302 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6304 MONO_REQ_GC_UNSAFE_MODE;
6305 MonoObject *res;
6306 int size;
6307 MonoVTable *vtable;
6309 mono_error_init (error);
6311 g_assert (klass->valuetype);
6312 if (mono_class_is_nullable (klass))
6313 return mono_nullable_box ((guint8 *)value, klass, error);
6315 vtable = mono_class_vtable (domain, klass);
6316 if (!vtable)
6317 return NULL;
6318 size = mono_class_instance_size (klass);
6319 res = mono_object_new_alloc_specific_checked (vtable, error);
6320 return_val_if_nok (error, NULL);
6322 size = size - sizeof (MonoObject);
6324 #ifdef HAVE_SGEN_GC
6325 g_assert (size == mono_class_value_size (klass, NULL));
6326 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6327 #else
6328 #if NO_UNALIGNED_ACCESS
6329 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6330 #else
6331 switch (size) {
6332 case 1:
6333 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6334 break;
6335 case 2:
6336 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6337 break;
6338 case 4:
6339 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6340 break;
6341 case 8:
6342 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6343 break;
6344 default:
6345 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6347 #endif
6348 #endif
6349 if (klass->has_finalize) {
6350 mono_object_register_finalizer (res);
6351 return_val_if_nok (error, NULL);
6353 return res;
6357 * mono_value_copy:
6358 * @dest: destination pointer
6359 * @src: source pointer
6360 * @klass: a valuetype class
6362 * Copy a valuetype from @src to @dest. This function must be used
6363 * when @klass contains references fields.
6365 void
6366 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6368 MONO_REQ_GC_UNSAFE_MODE;
6370 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6374 * mono_value_copy_array:
6375 * @dest: destination array
6376 * @dest_idx: index in the @dest array
6377 * @src: source pointer
6378 * @count: number of items
6380 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6381 * This function must be used when @klass contains references fields.
6382 * Overlap is handled.
6384 void
6385 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6387 MONO_REQ_GC_UNSAFE_MODE;
6389 int size = mono_array_element_size (dest->obj.vtable->klass);
6390 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6391 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6392 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6396 * mono_object_get_domain:
6397 * @obj: object to query
6399 * Returns: the MonoDomain where the object is hosted
6401 MonoDomain*
6402 mono_object_get_domain (MonoObject *obj)
6404 MONO_REQ_GC_UNSAFE_MODE;
6406 return mono_object_domain (obj);
6410 * mono_object_get_class:
6411 * @obj: object to query
6413 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6415 * Returns: the MonoClass of the object.
6417 MonoClass*
6418 mono_object_get_class (MonoObject *obj)
6420 MONO_REQ_GC_UNSAFE_MODE;
6422 return mono_object_class (obj);
6425 * mono_object_get_size:
6426 * @o: object to query
6428 * Returns: the size, in bytes, of @o
6430 guint
6431 mono_object_get_size (MonoObject* o)
6433 MONO_REQ_GC_UNSAFE_MODE;
6435 MonoClass* klass = mono_object_class (o);
6436 if (klass == mono_defaults.string_class) {
6437 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6438 } else if (o->vtable->rank) {
6439 MonoArray *array = (MonoArray*)o;
6440 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6441 if (array->bounds) {
6442 size += 3;
6443 size &= ~3;
6444 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6446 return size;
6447 } else {
6448 return mono_class_instance_size (klass);
6453 * mono_object_unbox:
6454 * @obj: object to unbox
6456 * Returns: a pointer to the start of the valuetype boxed in this
6457 * object.
6459 * This method will assert if the object passed is not a valuetype.
6461 gpointer
6462 mono_object_unbox (MonoObject *obj)
6464 MONO_REQ_GC_UNSAFE_MODE;
6466 /* add assert for valuetypes? */
6467 g_assert (obj->vtable->klass->valuetype);
6468 return ((char*)obj) + sizeof (MonoObject);
6472 * mono_object_isinst:
6473 * @obj: an object
6474 * @klass: a pointer to a class
6476 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6478 MonoObject *
6479 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6481 MONO_REQ_GC_UNSAFE_MODE;
6483 HANDLE_FUNCTION_ENTER ();
6484 MONO_HANDLE_DCL (MonoObject, obj);
6485 MonoError error;
6486 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6487 mono_error_cleanup (&error);
6488 HANDLE_FUNCTION_RETURN_OBJ (result);
6493 * mono_object_isinst_checked:
6494 * @obj: an object
6495 * @klass: a pointer to a class
6496 * @error: set on error
6498 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6499 * On failure returns NULL and sets @error.
6501 MonoObject *
6502 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6504 MONO_REQ_GC_UNSAFE_MODE;
6506 HANDLE_FUNCTION_ENTER ();
6507 mono_error_init (error);
6508 MONO_HANDLE_DCL (MonoObject, obj);
6509 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6510 HANDLE_FUNCTION_RETURN_OBJ (result);
6514 * mono_object_handle_isinst:
6515 * @obj: an object
6516 * @klass: a pointer to a class
6517 * @error: set on error
6519 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6520 * On failure returns NULL and sets @error.
6522 MonoObjectHandle
6523 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6525 mono_error_init (error);
6527 if (!klass->inited)
6528 mono_class_init (klass);
6530 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6531 return mono_object_handle_isinst_mbyref (obj, klass, error);
6534 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6536 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6537 MONO_HANDLE_ASSIGN (result, obj);
6538 return result;
6541 MonoObject *
6542 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6544 MONO_REQ_GC_UNSAFE_MODE;
6546 HANDLE_FUNCTION_ENTER ();
6547 MonoError error;
6548 MONO_HANDLE_DCL (MonoObject, obj);
6549 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6550 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6551 HANDLE_FUNCTION_RETURN_OBJ (result);
6554 MonoObjectHandle
6555 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6557 mono_error_init (error);
6559 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6561 if (MONO_HANDLE_IS_NULL (obj))
6562 goto leave;
6564 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6566 if (mono_class_is_interface (klass)) {
6567 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6568 MONO_HANDLE_ASSIGN (result, obj);
6569 goto leave;
6572 /* casting an array one of the invariant interfaces that must act as such */
6573 if (klass->is_array_special_interface) {
6574 if (mono_class_is_assignable_from (klass, vt->klass)) {
6575 MONO_HANDLE_ASSIGN (result, obj);
6576 goto leave;
6580 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6581 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6582 MONO_HANDLE_ASSIGN (result, obj);
6583 goto leave;
6585 } else {
6586 MonoClass *oklass = vt->klass;
6587 if (mono_class_is_transparent_proxy (oklass)){
6588 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6589 oklass = remote_class->proxy_class;
6592 mono_class_setup_supertypes (klass);
6593 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6594 MONO_HANDLE_ASSIGN (result, obj);
6595 goto leave;
6598 #ifndef DISABLE_REMOTING
6599 if (vt->klass == mono_defaults.transparent_proxy_class)
6601 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6602 if (!custom_type_info)
6603 goto leave;
6604 MonoDomain *domain = mono_domain_get ();
6605 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6606 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6607 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6608 MonoMethod *im = NULL;
6609 gpointer pa [2];
6611 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6612 if (!im) {
6613 mono_error_set_not_supported (error, "Linked away.");
6614 goto leave;
6616 im = mono_object_handle_get_virtual_method (rp, im, error);
6617 if (!is_ok (error))
6618 goto leave;
6619 g_assert (im);
6621 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6622 if (!is_ok (error))
6623 goto leave;
6625 pa [0] = MONO_HANDLE_RAW (reftype);
6626 pa [1] = MONO_HANDLE_RAW (obj);
6627 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6628 if (!is_ok (error))
6629 goto leave;
6631 if (*(MonoBoolean *) mono_object_unbox(res)) {
6632 /* Update the vtable of the remote type, so it can safely cast to this new type */
6633 mono_upgrade_remote_class (domain, obj, klass, error);
6634 if (!is_ok (error))
6635 goto leave;
6636 MONO_HANDLE_ASSIGN (result, obj);
6639 #endif /* DISABLE_REMOTING */
6640 leave:
6641 return result;
6645 * mono_object_castclass_mbyref:
6646 * @obj: an object
6647 * @klass: a pointer to a class
6649 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6651 MonoObject *
6652 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6654 MONO_REQ_GC_UNSAFE_MODE;
6655 HANDLE_FUNCTION_ENTER ();
6656 MonoError error;
6657 MONO_HANDLE_DCL (MonoObject, obj);
6658 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6659 if (MONO_HANDLE_IS_NULL (obj))
6660 goto leave;
6661 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6662 mono_error_cleanup (&error);
6663 leave:
6664 HANDLE_FUNCTION_RETURN_OBJ (result);
6667 typedef struct {
6668 MonoDomain *orig_domain;
6669 MonoString *ins;
6670 MonoString *res;
6671 } LDStrInfo;
6673 static void
6674 str_lookup (MonoDomain *domain, gpointer user_data)
6676 MONO_REQ_GC_UNSAFE_MODE;
6678 LDStrInfo *info = (LDStrInfo *)user_data;
6679 if (info->res || domain == info->orig_domain)
6680 return;
6681 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6684 static MonoString*
6685 mono_string_get_pinned (MonoString *str, MonoError *error)
6687 MONO_REQ_GC_UNSAFE_MODE;
6689 mono_error_init (error);
6691 /* We only need to make a pinned version of a string if this is a moving GC */
6692 if (!mono_gc_is_moving ())
6693 return str;
6694 int size;
6695 MonoString *news;
6696 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6697 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6698 if (news) {
6699 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6700 news->length = mono_string_length (str);
6701 } else {
6702 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6704 return news;
6707 static MonoString*
6708 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6710 MONO_REQ_GC_UNSAFE_MODE;
6712 MonoGHashTable *ldstr_table;
6713 MonoString *s, *res;
6714 MonoDomain *domain;
6716 mono_error_init (error);
6718 domain = ((MonoObject *)str)->vtable->domain;
6719 ldstr_table = domain->ldstr_table;
6720 ldstr_lock ();
6721 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6722 if (res) {
6723 ldstr_unlock ();
6724 return res;
6726 if (insert) {
6727 /* Allocate outside the lock */
6728 ldstr_unlock ();
6729 s = mono_string_get_pinned (str, error);
6730 return_val_if_nok (error, NULL);
6731 if (s) {
6732 ldstr_lock ();
6733 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6734 if (res) {
6735 ldstr_unlock ();
6736 return res;
6738 mono_g_hash_table_insert (ldstr_table, s, s);
6739 ldstr_unlock ();
6741 return s;
6742 } else {
6743 LDStrInfo ldstr_info;
6744 ldstr_info.orig_domain = domain;
6745 ldstr_info.ins = str;
6746 ldstr_info.res = NULL;
6748 mono_domain_foreach (str_lookup, &ldstr_info);
6749 if (ldstr_info.res) {
6751 * the string was already interned in some other domain:
6752 * intern it in the current one as well.
6754 mono_g_hash_table_insert (ldstr_table, str, str);
6755 ldstr_unlock ();
6756 return str;
6759 ldstr_unlock ();
6760 return NULL;
6764 * mono_string_is_interned:
6765 * @o: String to probe
6767 * Returns whether the string has been interned.
6769 MonoString*
6770 mono_string_is_interned (MonoString *o)
6772 MonoError error;
6773 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6774 /* This function does not fail. */
6775 mono_error_assert_ok (&error);
6776 return result;
6780 * mono_string_intern:
6781 * @o: String to intern
6783 * Interns the string passed.
6784 * Returns: The interned string.
6786 MonoString*
6787 mono_string_intern (MonoString *str)
6789 MonoError error;
6790 MonoString *result = mono_string_intern_checked (str, &error);
6791 mono_error_assert_ok (&error);
6792 return result;
6796 * mono_string_intern_checked:
6797 * @o: String to intern
6798 * @error: set on error.
6800 * Interns the string passed.
6801 * Returns: The interned string. On failure returns NULL and sets @error
6803 MonoString*
6804 mono_string_intern_checked (MonoString *str, MonoError *error)
6806 MONO_REQ_GC_UNSAFE_MODE;
6808 mono_error_init (error);
6810 return mono_string_is_interned_lookup (str, TRUE, error);
6814 * mono_ldstr:
6815 * @domain: the domain where the string will be used.
6816 * @image: a metadata context
6817 * @idx: index into the user string table.
6819 * Implementation for the ldstr opcode.
6820 * Returns: a loaded string from the @image/@idx combination.
6822 MonoString*
6823 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6825 MonoError error;
6826 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6827 mono_error_cleanup (&error);
6828 return result;
6832 * mono_ldstr_checked:
6833 * @domain: the domain where the string will be used.
6834 * @image: a metadata context
6835 * @idx: index into the user string table.
6836 * @error: set on error.
6838 * Implementation for the ldstr opcode.
6839 * Returns: a loaded string from the @image/@idx combination.
6840 * On failure returns NULL and sets @error.
6842 MonoString*
6843 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6845 MONO_REQ_GC_UNSAFE_MODE;
6846 mono_error_init (error);
6848 if (image->dynamic) {
6849 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6850 return str;
6851 } else {
6852 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6853 return NULL; /*FIXME we should probably be raising an exception here*/
6854 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6855 return str;
6860 * mono_ldstr_metadata_sig
6861 * @domain: the domain for the string
6862 * @sig: the signature of a metadata string
6863 * @error: set on error
6865 * Returns: a MonoString for a string stored in the metadata. On
6866 * failure returns NULL and sets @error.
6868 static MonoString*
6869 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6871 MONO_REQ_GC_UNSAFE_MODE;
6873 mono_error_init (error);
6874 const char *str = sig;
6875 MonoString *o, *interned;
6876 size_t len2;
6878 len2 = mono_metadata_decode_blob_size (str, &str);
6879 len2 >>= 1;
6881 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6882 return_val_if_nok (error, NULL);
6883 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6885 int i;
6886 guint16 *p2 = (guint16*)mono_string_chars (o);
6887 for (i = 0; i < len2; ++i) {
6888 *p2 = GUINT16_FROM_LE (*p2);
6889 ++p2;
6892 #endif
6893 ldstr_lock ();
6894 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6895 ldstr_unlock ();
6896 if (interned)
6897 return interned; /* o will get garbage collected */
6899 o = mono_string_get_pinned (o, error);
6900 if (o) {
6901 ldstr_lock ();
6902 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6903 if (!interned) {
6904 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6905 interned = o;
6907 ldstr_unlock ();
6910 return interned;
6914 * mono_ldstr_utf8:
6916 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6917 * of an object.
6919 char*
6920 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6922 const char *str;
6923 size_t len2;
6924 long written = 0;
6925 char *as;
6926 GError *gerror = NULL;
6928 mono_error_init (error);
6930 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6931 return NULL; /*FIXME we should probably be raising an exception here*/
6932 str = mono_metadata_user_string (image, idx);
6934 len2 = mono_metadata_decode_blob_size (str, &str);
6935 len2 >>= 1;
6937 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6938 if (gerror) {
6939 mono_error_set_argument (error, "string", "%s", gerror->message);
6940 g_error_free (gerror);
6941 return NULL;
6943 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6944 if (len2 > written) {
6945 /* allocate the total length and copy the part of the string that has been converted */
6946 char *as2 = (char *)g_malloc0 (len2);
6947 memcpy (as2, as, written);
6948 g_free (as);
6949 as = as2;
6952 return as;
6956 * mono_string_to_utf8:
6957 * @s: a System.String
6959 * Returns the UTF8 representation for @s.
6960 * The resulting buffer needs to be freed with mono_free().
6962 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6964 char *
6965 mono_string_to_utf8 (MonoString *s)
6967 MONO_REQ_GC_UNSAFE_MODE;
6969 MonoError error;
6970 char *result = mono_string_to_utf8_checked (s, &error);
6972 if (!is_ok (&error)) {
6973 mono_error_cleanup (&error);
6974 return NULL;
6976 return result;
6980 * mono_string_to_utf8_checked:
6981 * @s: a System.String
6982 * @error: a MonoError.
6984 * Converts a MonoString to its UTF8 representation. May fail; check
6985 * @error to determine whether the conversion was successful.
6986 * The resulting buffer should be freed with mono_free().
6988 char *
6989 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6991 MONO_REQ_GC_UNSAFE_MODE;
6993 long written = 0;
6994 char *as;
6995 GError *gerror = NULL;
6997 mono_error_init (error);
6999 if (s == NULL)
7000 return NULL;
7002 if (!s->length)
7003 return g_strdup ("");
7005 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7006 if (gerror) {
7007 mono_error_set_argument (error, "string", "%s", gerror->message);
7008 g_error_free (gerror);
7009 return NULL;
7011 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7012 if (s->length > written) {
7013 /* allocate the total length and copy the part of the string that has been converted */
7014 char *as2 = (char *)g_malloc0 (s->length);
7015 memcpy (as2, as, written);
7016 g_free (as);
7017 as = as2;
7020 return as;
7023 char *
7024 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7026 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7030 * mono_string_to_utf8_ignore:
7031 * @s: a MonoString
7033 * Converts a MonoString to its UTF8 representation. Will ignore
7034 * invalid surrogate pairs.
7035 * The resulting buffer should be freed with mono_free().
7038 char *
7039 mono_string_to_utf8_ignore (MonoString *s)
7041 MONO_REQ_GC_UNSAFE_MODE;
7043 long written = 0;
7044 char *as;
7046 if (s == NULL)
7047 return NULL;
7049 if (!s->length)
7050 return g_strdup ("");
7052 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7054 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7055 if (s->length > written) {
7056 /* allocate the total length and copy the part of the string that has been converted */
7057 char *as2 = (char *)g_malloc0 (s->length);
7058 memcpy (as2, as, written);
7059 g_free (as);
7060 as = as2;
7063 return as;
7067 * mono_string_to_utf8_image_ignore:
7068 * @s: a System.String
7070 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7072 char *
7073 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7075 MONO_REQ_GC_UNSAFE_MODE;
7077 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7081 * mono_string_to_utf8_mp_ignore:
7082 * @s: a System.String
7084 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7086 char *
7087 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7089 MONO_REQ_GC_UNSAFE_MODE;
7091 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7096 * mono_string_to_utf16:
7097 * @s: a MonoString
7099 * Return an null-terminated array of the utf-16 chars
7100 * contained in @s. The result must be freed with g_free().
7101 * This is a temporary helper until our string implementation
7102 * is reworked to always include the null terminating char.
7104 mono_unichar2*
7105 mono_string_to_utf16 (MonoString *s)
7107 MONO_REQ_GC_UNSAFE_MODE;
7109 char *as;
7111 if (s == NULL)
7112 return NULL;
7114 as = (char *)g_malloc ((s->length * 2) + 2);
7115 as [(s->length * 2)] = '\0';
7116 as [(s->length * 2) + 1] = '\0';
7118 if (!s->length) {
7119 return (gunichar2 *)(as);
7122 memcpy (as, mono_string_chars(s), s->length * 2);
7123 return (gunichar2 *)(as);
7127 * mono_string_to_utf32:
7128 * @s: a MonoString
7130 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7131 * contained in @s. The result must be freed with g_free().
7133 mono_unichar4*
7134 mono_string_to_utf32 (MonoString *s)
7136 MONO_REQ_GC_UNSAFE_MODE;
7138 mono_unichar4 *utf32_output = NULL;
7139 GError *error = NULL;
7140 glong items_written;
7142 if (s == NULL)
7143 return NULL;
7145 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7147 if (error)
7148 g_error_free (error);
7150 return utf32_output;
7154 * mono_string_from_utf16:
7155 * @data: the UTF16 string (LPWSTR) to convert
7157 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7159 * Returns: a MonoString.
7161 MonoString *
7162 mono_string_from_utf16 (gunichar2 *data)
7164 MonoError error;
7165 MonoString *result = mono_string_from_utf16_checked (data, &error);
7166 mono_error_cleanup (&error);
7167 return result;
7171 * mono_string_from_utf16_checked:
7172 * @data: the UTF16 string (LPWSTR) to convert
7173 * @error: set on error
7175 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7177 * Returns: a MonoString. On failure sets @error and returns NULL.
7179 MonoString *
7180 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7183 MONO_REQ_GC_UNSAFE_MODE;
7185 mono_error_init (error);
7186 MonoDomain *domain = mono_domain_get ();
7187 int len = 0;
7189 if (!data)
7190 return NULL;
7192 while (data [len]) len++;
7194 return mono_string_new_utf16_checked (domain, data, len, error);
7198 * mono_string_from_utf32:
7199 * @data: the UTF32 string (LPWSTR) to convert
7201 * Converts a UTF32 (UCS-4)to a MonoString.
7203 * Returns: a MonoString.
7205 MonoString *
7206 mono_string_from_utf32 (mono_unichar4 *data)
7208 MonoError error;
7209 MonoString *result = mono_string_from_utf32_checked (data, &error);
7210 mono_error_cleanup (&error);
7211 return result;
7215 * mono_string_from_utf32_checked:
7216 * @data: the UTF32 string (LPWSTR) to convert
7217 * @error: set on error
7219 * Converts a UTF32 (UCS-4)to a MonoString.
7221 * Returns: a MonoString. On failure returns NULL and sets @error.
7223 MonoString *
7224 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7226 MONO_REQ_GC_UNSAFE_MODE;
7228 mono_error_init (error);
7229 MonoString* result = NULL;
7230 mono_unichar2 *utf16_output = NULL;
7231 GError *gerror = NULL;
7232 glong items_written;
7233 int len = 0;
7235 if (!data)
7236 return NULL;
7238 while (data [len]) len++;
7240 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7242 if (gerror)
7243 g_error_free (gerror);
7245 result = mono_string_from_utf16_checked (utf16_output, error);
7246 g_free (utf16_output);
7247 return result;
7250 static char *
7251 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7253 MONO_REQ_GC_UNSAFE_MODE;
7255 char *r;
7256 char *mp_s;
7257 int len;
7259 if (ignore_error) {
7260 r = mono_string_to_utf8_ignore (s);
7261 } else {
7262 r = mono_string_to_utf8_checked (s, error);
7263 if (!mono_error_ok (error))
7264 return NULL;
7267 if (!mp && !image)
7268 return r;
7270 len = strlen (r) + 1;
7271 if (mp)
7272 mp_s = (char *)mono_mempool_alloc (mp, len);
7273 else
7274 mp_s = (char *)mono_image_alloc (image, len);
7276 memcpy (mp_s, r, len);
7278 g_free (r);
7280 return mp_s;
7284 * mono_string_to_utf8_image:
7285 * @s: a System.String
7287 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7289 char *
7290 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7292 MONO_REQ_GC_UNSAFE_MODE;
7294 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7298 * mono_string_to_utf8_mp:
7299 * @s: a System.String
7301 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7303 char *
7304 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7306 MONO_REQ_GC_UNSAFE_MODE;
7308 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7312 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7314 void
7315 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7317 eh_callbacks = *cbs;
7320 MonoRuntimeExceptionHandlingCallbacks *
7321 mono_get_eh_callbacks (void)
7323 return &eh_callbacks;
7327 * mono_raise_exception:
7328 * @ex: exception object
7330 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7332 void
7333 mono_raise_exception (MonoException *ex)
7335 MONO_REQ_GC_UNSAFE_MODE;
7338 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7339 * that will cause gcc to omit the function epilog, causing problems when
7340 * the JIT tries to walk the stack, since the return address on the stack
7341 * will point into the next function in the executable, not this one.
7343 eh_callbacks.mono_raise_exception (ex);
7346 void
7347 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7349 MONO_REQ_GC_UNSAFE_MODE;
7351 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7355 * mono_wait_handle_new:
7356 * @domain: Domain where the object will be created
7357 * @handle: Handle for the wait handle
7358 * @error: set on error.
7360 * Returns: A new MonoWaitHandle created in the given domain for the
7361 * given handle. On failure returns NULL and sets @rror.
7363 MonoWaitHandle *
7364 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7366 MONO_REQ_GC_UNSAFE_MODE;
7368 MonoWaitHandle *res;
7369 gpointer params [1];
7370 static MonoMethod *handle_set;
7372 mono_error_init (error);
7373 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7374 return_val_if_nok (error, NULL);
7376 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7377 if (!handle_set)
7378 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7380 params [0] = &handle;
7382 mono_runtime_invoke_checked (handle_set, res, params, error);
7383 return res;
7386 HANDLE
7387 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7389 MONO_REQ_GC_UNSAFE_MODE;
7391 static MonoClassField *f_safe_handle = NULL;
7392 MonoSafeHandle *sh;
7394 if (!f_safe_handle) {
7395 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7396 g_assert (f_safe_handle);
7399 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7400 return sh->handle;
7404 static MonoObject*
7405 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7407 MONO_REQ_GC_UNSAFE_MODE;
7409 RuntimeInvokeFunction runtime_invoke;
7411 mono_error_init (error);
7413 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7414 MonoMethod *method = mono_get_context_capture_method ();
7415 MonoMethod *wrapper;
7416 if (!method)
7417 return NULL;
7418 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7419 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7420 return_val_if_nok (error, NULL);
7421 domain->capture_context_method = mono_compile_method_checked (method, error);
7422 return_val_if_nok (error, NULL);
7425 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7427 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7430 * mono_async_result_new:
7431 * @domain:domain where the object will be created.
7432 * @handle: wait handle.
7433 * @state: state to pass to AsyncResult
7434 * @data: C closure data.
7435 * @error: set on error.
7437 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7438 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7439 * On failure returns NULL and sets @error.
7442 MonoAsyncResult *
7443 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7445 MONO_REQ_GC_UNSAFE_MODE;
7447 mono_error_init (error);
7448 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7449 return_val_if_nok (error, NULL);
7450 MonoObject *context = mono_runtime_capture_context (domain, error);
7451 return_val_if_nok (error, NULL);
7452 /* we must capture the execution context from the original thread */
7453 if (context) {
7454 MONO_OBJECT_SETREF (res, execution_context, context);
7455 /* note: result may be null if the flow is suppressed */
7458 res->data = (void **)data;
7459 MONO_OBJECT_SETREF (res, object_data, object_data);
7460 MONO_OBJECT_SETREF (res, async_state, state);
7461 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7462 return_val_if_nok (error, NULL);
7463 if (handle != NULL)
7464 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7466 res->sync_completed = FALSE;
7467 res->completed = FALSE;
7469 return res;
7472 MonoObject *
7473 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7475 MONO_REQ_GC_UNSAFE_MODE;
7477 MonoError error;
7478 MonoAsyncCall *ac;
7479 MonoObject *res;
7481 g_assert (ares);
7482 g_assert (ares->async_delegate);
7484 ac = (MonoAsyncCall*) ares->object_data;
7485 if (!ac) {
7486 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7487 if (mono_error_set_pending_exception (&error))
7488 return NULL;
7489 } else {
7490 gpointer wait_event = NULL;
7492 ac->msg->exc = NULL;
7494 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7496 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7497 mono_threads_begin_abort_protected_block ();
7499 if (!ac->msg->exc) {
7500 MonoException *ex = mono_error_convert_to_exception (&error);
7501 ac->msg->exc = (MonoObject *)ex;
7502 } else {
7503 mono_error_cleanup (&error);
7506 MONO_OBJECT_SETREF (ac, res, res);
7508 mono_monitor_enter ((MonoObject*) ares);
7509 ares->completed = 1;
7510 if (ares->handle)
7511 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7512 mono_monitor_exit ((MonoObject*) ares);
7514 if (wait_event != NULL)
7515 mono_w32event_set (wait_event);
7517 mono_error_init (&error); //the else branch would leave it in an undefined state
7518 if (ac->cb_method)
7519 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7521 mono_threads_end_abort_protected_block ();
7523 if (mono_error_set_pending_exception (&error))
7524 return NULL;
7527 return res;
7530 gboolean
7531 mono_message_init (MonoDomain *domain,
7532 MonoMethodMessage *this_obj,
7533 MonoReflectionMethod *method,
7534 MonoArray *out_args,
7535 MonoError *error)
7537 MONO_REQ_GC_UNSAFE_MODE;
7539 static MonoMethod *init_message_method = NULL;
7541 if (!init_message_method) {
7542 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7543 g_assert (init_message_method != NULL);
7546 mono_error_init (error);
7547 /* FIXME set domain instead? */
7548 g_assert (domain == mono_domain_get ());
7550 gpointer args[2];
7552 args[0] = method;
7553 args[1] = out_args;
7555 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7556 return is_ok (error);
7559 #ifndef DISABLE_REMOTING
7561 * mono_remoting_invoke:
7562 * @real_proxy: pointer to a RealProxy object
7563 * @msg: The MonoMethodMessage to execute
7564 * @exc: used to store exceptions
7565 * @out_args: used to store output arguments
7567 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7568 * IMessage interface and it is not trivial to extract results from there. So
7569 * we call an helper method PrivateInvoke instead of calling
7570 * RealProxy::Invoke() directly.
7572 * Returns: the result object.
7574 MonoObject *
7575 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7577 MONO_REQ_GC_UNSAFE_MODE;
7579 MonoObject *o;
7580 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7581 gpointer pa [4];
7583 g_assert (exc);
7585 mono_error_init (error);
7587 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7589 if (!im) {
7590 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7591 if (!im) {
7592 mono_error_set_not_supported (error, "Linked away.");
7593 return NULL;
7595 real_proxy->vtable->domain->private_invoke_method = im;
7598 pa [0] = real_proxy;
7599 pa [1] = msg;
7600 pa [2] = exc;
7601 pa [3] = out_args;
7603 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7604 return_val_if_nok (error, NULL);
7606 return o;
7608 #endif
7610 MonoObject *
7611 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7612 MonoObject **exc, MonoArray **out_args, MonoError *error)
7614 MONO_REQ_GC_UNSAFE_MODE;
7616 static MonoClass *object_array_klass;
7617 mono_error_init (error);
7619 MonoDomain *domain;
7620 MonoMethod *method;
7621 MonoMethodSignature *sig;
7622 MonoArray *arr;
7623 int i, j, outarg_count = 0;
7625 #ifndef DISABLE_REMOTING
7626 if (target && mono_object_is_transparent_proxy (target)) {
7627 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7628 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7629 target = tp->rp->unwrapped_server;
7630 } else {
7631 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7634 #endif
7636 domain = mono_domain_get ();
7637 method = msg->method->method;
7638 sig = mono_method_signature (method);
7640 for (i = 0; i < sig->param_count; i++) {
7641 if (sig->params [i]->byref)
7642 outarg_count++;
7645 if (!object_array_klass) {
7646 MonoClass *klass;
7648 klass = mono_array_class_get (mono_defaults.object_class, 1);
7649 g_assert (klass);
7651 mono_memory_barrier ();
7652 object_array_klass = klass;
7655 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7656 return_val_if_nok (error, NULL);
7658 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7659 *exc = NULL;
7661 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7662 return_val_if_nok (error, NULL);
7664 for (i = 0, j = 0; i < sig->param_count; i++) {
7665 if (sig->params [i]->byref) {
7666 MonoObject* arg;
7667 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7668 mono_array_setref (*out_args, j, arg);
7669 j++;
7673 return ret;
7677 * prepare_to_string_method:
7678 * @obj: The object
7679 * @target: Set to @obj or unboxed value if a valuetype
7681 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7683 static MonoMethod *
7684 prepare_to_string_method (MonoObject *obj, void **target)
7686 MONO_REQ_GC_UNSAFE_MODE;
7688 static MonoMethod *to_string = NULL;
7689 MonoMethod *method;
7690 g_assert (target);
7691 g_assert (obj);
7693 *target = obj;
7695 if (!to_string)
7696 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7698 method = mono_object_get_virtual_method (obj, to_string);
7700 // Unbox value type if needed
7701 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7702 *target = mono_object_unbox (obj);
7704 return method;
7708 * mono_object_to_string:
7709 * @obj: The object
7710 * @exc: Any exception thrown by ToString (). May be NULL.
7712 * Returns: the result of calling ToString () on an object.
7714 MonoString *
7715 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7717 MonoError error;
7718 MonoString *s = NULL;
7719 void *target;
7720 MonoMethod *method = prepare_to_string_method (obj, &target);
7721 if (exc) {
7722 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7723 if (*exc == NULL && !mono_error_ok (&error))
7724 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7725 else
7726 mono_error_cleanup (&error);
7727 } else {
7728 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7729 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7732 return s;
7736 * mono_object_to_string_checked:
7737 * @obj: The object
7738 * @error: Set on error.
7740 * Returns: the result of calling ToString () on an object. If the
7741 * method cannot be invoked or if it raises an exception, sets @error
7742 * and returns NULL.
7744 MonoString *
7745 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7747 mono_error_init (error);
7748 void *target;
7749 MonoMethod *method = prepare_to_string_method (obj, &target);
7750 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7754 * mono_object_try_to_string:
7755 * @obj: The object
7756 * @exc: Any exception thrown by ToString (). Must not be NULL.
7757 * @error: Set if method cannot be invoked.
7759 * Returns: the result of calling ToString () on an object. If the
7760 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7761 * and returns NULL.
7763 MonoString *
7764 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7766 g_assert (exc);
7767 mono_error_init (error);
7768 void *target;
7769 MonoMethod *method = prepare_to_string_method (obj, &target);
7770 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7775 static char *
7776 get_native_backtrace (MonoException *exc_raw)
7778 HANDLE_FUNCTION_ENTER ();
7779 MONO_HANDLE_DCL(MonoException, exc);
7780 char * trace = mono_exception_handle_get_native_backtrace (exc);
7781 HANDLE_FUNCTION_RETURN_VAL (trace);
7785 * mono_print_unhandled_exception:
7786 * @exc: The exception
7788 * Prints the unhandled exception.
7790 void
7791 mono_print_unhandled_exception (MonoObject *exc)
7793 MONO_REQ_GC_UNSAFE_MODE;
7795 MonoString * str;
7796 char *message = (char*)"";
7797 gboolean free_message = FALSE;
7798 MonoError error;
7800 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7801 message = g_strdup ("OutOfMemoryException");
7802 free_message = TRUE;
7803 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7804 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7805 free_message = TRUE;
7806 } else {
7808 if (((MonoException*)exc)->native_trace_ips) {
7809 message = get_native_backtrace ((MonoException*)exc);
7810 free_message = TRUE;
7811 } else {
7812 MonoObject *other_exc = NULL;
7813 str = mono_object_try_to_string (exc, &other_exc, &error);
7814 if (other_exc == NULL && !is_ok (&error))
7815 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7816 else
7817 mono_error_cleanup (&error);
7818 if (other_exc) {
7819 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7820 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7822 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7823 original_backtrace, nested_backtrace);
7825 g_free (original_backtrace);
7826 g_free (nested_backtrace);
7827 free_message = TRUE;
7828 } else if (str) {
7829 message = mono_string_to_utf8_checked (str, &error);
7830 if (!mono_error_ok (&error)) {
7831 mono_error_cleanup (&error);
7832 message = (char *) "";
7833 } else {
7834 free_message = TRUE;
7841 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7842 * exc->vtable->klass->name, message);
7844 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7846 if (free_message)
7847 g_free (message);
7851 * mono_delegate_ctor_with_method:
7852 * @this: pointer to an uninitialized delegate object
7853 * @target: target object
7854 * @addr: pointer to native code
7855 * @method: method
7856 * @error: set on error.
7858 * Initialize a delegate and sets a specific method, not the one
7859 * associated with addr. This is useful when sharing generic code.
7860 * In that case addr will most probably not be associated with the
7861 * correct instantiation of the method.
7862 * On failure returns FALSE and sets @error.
7864 gboolean
7865 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7867 MONO_REQ_GC_UNSAFE_MODE;
7869 mono_error_init (error);
7870 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7872 g_assert (this_obj);
7873 g_assert (addr);
7875 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7877 if (method)
7878 delegate->method = method;
7880 mono_stats.delegate_creations++;
7882 #ifndef DISABLE_REMOTING
7883 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7884 g_assert (method);
7885 method = mono_marshal_get_remoting_invoke (method);
7886 delegate->method_ptr = mono_compile_method_checked (method, error);
7887 return_val_if_nok (error, FALSE);
7888 MONO_OBJECT_SETREF (delegate, target, target);
7889 } else
7890 #endif
7892 delegate->method_ptr = addr;
7893 MONO_OBJECT_SETREF (delegate, target, target);
7896 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7897 if (callbacks.init_delegate)
7898 callbacks.init_delegate (delegate);
7899 return TRUE;
7903 * mono_delegate_ctor:
7904 * @this: pointer to an uninitialized delegate object
7905 * @target: target object
7906 * @addr: pointer to native code
7907 * @error: set on error.
7909 * This is used to initialize a delegate.
7910 * On failure returns FALSE and sets @error.
7912 gboolean
7913 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7915 MONO_REQ_GC_UNSAFE_MODE;
7917 mono_error_init (error);
7918 MonoDomain *domain = mono_domain_get ();
7919 MonoJitInfo *ji;
7920 MonoMethod *method = NULL;
7922 g_assert (addr);
7924 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7925 /* Shared code */
7926 if (!ji && domain != mono_get_root_domain ())
7927 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7928 if (ji) {
7929 method = mono_jit_info_get_method (ji);
7930 g_assert (!mono_class_is_gtd (method->klass));
7933 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7937 * mono_method_call_message_new:
7938 * @method: method to encapsulate
7939 * @params: parameters to the method
7940 * @invoke: optional, delegate invoke.
7941 * @cb: async callback delegate.
7942 * @state: state passed to the async callback.
7943 * @error: set on error.
7945 * Translates arguments pointers into a MonoMethodMessage.
7946 * On failure returns NULL and sets @error.
7948 MonoMethodMessage *
7949 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7950 MonoDelegate **cb, MonoObject **state, MonoError *error)
7952 MONO_REQ_GC_UNSAFE_MODE;
7954 mono_error_init (error);
7956 MonoDomain *domain = mono_domain_get ();
7957 MonoMethodSignature *sig = mono_method_signature (method);
7958 MonoMethodMessage *msg;
7959 int i, count;
7961 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7962 return_val_if_nok (error, NULL);
7964 if (invoke) {
7965 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7966 return_val_if_nok (error, NULL);
7967 mono_message_init (domain, msg, rm, NULL, error);
7968 return_val_if_nok (error, NULL);
7969 count = sig->param_count - 2;
7970 } else {
7971 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7972 return_val_if_nok (error, NULL);
7973 mono_message_init (domain, msg, rm, NULL, error);
7974 return_val_if_nok (error, NULL);
7975 count = sig->param_count;
7978 for (i = 0; i < count; i++) {
7979 gpointer vpos;
7980 MonoClass *klass;
7981 MonoObject *arg;
7983 if (sig->params [i]->byref)
7984 vpos = *((gpointer *)params [i]);
7985 else
7986 vpos = params [i];
7988 klass = mono_class_from_mono_type (sig->params [i]);
7990 if (klass->valuetype) {
7991 arg = mono_value_box_checked (domain, klass, vpos, error);
7992 return_val_if_nok (error, NULL);
7993 } else
7994 arg = *((MonoObject **)vpos);
7996 mono_array_setref (msg->args, i, arg);
7999 if (cb != NULL && state != NULL) {
8000 *cb = *((MonoDelegate **)params [i]);
8001 i++;
8002 *state = *((MonoObject **)params [i]);
8005 return msg;
8009 * mono_method_return_message_restore:
8011 * Restore results from message based processing back to arguments pointers
8013 void
8014 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8016 MONO_REQ_GC_UNSAFE_MODE;
8018 mono_error_init (error);
8020 MonoMethodSignature *sig = mono_method_signature (method);
8021 int i, j, type, size, out_len;
8023 if (out_args == NULL)
8024 return;
8025 out_len = mono_array_length (out_args);
8026 if (out_len == 0)
8027 return;
8029 for (i = 0, j = 0; i < sig->param_count; i++) {
8030 MonoType *pt = sig->params [i];
8032 if (pt->byref) {
8033 char *arg;
8034 if (j >= out_len) {
8035 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8036 return;
8039 arg = (char *)mono_array_get (out_args, gpointer, j);
8040 type = pt->type;
8042 g_assert (type != MONO_TYPE_VOID);
8044 if (MONO_TYPE_IS_REFERENCE (pt)) {
8045 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8046 } else {
8047 if (arg) {
8048 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8049 size = mono_class_value_size (klass, NULL);
8050 if (klass->has_references)
8051 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8052 else
8053 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8054 } else {
8055 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8056 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8060 j++;
8065 #ifndef DISABLE_REMOTING
8068 * mono_load_remote_field:
8069 * @this: pointer to an object
8070 * @klass: klass of the object containing @field
8071 * @field: the field to load
8072 * @res: a storage to store the result
8074 * This method is called by the runtime on attempts to load fields of
8075 * transparent proxy objects. @this points to such TP, @klass is the class of
8076 * the object containing @field. @res is a storage location which can be
8077 * used to store the result.
8079 * Returns: an address pointing to the value of field.
8081 gpointer
8082 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8084 MonoError error;
8085 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8086 mono_error_cleanup (&error);
8087 return result;
8091 * mono_load_remote_field_checked:
8092 * @this: pointer to an object
8093 * @klass: klass of the object containing @field
8094 * @field: the field to load
8095 * @res: a storage to store the result
8096 * @error: set on error
8098 * This method is called by the runtime on attempts to load fields of
8099 * transparent proxy objects. @this points to such TP, @klass is the class of
8100 * the object containing @field. @res is a storage location which can be
8101 * used to store the result.
8103 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8105 gpointer
8106 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8108 MONO_REQ_GC_UNSAFE_MODE;
8110 static MonoMethod *getter = NULL;
8112 mono_error_init (error);
8114 MonoDomain *domain = mono_domain_get ();
8115 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8116 MonoClass *field_class;
8117 MonoMethodMessage *msg;
8118 MonoArray *out_args;
8119 MonoObject *exc;
8120 char* full_name;
8122 g_assert (mono_object_is_transparent_proxy (this_obj));
8123 g_assert (res != NULL);
8125 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8126 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8127 return res;
8130 if (!getter) {
8131 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8132 if (!getter) {
8133 mono_error_set_not_supported (error, "Linked away.");
8134 return NULL;
8138 field_class = mono_class_from_mono_type (field->type);
8140 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8141 return_val_if_nok (error, NULL);
8142 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8143 return_val_if_nok (error, NULL);
8144 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8145 return_val_if_nok (error, NULL);
8146 mono_message_init (domain, msg, rm, out_args, error);
8147 return_val_if_nok (error, NULL);
8149 full_name = mono_type_get_full_name (klass);
8150 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8151 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8152 g_free (full_name);
8154 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8155 return_val_if_nok (error, NULL);
8157 if (exc) {
8158 mono_error_set_exception_instance (error, (MonoException *)exc);
8159 return NULL;
8162 if (mono_array_length (out_args) == 0)
8163 return NULL;
8165 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8167 if (field_class->valuetype) {
8168 return ((char *)*res) + sizeof (MonoObject);
8169 } else
8170 return res;
8174 * mono_load_remote_field_new:
8175 * @this:
8176 * @klass:
8177 * @field:
8179 * Missing documentation.
8181 MonoObject *
8182 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8184 MonoError error;
8186 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8187 mono_error_cleanup (&error);
8188 return result;
8192 * mono_load_remote_field_new_checked:
8193 * @this: pointer to an object
8194 * @klass: klass of the object containing @field
8195 * @field: the field to load
8196 * @error: set on error.
8198 * This method is called by the runtime on attempts to load fields of
8199 * transparent proxy objects. @this points to such TP, @klass is the class of
8200 * the object containing @field.
8202 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8204 MonoObject *
8205 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8207 MONO_REQ_GC_UNSAFE_MODE;
8209 mono_error_init (error);
8211 static MonoMethod *tp_load = NULL;
8213 g_assert (mono_object_is_transparent_proxy (this_obj));
8215 if (!tp_load) {
8216 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8217 if (!tp_load) {
8218 mono_error_set_not_supported (error, "Linked away.");
8219 return NULL;
8223 /* MonoType *type = mono_class_get_type (klass); */
8225 gpointer args[2];
8226 args [0] = &klass;
8227 args [1] = &field;
8229 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8233 * mono_store_remote_field:
8234 * @this_obj: pointer to an object
8235 * @klass: klass of the object containing @field
8236 * @field: the field to load
8237 * @val: the value/object to store
8239 * This method is called by the runtime on attempts to store fields of
8240 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8241 * the object containing @field. @val is the new value to store in @field.
8243 void
8244 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8246 MonoError error;
8247 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8248 mono_error_cleanup (&error);
8252 * mono_store_remote_field_checked:
8253 * @this_obj: pointer to an object
8254 * @klass: klass of the object containing @field
8255 * @field: the field to load
8256 * @val: the value/object to store
8257 * @error: set on error
8259 * This method is called by the runtime on attempts to store fields of
8260 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8261 * the object containing @field. @val is the new value to store in @field.
8263 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8265 gboolean
8266 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8269 MONO_REQ_GC_UNSAFE_MODE;
8271 mono_error_init (error);
8273 MonoDomain *domain = mono_domain_get ();
8274 MonoClass *field_class;
8275 MonoObject *arg;
8277 g_assert (mono_object_is_transparent_proxy (this_obj));
8279 field_class = mono_class_from_mono_type (field->type);
8281 if (field_class->valuetype) {
8282 arg = mono_value_box_checked (domain, field_class, val, error);
8283 return_val_if_nok (error, FALSE);
8284 } else {
8285 arg = *((MonoObject**)val);
8288 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8292 * mono_store_remote_field_new:
8293 * @this_obj:
8294 * @klass:
8295 * @field:
8296 * @arg:
8298 * Missing documentation
8300 void
8301 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8303 MonoError error;
8304 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8305 mono_error_cleanup (&error);
8309 * mono_store_remote_field_new_checked:
8310 * @this_obj:
8311 * @klass:
8312 * @field:
8313 * @arg:
8314 * @error:
8316 * Missing documentation
8318 gboolean
8319 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8321 MONO_REQ_GC_UNSAFE_MODE;
8323 static MonoMethod *tp_store = NULL;
8325 mono_error_init (error);
8327 g_assert (mono_object_is_transparent_proxy (this_obj));
8329 if (!tp_store) {
8330 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8331 if (!tp_store) {
8332 mono_error_set_not_supported (error, "Linked away.");
8333 return FALSE;
8337 gpointer args[3];
8338 args [0] = &klass;
8339 args [1] = &field;
8340 args [2] = arg;
8342 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8343 return is_ok (error);
8345 #endif
8348 * mono_create_ftnptr:
8350 * Given a function address, create a function descriptor for it.
8351 * This is only needed on some platforms.
8353 gpointer
8354 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8356 return callbacks.create_ftnptr (domain, addr);
8360 * mono_get_addr_from_ftnptr:
8362 * Given a pointer to a function descriptor, return the function address.
8363 * This is only needed on some platforms.
8365 gpointer
8366 mono_get_addr_from_ftnptr (gpointer descr)
8368 return callbacks.get_addr_from_ftnptr (descr);
8372 * mono_string_chars:
8373 * @s: a MonoString
8375 * Returns a pointer to the UCS16 characters stored in the MonoString
8377 gunichar2 *
8378 mono_string_chars (MonoString *s)
8380 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8382 return s->chars;
8386 * mono_string_length:
8387 * @s: MonoString
8389 * Returns the lenght in characters of the string
8392 mono_string_length (MonoString *s)
8394 MONO_REQ_GC_UNSAFE_MODE;
8396 return s->length;
8400 * mono_array_length:
8401 * @array: a MonoArray*
8403 * Returns the total number of elements in the array. This works for
8404 * both vectors and multidimensional arrays.
8406 uintptr_t
8407 mono_array_length (MonoArray *array)
8409 MONO_REQ_GC_UNSAFE_MODE;
8411 return array->max_length;
8415 * mono_array_addr_with_size:
8416 * @array: a MonoArray*
8417 * @size: size of the array elements
8418 * @idx: index into the array
8420 * Use this function to obtain the address for the @idx item on the
8421 * @array containing elements of size @size.
8423 * This method performs no bounds checking or type checking.
8425 * Returns the address of the @idx element in the array.
8427 char*
8428 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8430 MONO_REQ_GC_UNSAFE_MODE;
8432 return ((char*)(array)->vector) + size * idx;
8436 MonoArray *
8437 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8439 MonoDomain *domain = mono_domain_get ();
8440 MonoArray *res;
8441 int len, i;
8443 mono_error_init (error);
8444 if (!list)
8445 return NULL;
8447 len = g_list_length (list);
8448 res = mono_array_new_checked (domain, eclass, len, error);
8449 return_val_if_nok (error, NULL);
8451 for (i = 0; list; list = list->next, i++)
8452 mono_array_set (res, gpointer, i, list->data);
8454 return res;
8457 #if NEVER_DEFINED
8459 * The following section is purely to declare prototypes and
8460 * document the API, as these C files are processed by our
8461 * tool
8465 * mono_array_set:
8466 * @array: array to alter
8467 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8468 * @index: index into the array
8469 * @value: value to set
8471 * Value Type version: This sets the @index's element of the @array
8472 * with elements of size sizeof(type) to the provided @value.
8474 * This macro does not attempt to perform type checking or bounds checking.
8476 * Use this to set value types in a `MonoArray`.
8478 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8483 * mono_array_setref:
8484 * @array: array to alter
8485 * @index: index into the array
8486 * @value: value to set
8488 * Reference Type version: This sets the @index's element of the
8489 * @array with elements of size sizeof(type) to the provided @value.
8491 * This macro does not attempt to perform type checking or bounds checking.
8493 * Use this to reference types in a `MonoArray`.
8495 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8500 * mono_array_get:
8501 * @array: array on which to operate on
8502 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8503 * @index: index into the array
8505 * Use this macro to retrieve the @index element of an @array and
8506 * extract the value assuming that the elements of the array match
8507 * the provided type value.
8509 * This method can be used with both arrays holding value types and
8510 * reference types. For reference types, the @type parameter should
8511 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8513 * This macro does not attempt to perform type checking or bounds checking.
8515 * Returns: The element at the @index position in the @array.
8517 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8520 #endif