[System] Tweak socket test
[mono-project.git] / mono / metadata / object.c
blobb1492101b44025f1fc6c3ce08d39d5dd0abcf80b
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/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
53 static void
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
56 static MonoString*
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
59 static void
60 free_main_args (void);
62 static char *
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
65 static void
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
68 static MonoMethod*
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
84 /**
85 * mono_runtime_object_init:
86 * @this_obj: the object to initialize
88 * This function calls the zero-argument constructor (which must
89 * exist) for the given object.
91 void
92 mono_runtime_object_init (MonoObject *this_obj)
94 MonoError error;
95 mono_runtime_object_init_checked (this_obj, &error);
96 mono_error_assert_ok (&error);
99 /**
100 * mono_runtime_object_init_checked:
101 * @this_obj: the object to initialize
102 * @error: set on error.
104 * This function calls the zero-argument constructor (which must
105 * exist) for the given object and returns TRUE on success, or FALSE
106 * on error and sets @error.
108 gboolean
109 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
111 MONO_REQ_GC_UNSAFE_MODE;
113 MonoMethod *method = NULL;
114 MonoClass *klass = this_obj->vtable->klass;
116 mono_error_init (error);
117 method = mono_class_get_method_from_name (klass, ".ctor", 0);
118 if (!method)
119 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
121 if (method->klass->valuetype)
122 this_obj = (MonoObject *)mono_object_unbox (this_obj);
124 mono_runtime_invoke_checked (method, this_obj, NULL, error);
125 return is_ok (error);
128 /* The pseudo algorithm for type initialization from the spec
129 Note it doesn't say anything about domains - only threads.
131 2. If the type is initialized you are done.
132 2.1. If the type is not yet initialized, try to take an
133 initialization lock.
134 2.2. If successful, record this thread as responsible for
135 initializing the type and proceed to step 2.3.
136 2.2.1. If not, see whether this thread or any thread
137 waiting for this thread to complete already holds the lock.
138 2.2.2. If so, return since blocking would create a deadlock. This thread
139 will now see an incompletely initialized state for the type,
140 but no deadlock will arise.
141 2.2.3 If not, block until the type is initialized then return.
142 2.3 Initialize the parent type and then all interfaces implemented
143 by this type.
144 2.4 Execute the type initialization code for this type.
145 2.5 Mark the type as initialized, release the initialization lock,
146 awaken any threads waiting for this type to be initialized,
147 and return.
151 typedef struct
153 MonoNativeThreadId initializing_tid;
154 guint32 waiting_count;
155 gboolean done;
156 MonoCoopMutex mutex;
157 /* condvar used to wait for 'done' becoming TRUE */
158 MonoCoopCond cond;
159 } TypeInitializationLock;
161 /* for locking access to type_initialization_hash and blocked_thread_hash */
162 static MonoCoopMutex type_initialization_section;
164 static inline void
165 mono_type_initialization_lock (void)
167 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
168 mono_coop_mutex_lock (&type_initialization_section);
171 static inline void
172 mono_type_initialization_unlock (void)
174 mono_coop_mutex_unlock (&type_initialization_section);
177 static void
178 mono_type_init_lock (TypeInitializationLock *lock)
180 MONO_REQ_GC_NEUTRAL_MODE;
182 mono_coop_mutex_lock (&lock->mutex);
185 static void
186 mono_type_init_unlock (TypeInitializationLock *lock)
188 mono_coop_mutex_unlock (&lock->mutex);
191 /* from vtable to lock */
192 static GHashTable *type_initialization_hash;
194 /* from thread id to thread id being waited on */
195 static GHashTable *blocked_thread_hash;
197 /* Main thread */
198 static MonoThread *main_thread;
200 /* Functions supplied by the runtime */
201 static MonoRuntimeCallbacks callbacks;
204 * mono_thread_set_main:
205 * @thread: thread to set as the main thread
207 * This function can be used to instruct the runtime to treat @thread
208 * as the main thread, ie, the thread that would normally execute the Main()
209 * method. This basically means that at the end of @thread, the runtime will
210 * wait for the existing foreground threads to quit and other such details.
212 void
213 mono_thread_set_main (MonoThread *thread)
215 MONO_REQ_GC_UNSAFE_MODE;
217 static gboolean registered = FALSE;
219 if (!registered) {
220 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 registered = TRUE;
224 main_thread = thread;
227 MonoThread*
228 mono_thread_get_main (void)
230 MONO_REQ_GC_UNSAFE_MODE;
232 return main_thread;
235 void
236 mono_type_initialization_init (void)
238 mono_coop_mutex_init_recursive (&type_initialization_section);
239 type_initialization_hash = g_hash_table_new (NULL, NULL);
240 blocked_thread_hash = g_hash_table_new (NULL, NULL);
241 mono_os_mutex_init_recursive (&ldstr_section);
244 void
245 mono_type_initialization_cleanup (void)
247 #if 0
248 /* This is causing race conditions with
249 * mono_release_type_locks
251 mono_coop_mutex_destroy (&type_initialization_section);
252 g_hash_table_destroy (type_initialization_hash);
253 type_initialization_hash = NULL;
254 #endif
255 mono_os_mutex_destroy (&ldstr_section);
256 g_hash_table_destroy (blocked_thread_hash);
257 blocked_thread_hash = NULL;
259 free_main_args ();
263 * get_type_init_exception_for_vtable:
265 * Return the stored type initialization exception for VTABLE.
267 static MonoException*
268 get_type_init_exception_for_vtable (MonoVTable *vtable)
270 MONO_REQ_GC_UNSAFE_MODE;
272 MonoError error;
273 MonoDomain *domain = vtable->domain;
274 MonoClass *klass = vtable->klass;
275 MonoException *ex;
276 gchar *full_name;
278 if (!vtable->init_failed)
279 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282 * If the initializing thread was rudely aborted, the exception is not stored
283 * in the hash.
285 ex = NULL;
286 mono_domain_lock (domain);
287 if (domain->type_init_exception_hash)
288 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
289 mono_domain_unlock (domain);
291 if (!ex) {
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
294 else
295 full_name = g_strdup (klass->name);
296 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
297 g_free (full_name);
298 return_val_if_nok (&error, NULL);
301 return ex;
305 * mono_runtime_class_init:
306 * @vtable: vtable that needs to be initialized
308 * This routine calls the class constructor for @vtable.
310 void
311 mono_runtime_class_init (MonoVTable *vtable)
313 MONO_REQ_GC_UNSAFE_MODE;
314 MonoError error;
316 mono_runtime_class_init_full (vtable, &error);
317 mono_error_assert_ok (&error);
321 * Returns TRUE if the lock was freed.
322 * LOCKING: Caller should hold type_initialization_lock.
324 static gboolean
325 unref_type_lock (TypeInitializationLock *lock)
327 --lock->waiting_count;
328 if (lock->waiting_count == 0) {
329 mono_coop_mutex_destroy (&lock->mutex);
330 mono_coop_cond_destroy (&lock->cond);
331 g_free (lock);
332 return TRUE;
333 } else {
334 return FALSE;
339 * mono_runtime_class_init_full:
340 * @vtable that neeeds to be initialized
341 * @error set on error
343 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
346 gboolean
347 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
349 MONO_REQ_GC_UNSAFE_MODE;
351 MonoMethod *method = NULL;
352 MonoClass *klass;
353 gchar *full_name;
354 MonoDomain *domain = vtable->domain;
355 TypeInitializationLock *lock;
356 MonoNativeThreadId tid;
357 int do_initialization = 0;
358 MonoDomain *last_domain = NULL;
359 MonoException * pending_tae = NULL;
361 mono_error_init (error);
363 if (vtable->initialized)
364 return TRUE;
366 klass = vtable->klass;
368 if (!klass->image->checked_module_cctor) {
369 mono_image_check_for_module_cctor (klass->image);
370 if (klass->image->has_module_cctor) {
371 MonoClass *module_klass;
372 MonoVTable *module_vtable;
374 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
375 if (!module_klass) {
376 return FALSE;
379 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
380 if (!module_vtable)
381 return FALSE;
382 if (!mono_runtime_class_init_full (module_vtable, error))
383 return FALSE;
386 method = mono_class_get_cctor (klass);
387 if (!method) {
388 vtable->initialized = 1;
389 return TRUE;
392 tid = mono_native_thread_id_get ();
395 * Due some preprocessing inside a global lock. If we are the first thread
396 * trying to initialize this class, create a separate lock+cond var, and
397 * acquire it before leaving the global lock. The other threads will wait
398 * on this cond var.
401 mono_type_initialization_lock ();
402 /* double check... */
403 if (vtable->initialized) {
404 mono_type_initialization_unlock ();
405 return TRUE;
407 if (vtable->init_failed) {
408 mono_type_initialization_unlock ();
410 /* The type initialization already failed once, rethrow the same exception */
411 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
412 return FALSE;
414 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
415 if (lock == NULL) {
416 /* This thread will get to do the initialization */
417 if (mono_domain_get () != domain) {
418 /* Transfer into the target domain */
419 last_domain = mono_domain_get ();
420 if (!mono_domain_set (domain, FALSE)) {
421 vtable->initialized = 1;
422 mono_type_initialization_unlock ();
423 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
424 return FALSE;
427 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
428 mono_coop_mutex_init_recursive (&lock->mutex);
429 mono_coop_cond_init (&lock->cond);
430 lock->initializing_tid = tid;
431 lock->waiting_count = 1;
432 lock->done = FALSE;
433 g_hash_table_insert (type_initialization_hash, vtable, lock);
434 do_initialization = 1;
435 } else {
436 gpointer blocked;
437 TypeInitializationLock *pending_lock;
439 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
440 mono_type_initialization_unlock ();
441 return TRUE;
443 /* see if the thread doing the initialization is already blocked on this thread */
444 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
445 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
446 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
447 if (!pending_lock->done) {
448 mono_type_initialization_unlock ();
449 return TRUE;
450 } else {
451 /* the thread doing the initialization is blocked on this thread,
452 but on a lock that has already been freed. It just hasn't got
453 time to awake */
454 break;
457 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
459 ++lock->waiting_count;
460 /* record the fact that we are waiting on the initializing thread */
461 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
463 mono_type_initialization_unlock ();
465 if (do_initialization) {
466 MonoException *exc = NULL;
468 /* We are holding the per-vtable lock, do the actual initialization */
470 mono_threads_begin_abort_protected_block ();
471 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
472 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
474 //exception extracted, error will be set to the right value later
475 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
476 exc = mono_error_convert_to_exception (error);
477 else
478 mono_error_cleanup (error);
480 mono_error_init (error);
482 /* If the initialization failed, mark the class as unusable. */
483 /* Avoid infinite loops */
484 if (!(!exc ||
485 (klass->image == mono_defaults.corlib &&
486 !strcmp (klass->name_space, "System") &&
487 !strcmp (klass->name, "TypeInitializationException")))) {
488 vtable->init_failed = 1;
490 if (klass->name_space && *klass->name_space)
491 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
492 else
493 full_name = g_strdup (klass->name);
495 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
496 g_free (full_name);
498 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
501 * Store the exception object so it could be thrown on subsequent
502 * accesses.
504 mono_domain_lock (domain);
505 if (!domain->type_init_exception_hash)
506 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");
507 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
508 mono_domain_unlock (domain);
511 if (last_domain)
512 mono_domain_set (last_domain, TRUE);
514 /* Signal to the other threads that we are done */
515 mono_type_init_lock (lock);
516 lock->done = TRUE;
517 mono_coop_cond_broadcast (&lock->cond);
518 mono_type_init_unlock (lock);
520 //This can happen if the cctor self-aborts
521 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
522 pending_tae = exc;
524 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
525 if (!pending_tae && got_pending_interrupt)
526 pending_tae = mono_thread_try_resume_interruption ();
527 } else {
528 /* this just blocks until the initializing thread is done */
529 mono_type_init_lock (lock);
530 while (!lock->done)
531 mono_coop_cond_wait (&lock->cond, &lock->mutex);
532 mono_type_init_unlock (lock);
535 /* Do cleanup and setting vtable->initialized inside the global lock again */
536 mono_type_initialization_lock ();
537 if (!do_initialization)
538 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
539 gboolean deleted = unref_type_lock (lock);
540 if (deleted)
541 g_hash_table_remove (type_initialization_hash, vtable);
542 /* Have to set this here since we check it inside the global lock */
543 if (do_initialization && !vtable->init_failed)
544 vtable->initialized = 1;
545 mono_type_initialization_unlock ();
547 //TAE wins over TIE
548 if (pending_tae)
549 mono_error_set_exception_instance (error, pending_tae);
550 else if (vtable->init_failed) {
551 /* Either we were the initializing thread or we waited for the initialization */
552 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
553 return FALSE;
555 return TRUE;
558 static
559 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
561 MONO_REQ_GC_NEUTRAL_MODE;
563 MonoVTable *vtable = (MonoVTable*)key;
565 TypeInitializationLock *lock = (TypeInitializationLock*) value;
566 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
567 lock->done = TRUE;
569 * Have to set this since it cannot be set by the normal code in
570 * mono_runtime_class_init (). In this case, the exception object is not stored,
571 * and get_type_init_exception_for_class () needs to be aware of this.
573 mono_type_init_lock (lock);
574 vtable->init_failed = 1;
575 mono_coop_cond_broadcast (&lock->cond);
576 mono_type_init_unlock (lock);
577 gboolean deleted = unref_type_lock (lock);
578 if (deleted)
579 return TRUE;
581 return FALSE;
584 void
585 mono_release_type_locks (MonoInternalThread *thread)
587 MONO_REQ_GC_UNSAFE_MODE;
589 mono_type_initialization_lock ();
590 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
591 mono_type_initialization_unlock ();
594 #ifndef DISABLE_REMOTING
596 static gpointer
597 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
599 if (!callbacks.create_remoting_trampoline)
600 g_error ("remoting not installed");
601 return callbacks.create_remoting_trampoline (domain, method, target, error);
604 #endif
606 static MonoImtTrampolineBuilder imt_trampoline_builder;
607 static gboolean always_build_imt_trampolines;
609 #if (MONO_IMT_SIZE > 32)
610 #error "MONO_IMT_SIZE cannot be larger than 32"
611 #endif
613 void
614 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
616 memcpy (&callbacks, cbs, sizeof (*cbs));
619 MonoRuntimeCallbacks*
620 mono_get_runtime_callbacks (void)
622 return &callbacks;
625 void
626 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
628 imt_trampoline_builder = func;
631 void
632 mono_set_always_build_imt_trampolines (gboolean value)
634 always_build_imt_trampolines = value;
638 * mono_compile_method:
639 * @method: The method to compile.
641 * This JIT-compiles the method, and returns the pointer to the native code
642 * produced.
644 gpointer
645 mono_compile_method (MonoMethod *method)
647 MonoError error;
648 gpointer result = mono_compile_method_checked (method, &error);
649 mono_error_cleanup (&error);
650 return result;
654 * mono_compile_method:
655 * @method: The method to compile.
656 * @error: set on error.
658 * This JIT-compiles the method, and returns the pointer to the native code
659 * produced. On failure returns NULL and sets @error.
661 gpointer
662 mono_compile_method_checked (MonoMethod *method, MonoError *error)
664 gpointer res;
666 MONO_REQ_GC_NEUTRAL_MODE
668 mono_error_init (error);
670 g_assert (callbacks.compile_method);
671 res = callbacks.compile_method (method, error);
672 return res;
675 gpointer
676 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
678 gpointer res;
680 MONO_REQ_GC_NEUTRAL_MODE;
682 mono_error_init (error);
683 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
684 return res;
687 gpointer
688 mono_runtime_create_delegate_trampoline (MonoClass *klass)
690 MONO_REQ_GC_NEUTRAL_MODE
692 g_assert (callbacks.create_delegate_trampoline);
693 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
697 * mono_runtime_free_method:
698 * @domain; domain where the method is hosted
699 * @method: method to release
701 * This routine is invoked to free the resources associated with
702 * a method that has been JIT compiled. This is used to discard
703 * methods that were used only temporarily (for example, used in marshalling)
706 void
707 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
709 MONO_REQ_GC_NEUTRAL_MODE
711 if (callbacks.free_method)
712 callbacks.free_method (domain, method);
714 mono_method_clear_object (domain, method);
716 mono_free_method (method);
720 * The vtables in the root appdomain are assumed to be reachable by other
721 * roots, and we don't use typed allocation in the other domains.
724 /* The sync block is no longer a GC pointer */
725 #define GC_HEADER_BITMAP (0)
727 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
729 static gsize*
730 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
732 MONO_REQ_GC_NEUTRAL_MODE;
734 MonoClassField *field;
735 MonoClass *p;
736 guint32 pos;
737 int max_size;
739 if (static_fields)
740 max_size = mono_class_data_size (klass) / sizeof (gpointer);
741 else
742 max_size = klass->instance_size / sizeof (gpointer);
743 if (max_size > size) {
744 g_assert (offset <= 0);
745 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
746 size = max_size;
749 #ifdef HAVE_SGEN_GC
750 /*An Ephemeron cannot be marked by sgen*/
751 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
752 *max_set = 0;
753 memset (bitmap, 0, size / 8);
754 return bitmap;
756 #endif
758 for (p = klass; p != NULL; p = p->parent) {
759 gpointer iter = NULL;
760 while ((field = mono_class_get_fields (p, &iter))) {
761 MonoType *type;
763 if (static_fields) {
764 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
765 continue;
766 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
767 continue;
768 } else {
769 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
770 continue;
772 /* FIXME: should not happen, flag as type load error */
773 if (field->type->byref)
774 break;
776 if (static_fields && field->offset == -1)
777 /* special static */
778 continue;
780 pos = field->offset / sizeof (gpointer);
781 pos += offset;
783 type = mono_type_get_underlying_type (field->type);
784 switch (type->type) {
785 case MONO_TYPE_U:
786 case MONO_TYPE_I:
787 case MONO_TYPE_PTR:
788 case MONO_TYPE_FNPTR:
789 break;
790 case MONO_TYPE_STRING:
791 case MONO_TYPE_SZARRAY:
792 case MONO_TYPE_CLASS:
793 case MONO_TYPE_OBJECT:
794 case MONO_TYPE_ARRAY:
795 g_assert ((field->offset % sizeof(gpointer)) == 0);
797 g_assert (pos < size || pos <= max_size);
798 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
799 *max_set = MAX (*max_set, pos);
800 break;
801 case MONO_TYPE_GENERICINST:
802 if (!mono_type_generic_inst_is_valuetype (type)) {
803 g_assert ((field->offset % sizeof(gpointer)) == 0);
805 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
806 *max_set = MAX (*max_set, pos);
807 break;
808 } else {
809 /* fall through */
811 case MONO_TYPE_VALUETYPE: {
812 MonoClass *fclass = mono_class_from_mono_type (field->type);
813 if (fclass->has_references) {
814 /* remove the object header */
815 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
817 break;
819 case MONO_TYPE_I1:
820 case MONO_TYPE_U1:
821 case MONO_TYPE_I2:
822 case MONO_TYPE_U2:
823 case MONO_TYPE_I4:
824 case MONO_TYPE_U4:
825 case MONO_TYPE_I8:
826 case MONO_TYPE_U8:
827 case MONO_TYPE_R4:
828 case MONO_TYPE_R8:
829 case MONO_TYPE_BOOLEAN:
830 case MONO_TYPE_CHAR:
831 break;
832 default:
833 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
834 break;
837 if (static_fields)
838 break;
840 return bitmap;
844 * mono_class_compute_bitmap:
846 * Mono internal function to compute a bitmap of reference fields in a class.
848 gsize*
849 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
851 MONO_REQ_GC_NEUTRAL_MODE;
853 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
856 #if 0
858 * similar to the above, but sets the bits in the bitmap for any non-ref field
859 * and ignores static fields
861 static gsize*
862 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
864 MonoClassField *field;
865 MonoClass *p;
866 guint32 pos, pos2;
867 int max_size;
869 max_size = class->instance_size / sizeof (gpointer);
870 if (max_size >= size) {
871 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
874 for (p = class; p != NULL; p = p->parent) {
875 gpointer iter = NULL;
876 while ((field = mono_class_get_fields (p, &iter))) {
877 MonoType *type;
879 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
880 continue;
881 /* FIXME: should not happen, flag as type load error */
882 if (field->type->byref)
883 break;
885 pos = field->offset / sizeof (gpointer);
886 pos += offset;
888 type = mono_type_get_underlying_type (field->type);
889 switch (type->type) {
890 #if SIZEOF_VOID_P == 8
891 case MONO_TYPE_I:
892 case MONO_TYPE_U:
893 case MONO_TYPE_PTR:
894 case MONO_TYPE_FNPTR:
895 #endif
896 case MONO_TYPE_I8:
897 case MONO_TYPE_U8:
898 case MONO_TYPE_R8:
899 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
900 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
901 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
903 /* fall through */
904 #if SIZEOF_VOID_P == 4
905 case MONO_TYPE_I:
906 case MONO_TYPE_U:
907 case MONO_TYPE_PTR:
908 case MONO_TYPE_FNPTR:
909 #endif
910 case MONO_TYPE_I4:
911 case MONO_TYPE_U4:
912 case MONO_TYPE_R4:
913 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
914 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
915 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
917 /* fall through */
918 case MONO_TYPE_CHAR:
919 case MONO_TYPE_I2:
920 case MONO_TYPE_U2:
921 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
922 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
923 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
925 /* fall through */
926 case MONO_TYPE_BOOLEAN:
927 case MONO_TYPE_I1:
928 case MONO_TYPE_U1:
929 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
930 break;
931 case MONO_TYPE_STRING:
932 case MONO_TYPE_SZARRAY:
933 case MONO_TYPE_CLASS:
934 case MONO_TYPE_OBJECT:
935 case MONO_TYPE_ARRAY:
936 break;
937 case MONO_TYPE_GENERICINST:
938 if (!mono_type_generic_inst_is_valuetype (type)) {
939 break;
940 } else {
941 /* fall through */
943 case MONO_TYPE_VALUETYPE: {
944 MonoClass *fclass = mono_class_from_mono_type (field->type);
945 /* remove the object header */
946 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
947 break;
949 default:
950 g_assert_not_reached ();
951 break;
955 return bitmap;
959 * mono_class_insecure_overlapping:
960 * check if a class with explicit layout has references and non-references
961 * fields overlapping.
963 * Returns: TRUE if it is insecure to load the type.
965 gboolean
966 mono_class_insecure_overlapping (MonoClass *klass)
968 int max_set = 0;
969 gsize *bitmap;
970 gsize default_bitmap [4] = {0};
971 gsize *nrbitmap;
972 gsize default_nrbitmap [4] = {0};
973 int i, insecure = FALSE;
974 return FALSE;
976 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
977 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
979 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
980 int idx = i % (sizeof (bitmap [0]) * 8);
981 if (bitmap [idx] & nrbitmap [idx]) {
982 insecure = TRUE;
983 break;
986 if (bitmap != default_bitmap)
987 g_free (bitmap);
988 if (nrbitmap != default_nrbitmap)
989 g_free (nrbitmap);
990 if (insecure) {
991 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
992 return FALSE;
994 return insecure;
996 #endif
998 MonoString*
999 ves_icall_string_alloc (int length)
1001 MonoError error;
1002 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1003 mono_error_set_pending_exception (&error);
1005 return str;
1008 /* LOCKING: Acquires the loader lock */
1009 void
1010 mono_class_compute_gc_descriptor (MonoClass *klass)
1012 MONO_REQ_GC_NEUTRAL_MODE;
1014 int max_set = 0;
1015 gsize *bitmap;
1016 gsize default_bitmap [4] = {0};
1017 static gboolean gcj_inited = FALSE;
1018 MonoGCDescriptor gc_descr;
1020 if (!gcj_inited) {
1021 mono_loader_lock ();
1023 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1024 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1026 gcj_inited = TRUE;
1027 mono_loader_unlock ();
1030 if (!klass->inited)
1031 mono_class_init (klass);
1033 if (klass->gc_descr_inited)
1034 return;
1036 bitmap = default_bitmap;
1037 if (klass == mono_defaults.string_class) {
1038 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1039 } else if (klass->rank) {
1040 mono_class_compute_gc_descriptor (klass->element_class);
1041 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1042 gsize abm = 1;
1043 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1044 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1045 class->name_space, class->name);*/
1046 } else {
1047 /* remove the object header */
1048 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1049 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));
1050 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1051 class->name_space, class->name);*/
1052 if (bitmap != default_bitmap)
1053 g_free (bitmap);
1055 } else {
1056 /*static int count = 0;
1057 if (count++ > 58)
1058 return;*/
1059 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1060 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1062 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1063 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1065 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1066 if (bitmap != default_bitmap)
1067 g_free (bitmap);
1070 /* Publish the data */
1071 mono_loader_lock ();
1072 klass->gc_descr = gc_descr;
1073 mono_memory_barrier ();
1074 klass->gc_descr_inited = TRUE;
1075 mono_loader_unlock ();
1079 * field_is_special_static:
1080 * @fklass: The MonoClass to look up.
1081 * @field: The MonoClassField describing the field.
1083 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1084 * SPECIAL_STATIC_NONE otherwise.
1086 static gint32
1087 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1089 MONO_REQ_GC_NEUTRAL_MODE;
1091 MonoError error;
1092 MonoCustomAttrInfo *ainfo;
1093 int i;
1094 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1095 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1096 if (!ainfo)
1097 return FALSE;
1098 for (i = 0; i < ainfo->num_attrs; ++i) {
1099 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1100 if (klass->image == mono_defaults.corlib) {
1101 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1102 mono_custom_attrs_free (ainfo);
1103 return SPECIAL_STATIC_THREAD;
1105 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1106 mono_custom_attrs_free (ainfo);
1107 return SPECIAL_STATIC_CONTEXT;
1111 mono_custom_attrs_free (ainfo);
1112 return SPECIAL_STATIC_NONE;
1115 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1116 #define mix(a,b,c) { \
1117 a -= c; a ^= rot(c, 4); c += b; \
1118 b -= a; b ^= rot(a, 6); a += c; \
1119 c -= b; c ^= rot(b, 8); b += a; \
1120 a -= c; a ^= rot(c,16); c += b; \
1121 b -= a; b ^= rot(a,19); a += c; \
1122 c -= b; c ^= rot(b, 4); b += a; \
1124 #define final(a,b,c) { \
1125 c ^= b; c -= rot(b,14); \
1126 a ^= c; a -= rot(c,11); \
1127 b ^= a; b -= rot(a,25); \
1128 c ^= b; c -= rot(b,16); \
1129 a ^= c; a -= rot(c,4); \
1130 b ^= a; b -= rot(a,14); \
1131 c ^= b; c -= rot(b,24); \
1135 * mono_method_get_imt_slot:
1137 * The IMT slot is embedded into AOTed code, so this must return the same value
1138 * for the same method across all executions. This means:
1139 * - pointers shouldn't be used as hash values.
1140 * - mono_metadata_str_hash () should be used for hashing strings.
1142 guint32
1143 mono_method_get_imt_slot (MonoMethod *method)
1145 MONO_REQ_GC_NEUTRAL_MODE;
1147 MonoMethodSignature *sig;
1148 int hashes_count;
1149 guint32 *hashes_start, *hashes;
1150 guint32 a, b, c;
1151 int i;
1153 /* This can be used to stress tests the collision code */
1154 //return 0;
1157 * We do this to simplify generic sharing. It will hurt
1158 * performance in cases where a class implements two different
1159 * instantiations of the same generic interface.
1160 * The code in build_imt_slots () depends on this.
1162 if (method->is_inflated)
1163 method = ((MonoMethodInflated*)method)->declaring;
1165 sig = mono_method_signature (method);
1166 hashes_count = sig->param_count + 4;
1167 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1168 hashes = hashes_start;
1170 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1171 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1172 method->klass->name_space, method->klass->name, method->name);
1175 /* Initialize hashes */
1176 hashes [0] = mono_metadata_str_hash (method->klass->name);
1177 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1178 hashes [2] = mono_metadata_str_hash (method->name);
1179 hashes [3] = mono_metadata_type_hash (sig->ret);
1180 for (i = 0; i < sig->param_count; i++) {
1181 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1184 /* Setup internal state */
1185 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1187 /* Handle most of the hashes */
1188 while (hashes_count > 3) {
1189 a += hashes [0];
1190 b += hashes [1];
1191 c += hashes [2];
1192 mix (a,b,c);
1193 hashes_count -= 3;
1194 hashes += 3;
1197 /* Handle the last 3 hashes (all the case statements fall through) */
1198 switch (hashes_count) {
1199 case 3 : c += hashes [2];
1200 case 2 : b += hashes [1];
1201 case 1 : a += hashes [0];
1202 final (a,b,c);
1203 case 0: /* nothing left to add */
1204 break;
1207 g_free (hashes_start);
1208 /* Report the result */
1209 return c % MONO_IMT_SIZE;
1211 #undef rot
1212 #undef mix
1213 #undef final
1215 #define DEBUG_IMT 0
1217 static void
1218 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1219 MONO_REQ_GC_NEUTRAL_MODE;
1221 guint32 imt_slot = mono_method_get_imt_slot (method);
1222 MonoImtBuilderEntry *entry;
1224 if (slot_num >= 0 && imt_slot != slot_num) {
1225 /* we build just a single imt slot and this is not it */
1226 return;
1229 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1230 entry->key = method;
1231 entry->value.vtable_slot = vtable_slot;
1232 entry->next = imt_builder [imt_slot];
1233 if (imt_builder [imt_slot] != NULL) {
1234 entry->children = imt_builder [imt_slot]->children + 1;
1235 if (entry->children == 1) {
1236 mono_stats.imt_slots_with_collisions++;
1237 *imt_collisions_bitmap |= (1 << imt_slot);
1239 } else {
1240 entry->children = 0;
1241 mono_stats.imt_used_slots++;
1243 imt_builder [imt_slot] = entry;
1244 #if DEBUG_IMT
1246 char *method_name = mono_method_full_name (method, TRUE);
1247 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1248 method, method_name, imt_slot, vtable_slot, entry->children);
1249 g_free (method_name);
1251 #endif
1254 #if DEBUG_IMT
1255 static void
1256 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1257 if (e != NULL) {
1258 MonoMethod *method = e->key;
1259 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1260 message,
1261 num,
1262 method,
1263 method->klass->name_space,
1264 method->klass->name,
1265 method->name);
1266 } else {
1267 printf (" * %s: NULL\n", message);
1270 #endif
1272 static int
1273 compare_imt_builder_entries (const void *p1, const void *p2) {
1274 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1275 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1277 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1280 static int
1281 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1283 MONO_REQ_GC_NEUTRAL_MODE;
1285 int count = end - start;
1286 int chunk_start = out_array->len;
1287 if (count < 4) {
1288 int i;
1289 for (i = start; i < end; ++i) {
1290 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1291 item->key = sorted_array [i]->key;
1292 item->value = sorted_array [i]->value;
1293 item->has_target_code = sorted_array [i]->has_target_code;
1294 item->is_equals = TRUE;
1295 if (i < end - 1)
1296 item->check_target_idx = out_array->len + 1;
1297 else
1298 item->check_target_idx = 0;
1299 g_ptr_array_add (out_array, item);
1301 } else {
1302 int middle = start + count / 2;
1303 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1305 item->key = sorted_array [middle]->key;
1306 item->is_equals = FALSE;
1307 g_ptr_array_add (out_array, item);
1308 imt_emit_ir (sorted_array, start, middle, out_array);
1309 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1311 return chunk_start;
1314 static GPtrArray*
1315 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1316 MONO_REQ_GC_NEUTRAL_MODE;
1318 int number_of_entries = entries->children + 1;
1319 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1320 GPtrArray *result = g_ptr_array_new ();
1321 MonoImtBuilderEntry *current_entry;
1322 int i;
1324 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1325 sorted_array [i] = current_entry;
1327 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1329 /*for (i = 0; i < number_of_entries; i++) {
1330 print_imt_entry (" sorted array:", sorted_array [i], i);
1333 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1335 g_free (sorted_array);
1336 return result;
1339 static gpointer
1340 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1342 MONO_REQ_GC_NEUTRAL_MODE;
1344 if (imt_builder_entry != NULL) {
1345 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1346 /* No collision, return the vtable slot contents */
1347 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1348 } else {
1349 /* Collision, build the trampoline */
1350 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1351 gpointer result;
1352 int i;
1353 result = imt_trampoline_builder (vtable, domain,
1354 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1355 for (i = 0; i < imt_ir->len; ++i)
1356 g_free (g_ptr_array_index (imt_ir, i));
1357 g_ptr_array_free (imt_ir, TRUE);
1358 return result;
1360 } else {
1361 if (fail_tramp)
1362 return fail_tramp;
1363 else
1364 /* Empty slot */
1365 return NULL;
1369 static MonoImtBuilderEntry*
1370 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1373 * LOCKING: requires the loader and domain locks.
1376 static void
1377 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1379 MONO_REQ_GC_NEUTRAL_MODE;
1381 int i;
1382 GSList *list_item;
1383 guint32 imt_collisions_bitmap = 0;
1384 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1385 int method_count = 0;
1386 gboolean record_method_count_for_max_collisions = FALSE;
1387 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1389 #if DEBUG_IMT
1390 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1391 #endif
1392 for (i = 0; i < klass->interface_offsets_count; ++i) {
1393 MonoClass *iface = klass->interfaces_packed [i];
1394 int interface_offset = klass->interface_offsets_packed [i];
1395 int method_slot_in_interface, vt_slot;
1397 if (mono_class_has_variant_generic_params (iface))
1398 has_variant_iface = TRUE;
1400 mono_class_setup_methods (iface);
1401 vt_slot = interface_offset;
1402 int mcount = mono_class_get_method_count (iface);
1403 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1404 MonoMethod *method;
1406 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1408 * The imt slot of the method is the same as for its declaring method,
1409 * see the comment in mono_method_get_imt_slot (), so we can
1410 * avoid inflating methods which will be discarded by
1411 * add_imt_builder_entry anyway.
1413 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1414 if (mono_method_get_imt_slot (method) != slot_num) {
1415 vt_slot ++;
1416 continue;
1419 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1420 if (method->is_generic) {
1421 has_generic_virtual = TRUE;
1422 vt_slot ++;
1423 continue;
1426 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1427 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1428 vt_slot ++;
1432 if (extra_interfaces) {
1433 int interface_offset = klass->vtable_size;
1435 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1436 MonoClass* iface = (MonoClass *)list_item->data;
1437 int method_slot_in_interface;
1438 int mcount = mono_class_get_method_count (iface);
1439 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1440 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1442 if (method->is_generic)
1443 has_generic_virtual = TRUE;
1444 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1446 interface_offset += mcount;
1449 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1450 /* overwrite the imt slot only if we're building all the entries or if
1451 * we're building this specific one
1453 if (slot_num < 0 || i == slot_num) {
1454 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1456 if (entries) {
1457 if (imt_builder [i]) {
1458 MonoImtBuilderEntry *entry;
1460 /* Link entries with imt_builder [i] */
1461 for (entry = entries; entry->next; entry = entry->next) {
1462 #if DEBUG_IMT
1463 MonoMethod *method = (MonoMethod*)entry->key;
1464 char *method_name = mono_method_full_name (method, TRUE);
1465 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1466 g_free (method_name);
1467 #endif
1469 entry->next = imt_builder [i];
1470 entries->children += imt_builder [i]->children + 1;
1472 imt_builder [i] = entries;
1475 if (has_generic_virtual || has_variant_iface) {
1477 * There might be collisions later when the the trampoline is expanded.
1479 imt_collisions_bitmap |= (1 << i);
1482 * The IMT trampoline might be called with an instance of one of the
1483 * generic virtual methods, so has to fallback to the IMT trampoline.
1485 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1486 } else {
1487 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1489 #if DEBUG_IMT
1490 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1491 #endif
1494 if (imt_builder [i] != NULL) {
1495 int methods_in_slot = imt_builder [i]->children + 1;
1496 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1497 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1498 record_method_count_for_max_collisions = TRUE;
1500 method_count += methods_in_slot;
1504 mono_stats.imt_number_of_methods += method_count;
1505 if (record_method_count_for_max_collisions) {
1506 mono_stats.imt_method_count_when_max_collisions = method_count;
1509 for (i = 0; i < MONO_IMT_SIZE; i++) {
1510 MonoImtBuilderEntry* entry = imt_builder [i];
1511 while (entry != NULL) {
1512 MonoImtBuilderEntry* next = entry->next;
1513 g_free (entry);
1514 entry = next;
1517 g_free (imt_builder);
1518 /* we OR the bitmap since we may build just a single imt slot at a time */
1519 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1522 static void
1523 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1524 MONO_REQ_GC_NEUTRAL_MODE;
1526 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1530 * mono_vtable_build_imt_slot:
1531 * @vtable: virtual object table struct
1532 * @imt_slot: slot in the IMT table
1534 * Fill the given @imt_slot in the IMT table of @vtable with
1535 * a trampoline or a trampoline for the case of collisions.
1536 * This is part of the internal mono API.
1538 * LOCKING: Take the domain lock.
1540 void
1541 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1543 MONO_REQ_GC_NEUTRAL_MODE;
1545 gpointer *imt = (gpointer*)vtable;
1546 imt -= MONO_IMT_SIZE;
1547 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1549 /* no support for extra interfaces: the proxy objects will need
1550 * to build the complete IMT
1551 * Update and heck needs to ahppen inside the proper domain lock, as all
1552 * the changes made to a MonoVTable.
1554 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1555 mono_domain_lock (vtable->domain);
1556 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1557 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1558 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1559 mono_domain_unlock (vtable->domain);
1560 mono_loader_unlock ();
1563 #define THUNK_THRESHOLD 10
1566 * mono_method_alloc_generic_virtual_trampoline:
1567 * @domain: a domain
1568 * @size: size in bytes
1570 * Allocs size bytes to be used for the code of a generic virtual
1571 * trampoline. It's either allocated from the domain's code manager or
1572 * reused from a previously invalidated piece.
1574 * LOCKING: The domain lock must be held.
1576 gpointer
1577 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1579 MONO_REQ_GC_NEUTRAL_MODE;
1581 static gboolean inited = FALSE;
1582 static int generic_virtual_trampolines_size = 0;
1584 if (!inited) {
1585 mono_counters_register ("Generic virtual trampoline bytes",
1586 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1587 inited = TRUE;
1589 generic_virtual_trampolines_size += size;
1591 return mono_domain_code_reserve (domain, size);
1594 typedef struct _GenericVirtualCase {
1595 MonoMethod *method;
1596 gpointer code;
1597 int count;
1598 struct _GenericVirtualCase *next;
1599 } GenericVirtualCase;
1602 * get_generic_virtual_entries:
1604 * Return IMT entries for the generic virtual method instances and
1605 * variant interface methods for vtable slot
1606 * VTABLE_SLOT.
1608 static MonoImtBuilderEntry*
1609 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1611 MONO_REQ_GC_NEUTRAL_MODE;
1613 GenericVirtualCase *list;
1614 MonoImtBuilderEntry *entries;
1616 mono_domain_lock (domain);
1617 if (!domain->generic_virtual_cases)
1618 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1620 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1622 entries = NULL;
1623 for (; list; list = list->next) {
1624 MonoImtBuilderEntry *entry;
1626 if (list->count < THUNK_THRESHOLD)
1627 continue;
1629 entry = g_new0 (MonoImtBuilderEntry, 1);
1630 entry->key = list->method;
1631 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1632 entry->has_target_code = 1;
1633 if (entries)
1634 entry->children = entries->children + 1;
1635 entry->next = entries;
1636 entries = entry;
1639 mono_domain_unlock (domain);
1641 /* FIXME: Leaking memory ? */
1642 return entries;
1646 * mono_method_add_generic_virtual_invocation:
1647 * @domain: a domain
1648 * @vtable_slot: pointer to the vtable slot
1649 * @method: the inflated generic virtual method
1650 * @code: the method's code
1652 * Registers a call via unmanaged code to a generic virtual method
1653 * instantiation or variant interface method. If the number of calls reaches a threshold
1654 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1655 * virtual method trampoline.
1657 void
1658 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1659 gpointer *vtable_slot,
1660 MonoMethod *method, gpointer code)
1662 MONO_REQ_GC_NEUTRAL_MODE;
1664 static gboolean inited = FALSE;
1665 static int num_added = 0;
1666 static int num_freed = 0;
1668 GenericVirtualCase *gvc, *list;
1669 MonoImtBuilderEntry *entries;
1670 int i;
1671 GPtrArray *sorted;
1673 mono_domain_lock (domain);
1674 if (!domain->generic_virtual_cases)
1675 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1677 if (!inited) {
1678 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1679 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1680 inited = TRUE;
1683 /* Check whether the case was already added */
1684 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1685 gvc = list;
1686 while (gvc) {
1687 if (gvc->method == method)
1688 break;
1689 gvc = gvc->next;
1692 /* If not found, make a new one */
1693 if (!gvc) {
1694 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1695 gvc->method = method;
1696 gvc->code = code;
1697 gvc->count = 0;
1698 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1700 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1702 num_added++;
1705 if (++gvc->count == THUNK_THRESHOLD) {
1706 gpointer *old_thunk = (void **)*vtable_slot;
1707 gpointer vtable_trampoline = NULL;
1708 gpointer imt_trampoline = NULL;
1710 if ((gpointer)vtable_slot < (gpointer)vtable) {
1711 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1712 int imt_slot = MONO_IMT_SIZE + displacement;
1714 /* Force the rebuild of the trampoline at the next call */
1715 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1716 *vtable_slot = imt_trampoline;
1717 } else {
1718 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1720 entries = get_generic_virtual_entries (domain, vtable_slot);
1722 sorted = imt_sort_slot_entries (entries);
1724 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1725 vtable_trampoline);
1727 while (entries) {
1728 MonoImtBuilderEntry *next = entries->next;
1729 g_free (entries);
1730 entries = next;
1733 for (i = 0; i < sorted->len; ++i)
1734 g_free (g_ptr_array_index (sorted, i));
1735 g_ptr_array_free (sorted, TRUE);
1737 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1738 num_freed ++;
1742 mono_domain_unlock (domain);
1745 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1748 * mono_class_vtable:
1749 * @domain: the application domain
1750 * @class: the class to initialize
1752 * VTables are domain specific because we create domain specific code, and
1753 * they contain the domain specific static class data.
1754 * On failure, NULL is returned, and class->exception_type is set.
1756 MonoVTable *
1757 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1759 MonoError error;
1760 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1761 mono_error_cleanup (&error);
1762 return vtable;
1766 * mono_class_vtable_full:
1767 * @domain: the application domain
1768 * @class: the class to initialize
1769 * @error set on failure.
1771 * VTables are domain specific because we create domain specific code, and
1772 * they contain the domain specific static class data.
1774 MonoVTable *
1775 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1777 MONO_REQ_GC_UNSAFE_MODE;
1779 MonoClassRuntimeInfo *runtime_info;
1781 mono_error_init (error);
1783 g_assert (klass);
1785 if (mono_class_has_failure (klass)) {
1786 mono_error_set_for_class_failure (error, klass);
1787 return NULL;
1790 /* this check can be inlined in jitted code, too */
1791 runtime_info = klass->runtime_info;
1792 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1793 return runtime_info->domain_vtables [domain->domain_id];
1794 return mono_class_create_runtime_vtable (domain, klass, error);
1798 * mono_class_try_get_vtable:
1799 * @domain: the application domain
1800 * @class: the class to initialize
1802 * This function tries to get the associated vtable from @class if
1803 * it was already created.
1805 MonoVTable *
1806 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1808 MONO_REQ_GC_NEUTRAL_MODE;
1810 MonoClassRuntimeInfo *runtime_info;
1812 g_assert (klass);
1814 runtime_info = klass->runtime_info;
1815 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1816 return runtime_info->domain_vtables [domain->domain_id];
1817 return NULL;
1820 static gpointer*
1821 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1823 MONO_REQ_GC_NEUTRAL_MODE;
1825 size_t alloc_offset;
1828 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1829 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1830 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1832 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1833 g_assert ((imt_table_bytes & 7) == 4);
1834 vtable_size += 4;
1835 alloc_offset = 4;
1836 } else {
1837 alloc_offset = 0;
1840 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1843 static MonoVTable *
1844 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1846 MONO_REQ_GC_UNSAFE_MODE;
1848 MonoVTable *vt;
1849 MonoClassRuntimeInfo *runtime_info, *old_info;
1850 MonoClassField *field;
1851 char *t;
1852 int i, vtable_slots;
1853 size_t imt_table_bytes;
1854 int gc_bits;
1855 guint32 vtable_size, class_size;
1856 gpointer iter;
1857 gpointer *interface_offsets;
1859 mono_error_init (error);
1861 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1862 mono_domain_lock (domain);
1863 runtime_info = klass->runtime_info;
1864 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1865 mono_domain_unlock (domain);
1866 mono_loader_unlock ();
1867 return runtime_info->domain_vtables [domain->domain_id];
1869 if (!klass->inited || mono_class_has_failure (klass)) {
1870 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1871 mono_domain_unlock (domain);
1872 mono_loader_unlock ();
1873 mono_error_set_for_class_failure (error, klass);
1874 return NULL;
1878 /* Array types require that their element type be valid*/
1879 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1880 MonoClass *element_class = klass->element_class;
1881 if (!element_class->inited)
1882 mono_class_init (element_class);
1884 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1885 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1886 mono_class_setup_vtable (element_class);
1888 if (mono_class_has_failure (element_class)) {
1889 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1890 if (!mono_class_has_failure (klass))
1891 mono_class_set_type_load_failure (klass, "");
1892 mono_domain_unlock (domain);
1893 mono_loader_unlock ();
1894 mono_error_set_for_class_failure (error, klass);
1895 return NULL;
1900 * For some classes, mono_class_init () already computed klass->vtable_size, and
1901 * that is all that is needed because of the vtable trampolines.
1903 if (!klass->vtable_size)
1904 mono_class_setup_vtable (klass);
1906 if (mono_class_is_ginst (klass) && !klass->vtable)
1907 mono_class_check_vtable_constraints (klass, NULL);
1909 /* Initialize klass->has_finalize */
1910 mono_class_has_finalizer (klass);
1912 if (mono_class_has_failure (klass)) {
1913 mono_domain_unlock (domain);
1914 mono_loader_unlock ();
1915 mono_error_set_for_class_failure (error, klass);
1916 return NULL;
1919 vtable_slots = klass->vtable_size;
1920 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1921 class_size = mono_class_data_size (klass);
1922 if (class_size)
1923 vtable_slots++;
1925 if (klass->interface_offsets_count) {
1926 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1927 mono_stats.imt_number_of_tables++;
1928 mono_stats.imt_tables_size += imt_table_bytes;
1929 } else {
1930 imt_table_bytes = 0;
1933 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1935 mono_stats.used_class_count++;
1936 mono_stats.class_vtable_size += vtable_size;
1938 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1939 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1940 g_assert (!((gsize)vt & 7));
1942 vt->klass = klass;
1943 vt->rank = klass->rank;
1944 vt->domain = domain;
1946 mono_class_compute_gc_descriptor (klass);
1948 * We can't use typed allocation in the non-root domains, since the
1949 * collector needs the GC descriptor stored in the vtable even after
1950 * the mempool containing the vtable is destroyed when the domain is
1951 * unloaded. An alternative might be to allocate vtables in the GC
1952 * heap, but this does not seem to work (it leads to crashes inside
1953 * libgc). If that approach is tried, two gc descriptors need to be
1954 * allocated for each class: one for the root domain, and one for all
1955 * other domains. The second descriptor should contain a bit for the
1956 * vtable field in MonoObject, since we can no longer assume the
1957 * vtable is reachable by other roots after the appdomain is unloaded.
1959 #ifdef HAVE_BOEHM_GC
1960 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1961 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1962 else
1963 #endif
1964 vt->gc_descr = klass->gc_descr;
1966 gc_bits = mono_gc_get_vtable_bits (klass);
1967 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1969 vt->gc_bits = gc_bits;
1971 if (class_size) {
1972 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1973 if (klass->has_static_refs) {
1974 MonoGCDescriptor statics_gc_descr;
1975 int max_set = 0;
1976 gsize default_bitmap [4] = {0};
1977 gsize *bitmap;
1979 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1980 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1981 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1982 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1983 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1984 if (bitmap != default_bitmap)
1985 g_free (bitmap);
1986 } else {
1987 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1989 vt->has_static_fields = TRUE;
1990 mono_stats.class_static_data_size += class_size;
1993 iter = NULL;
1994 while ((field = mono_class_get_fields (klass, &iter))) {
1995 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1996 continue;
1997 if (mono_field_is_deleted (field))
1998 continue;
1999 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2000 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2001 if (special_static != SPECIAL_STATIC_NONE) {
2002 guint32 size, offset;
2003 gint32 align;
2004 gsize default_bitmap [4] = {0};
2005 gsize *bitmap;
2006 int max_set = 0;
2007 int numbits;
2008 MonoClass *fclass;
2009 if (mono_type_is_reference (field->type)) {
2010 default_bitmap [0] = 1;
2011 numbits = 1;
2012 bitmap = default_bitmap;
2013 } else if (mono_type_is_struct (field->type)) {
2014 fclass = mono_class_from_mono_type (field->type);
2015 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2016 numbits = max_set + 1;
2017 } else {
2018 default_bitmap [0] = 0;
2019 numbits = 0;
2020 bitmap = default_bitmap;
2022 size = mono_type_size (field->type, &align);
2023 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2024 if (!domain->special_static_fields)
2025 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2026 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2027 if (bitmap != default_bitmap)
2028 g_free (bitmap);
2030 * This marks the field as special static to speed up the
2031 * checks in mono_field_static_get/set_value ().
2033 field->offset = -1;
2034 continue;
2037 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2038 MonoClass *fklass = mono_class_from_mono_type (field->type);
2039 const char *data = mono_field_get_data (field);
2041 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2042 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2043 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2044 if (!data)
2045 continue;
2046 if (fklass->valuetype) {
2047 memcpy (t, data, mono_class_value_size (fklass, NULL));
2048 } else {
2049 /* it's a pointer type: add check */
2050 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2051 *t = *(char *)data;
2053 continue;
2057 vt->max_interface_id = klass->max_interface_id;
2058 vt->interface_bitmap = klass->interface_bitmap;
2060 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2061 // class->name, klass->interface_offsets_count);
2063 /* Initialize vtable */
2064 if (callbacks.get_vtable_trampoline) {
2065 // This also covers the AOT case
2066 for (i = 0; i < klass->vtable_size; ++i) {
2067 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2069 } else {
2070 mono_class_setup_vtable (klass);
2072 for (i = 0; i < klass->vtable_size; ++i) {
2073 MonoMethod *cm;
2075 cm = klass->vtable [i];
2076 if (cm) {
2077 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2078 if (!is_ok (error)) {
2079 mono_domain_unlock (domain);
2080 mono_loader_unlock ();
2081 return NULL;
2087 if (imt_table_bytes) {
2088 /* Now that the vtable is full, we can actually fill up the IMT */
2089 for (i = 0; i < MONO_IMT_SIZE; ++i)
2090 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2094 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2095 * re-acquire them and check if another thread has created the vtable in the meantime.
2097 /* Special case System.MonoType to avoid infinite recursion */
2098 if (klass != mono_defaults.runtimetype_class) {
2099 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2100 if (!is_ok (error)) {
2101 mono_domain_unlock (domain);
2102 mono_loader_unlock ();
2103 return NULL;
2106 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2107 /* This is unregistered in
2108 unregister_vtable_reflection_type() in
2109 domain.c. */
2110 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2113 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2115 /* class_vtable_array keeps an array of created vtables
2117 g_ptr_array_add (domain->class_vtable_array, vt);
2118 /* klass->runtime_info is protected by the loader lock, both when
2119 * it it enlarged and when it is stored info.
2123 * Store the vtable in klass->runtime_info.
2124 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2126 mono_memory_barrier ();
2128 old_info = klass->runtime_info;
2129 if (old_info && old_info->max_domain >= domain->domain_id) {
2130 /* someone already created a large enough runtime info */
2131 old_info->domain_vtables [domain->domain_id] = vt;
2132 } else {
2133 int new_size = domain->domain_id;
2134 if (old_info)
2135 new_size = MAX (new_size, old_info->max_domain);
2136 new_size++;
2137 /* make the new size a power of two */
2138 i = 2;
2139 while (new_size > i)
2140 i <<= 1;
2141 new_size = i;
2142 /* this is a bounded memory retention issue: may want to
2143 * handle it differently when we'll have a rcu-like system.
2145 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2146 runtime_info->max_domain = new_size - 1;
2147 /* copy the stuff from the older info */
2148 if (old_info) {
2149 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2151 runtime_info->domain_vtables [domain->domain_id] = vt;
2152 /* keep this last*/
2153 mono_memory_barrier ();
2154 klass->runtime_info = runtime_info;
2157 if (klass == mono_defaults.runtimetype_class) {
2158 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2159 if (!is_ok (error)) {
2160 mono_domain_unlock (domain);
2161 mono_loader_unlock ();
2162 return NULL;
2165 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2166 /* This is unregistered in
2167 unregister_vtable_reflection_type() in
2168 domain.c. */
2169 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2172 mono_domain_unlock (domain);
2173 mono_loader_unlock ();
2175 /* make sure the parent is initialized */
2176 /*FIXME shouldn't this fail the current type?*/
2177 if (klass->parent)
2178 mono_class_vtable_full (domain, klass->parent, error);
2180 return vt;
2183 #ifndef DISABLE_REMOTING
2185 * mono_class_proxy_vtable:
2186 * @domain: the application domain
2187 * @remove_class: the remote class
2188 * @error: set on error
2190 * Creates a vtable for transparent proxies. It is basically
2191 * a copy of the real vtable of the class wrapped in @remote_class,
2192 * but all function pointers invoke the remoting functions, and
2193 * vtable->klass points to the transparent proxy class, and not to @class.
2195 * On failure returns NULL and sets @error
2197 static MonoVTable *
2198 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2200 MONO_REQ_GC_UNSAFE_MODE;
2202 MonoVTable *vt, *pvt;
2203 int i, j, vtsize, extra_interface_vtsize = 0;
2204 guint32 max_interface_id;
2205 MonoClass *k;
2206 GSList *extra_interfaces = NULL;
2207 MonoClass *klass = remote_class->proxy_class;
2208 gpointer *interface_offsets;
2209 uint8_t *bitmap = NULL;
2210 int bsize;
2211 size_t imt_table_bytes;
2213 #ifdef COMPRESSED_INTERFACE_BITMAP
2214 int bcsize;
2215 #endif
2217 mono_error_init (error);
2219 vt = mono_class_vtable (domain, klass);
2220 g_assert (vt); /*FIXME property handle failure*/
2221 max_interface_id = vt->max_interface_id;
2223 /* Calculate vtable space for extra interfaces */
2224 for (j = 0; j < remote_class->interface_count; j++) {
2225 MonoClass* iclass = remote_class->interfaces[j];
2226 GPtrArray *ifaces;
2227 int method_count;
2229 /*FIXME test for interfaces with variant generic arguments*/
2230 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2231 continue; /* interface implemented by the class */
2232 if (g_slist_find (extra_interfaces, iclass))
2233 continue;
2235 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2237 method_count = mono_class_num_methods (iclass);
2239 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2240 if (!is_ok (error))
2241 goto failure;
2242 if (ifaces) {
2243 for (i = 0; i < ifaces->len; ++i) {
2244 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2245 /*FIXME test for interfaces with variant generic arguments*/
2246 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2247 continue; /* interface implemented by the class */
2248 if (g_slist_find (extra_interfaces, ic))
2249 continue;
2250 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2251 method_count += mono_class_num_methods (ic);
2253 g_ptr_array_free (ifaces, TRUE);
2254 ifaces = NULL;
2257 extra_interface_vtsize += method_count * sizeof (gpointer);
2258 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2261 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2262 mono_stats.imt_number_of_tables++;
2263 mono_stats.imt_tables_size += imt_table_bytes;
2265 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2267 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2269 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2270 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2271 g_assert (!((gsize)pvt & 7));
2273 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2275 pvt->klass = mono_defaults.transparent_proxy_class;
2276 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2277 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2279 /* initialize vtable */
2280 mono_class_setup_vtable (klass);
2281 for (i = 0; i < klass->vtable_size; ++i) {
2282 MonoMethod *cm;
2284 if ((cm = klass->vtable [i])) {
2285 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2286 if (!is_ok (error))
2287 goto failure;
2288 } else
2289 pvt->vtable [i] = NULL;
2292 if (mono_class_is_abstract (klass)) {
2293 /* create trampolines for abstract methods */
2294 for (k = klass; k; k = k->parent) {
2295 MonoMethod* m;
2296 gpointer iter = NULL;
2297 while ((m = mono_class_get_methods (k, &iter)))
2298 if (!pvt->vtable [m->slot]) {
2299 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2300 if (!is_ok (error))
2301 goto failure;
2306 pvt->max_interface_id = max_interface_id;
2307 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2308 #ifdef COMPRESSED_INTERFACE_BITMAP
2309 bitmap = (uint8_t *)g_malloc0 (bsize);
2310 #else
2311 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2312 #endif
2314 for (i = 0; i < klass->interface_offsets_count; ++i) {
2315 int interface_id = klass->interfaces_packed [i]->interface_id;
2316 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2319 if (extra_interfaces) {
2320 int slot = klass->vtable_size;
2321 MonoClass* interf;
2322 gpointer iter;
2323 MonoMethod* cm;
2324 GSList *list_item;
2326 /* Create trampolines for the methods of the interfaces */
2327 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2328 interf = (MonoClass *)list_item->data;
2330 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2332 iter = NULL;
2333 j = 0;
2334 while ((cm = mono_class_get_methods (interf, &iter))) {
2335 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2336 if (!is_ok (error))
2337 goto failure;
2340 slot += mono_class_num_methods (interf);
2344 /* Now that the vtable is full, we can actually fill up the IMT */
2345 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2346 if (extra_interfaces) {
2347 g_slist_free (extra_interfaces);
2350 #ifdef COMPRESSED_INTERFACE_BITMAP
2351 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2352 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2353 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2354 g_free (bitmap);
2355 #else
2356 pvt->interface_bitmap = bitmap;
2357 #endif
2358 return pvt;
2359 failure:
2360 if (extra_interfaces)
2361 g_slist_free (extra_interfaces);
2362 #ifdef COMPRESSED_INTERFACE_BITMAP
2363 g_free (bitmap);
2364 #endif
2365 return NULL;
2368 #endif /* DISABLE_REMOTING */
2371 * mono_class_field_is_special_static:
2373 * Returns whether @field is a thread/context static field.
2375 gboolean
2376 mono_class_field_is_special_static (MonoClassField *field)
2378 MONO_REQ_GC_NEUTRAL_MODE
2380 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2381 return FALSE;
2382 if (mono_field_is_deleted (field))
2383 return FALSE;
2384 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2385 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2386 return TRUE;
2388 return FALSE;
2392 * mono_class_field_get_special_static_type:
2393 * @field: The MonoClassField describing the field.
2395 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2396 * SPECIAL_STATIC_NONE otherwise.
2398 guint32
2399 mono_class_field_get_special_static_type (MonoClassField *field)
2401 MONO_REQ_GC_NEUTRAL_MODE
2403 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2404 return SPECIAL_STATIC_NONE;
2405 if (mono_field_is_deleted (field))
2406 return SPECIAL_STATIC_NONE;
2407 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2408 return field_is_special_static (field->parent, field);
2409 return SPECIAL_STATIC_NONE;
2413 * mono_class_has_special_static_fields:
2415 * Returns whenever @klass has any thread/context static fields.
2417 gboolean
2418 mono_class_has_special_static_fields (MonoClass *klass)
2420 MONO_REQ_GC_NEUTRAL_MODE
2422 MonoClassField *field;
2423 gpointer iter;
2425 iter = NULL;
2426 while ((field = mono_class_get_fields (klass, &iter))) {
2427 g_assert (field->parent == klass);
2428 if (mono_class_field_is_special_static (field))
2429 return TRUE;
2432 return FALSE;
2435 #ifndef DISABLE_REMOTING
2437 * create_remote_class_key:
2438 * Creates an array of pointers that can be used as a hash key for a remote class.
2439 * The first element of the array is the number of pointers.
2441 static gpointer*
2442 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2444 MONO_REQ_GC_NEUTRAL_MODE;
2446 gpointer *key;
2447 int i, j;
2449 if (remote_class == NULL) {
2450 if (mono_class_is_interface (extra_class)) {
2451 key = (void **)g_malloc (sizeof(gpointer) * 3);
2452 key [0] = GINT_TO_POINTER (2);
2453 key [1] = mono_defaults.marshalbyrefobject_class;
2454 key [2] = extra_class;
2455 } else {
2456 key = (void **)g_malloc (sizeof(gpointer) * 2);
2457 key [0] = GINT_TO_POINTER (1);
2458 key [1] = extra_class;
2460 } else {
2461 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2462 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2463 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2464 key [1] = remote_class->proxy_class;
2466 // Keep the list of interfaces sorted
2467 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2468 if (extra_class && remote_class->interfaces [i] > extra_class) {
2469 key [j++] = extra_class;
2470 extra_class = NULL;
2472 key [j] = remote_class->interfaces [i];
2474 if (extra_class)
2475 key [j] = extra_class;
2476 } else {
2477 // Replace the old class. The interface list is the same
2478 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2479 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2480 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2481 for (i = 0; i < remote_class->interface_count; i++)
2482 key [2 + i] = remote_class->interfaces [i];
2486 return key;
2490 * copy_remote_class_key:
2492 * Make a copy of KEY in the domain and return the copy.
2494 static gpointer*
2495 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2497 MONO_REQ_GC_NEUTRAL_MODE
2499 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2500 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2502 memcpy (mp_key, key, key_size);
2504 return mp_key;
2508 * mono_remote_class:
2509 * @domain: the application domain
2510 * @class_name: name of the remote class
2511 * @error: set on error
2513 * Creates and initializes a MonoRemoteClass object for a remote type.
2515 * On failure returns NULL and sets @error
2517 MonoRemoteClass*
2518 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2520 MONO_REQ_GC_UNSAFE_MODE;
2522 MonoRemoteClass *rc;
2523 gpointer* key, *mp_key;
2524 char *name;
2526 mono_error_init (error);
2528 key = create_remote_class_key (NULL, proxy_class);
2530 mono_domain_lock (domain);
2531 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2533 if (rc) {
2534 g_free (key);
2535 mono_domain_unlock (domain);
2536 return rc;
2539 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2540 if (!is_ok (error)) {
2541 g_free (key);
2542 mono_domain_unlock (domain);
2543 return NULL;
2546 mp_key = copy_remote_class_key (domain, key);
2547 g_free (key);
2548 key = mp_key;
2550 if (mono_class_is_interface (proxy_class)) {
2551 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2552 rc->interface_count = 1;
2553 rc->interfaces [0] = proxy_class;
2554 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2555 } else {
2556 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2557 rc->interface_count = 0;
2558 rc->proxy_class = proxy_class;
2561 rc->default_vtable = NULL;
2562 rc->xdomain_vtable = NULL;
2563 rc->proxy_class_name = name;
2564 #ifndef DISABLE_PERFCOUNTERS
2565 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2566 #endif
2568 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2570 mono_domain_unlock (domain);
2571 return rc;
2575 * clone_remote_class:
2576 * Creates a copy of the remote_class, adding the provided class or interface
2578 static MonoRemoteClass*
2579 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2581 MONO_REQ_GC_NEUTRAL_MODE;
2583 MonoRemoteClass *rc;
2584 gpointer* key, *mp_key;
2586 key = create_remote_class_key (remote_class, extra_class);
2587 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2588 if (rc != NULL) {
2589 g_free (key);
2590 return rc;
2593 mp_key = copy_remote_class_key (domain, key);
2594 g_free (key);
2595 key = mp_key;
2597 if (mono_class_is_interface (extra_class)) {
2598 int i,j;
2599 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2600 rc->proxy_class = remote_class->proxy_class;
2601 rc->interface_count = remote_class->interface_count + 1;
2603 // Keep the list of interfaces sorted, since the hash key of
2604 // the remote class depends on this
2605 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2606 if (remote_class->interfaces [i] > extra_class && i == j)
2607 rc->interfaces [j++] = extra_class;
2608 rc->interfaces [j] = remote_class->interfaces [i];
2610 if (i == j)
2611 rc->interfaces [j] = extra_class;
2612 } else {
2613 // Replace the old class. The interface array is the same
2614 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2615 rc->proxy_class = extra_class;
2616 rc->interface_count = remote_class->interface_count;
2617 if (rc->interface_count > 0)
2618 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2621 rc->default_vtable = NULL;
2622 rc->xdomain_vtable = NULL;
2623 rc->proxy_class_name = remote_class->proxy_class_name;
2625 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2627 return rc;
2630 gpointer
2631 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2633 MONO_REQ_GC_UNSAFE_MODE;
2635 mono_error_init (error);
2637 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2638 mono_domain_lock (domain);
2639 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2640 if (target_domain_id != -1) {
2641 if (remote_class->xdomain_vtable == NULL)
2642 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2643 mono_domain_unlock (domain);
2644 mono_loader_unlock ();
2645 return_val_if_nok (error, NULL);
2646 return remote_class->xdomain_vtable;
2648 if (remote_class->default_vtable == NULL) {
2649 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2650 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2652 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2653 MonoClass *klass = mono_class_from_mono_type (type);
2654 #ifndef DISABLE_COM
2655 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)))
2656 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2657 else
2658 #endif
2659 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2660 /* N.B. both branches of the if modify error */
2661 if (!is_ok (error)) {
2662 mono_domain_unlock (domain);
2663 mono_loader_unlock ();
2664 return NULL;
2668 mono_domain_unlock (domain);
2669 mono_loader_unlock ();
2670 return remote_class->default_vtable;
2674 * mono_upgrade_remote_class:
2675 * @domain: the application domain
2676 * @tproxy: the proxy whose remote class has to be upgraded.
2677 * @klass: class to which the remote class can be casted.
2678 * @error: set on error
2680 * Updates the vtable of the remote class by adding the necessary method slots
2681 * and interface offsets so it can be safely casted to klass. klass can be a
2682 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2684 gboolean
2685 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2687 MONO_REQ_GC_UNSAFE_MODE;
2689 mono_error_init (error);
2691 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2692 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2694 gboolean redo_vtable;
2695 if (mono_class_is_interface (klass)) {
2696 int i;
2697 redo_vtable = TRUE;
2698 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2699 if (remote_class->interfaces [i] == klass)
2700 redo_vtable = FALSE;
2702 else {
2703 redo_vtable = (remote_class->proxy_class != klass);
2706 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2707 mono_domain_lock (domain);
2708 if (redo_vtable) {
2709 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2710 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2711 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2712 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2713 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2714 if (!is_ok (error))
2715 goto leave;
2718 leave:
2719 mono_domain_unlock (domain);
2720 mono_loader_unlock ();
2721 return is_ok (error);
2723 #endif /* DISABLE_REMOTING */
2727 * mono_object_get_virtual_method:
2728 * @obj: object to operate on.
2729 * @method: method
2731 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2732 * the instance of a callvirt of method.
2734 MonoMethod*
2735 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2737 MONO_REQ_GC_UNSAFE_MODE;
2738 HANDLE_FUNCTION_ENTER ();
2739 MonoError error;
2740 MONO_HANDLE_DCL (MonoObject, obj);
2741 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2742 mono_error_assert_ok (&error);
2743 HANDLE_FUNCTION_RETURN_VAL (result);
2747 * mono_object_get_virtual_method:
2748 * @obj: object to operate on.
2749 * @method: method
2751 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2752 * the instance of a callvirt of method.
2754 MonoMethod*
2755 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2757 mono_error_init (error);
2759 gboolean is_proxy = FALSE;
2760 MonoClass *klass = mono_handle_class (obj);
2761 if (mono_class_is_transparent_proxy (klass)) {
2762 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2763 klass = remote_class->proxy_class;
2764 is_proxy = TRUE;
2766 return class_get_virtual_method (klass, method, is_proxy, error);
2769 static MonoMethod*
2770 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2772 mono_error_init (error);
2775 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2776 return method;
2778 mono_class_setup_vtable (klass);
2779 MonoMethod **vtable = klass->vtable;
2781 if (method->slot == -1) {
2782 /* method->slot might not be set for instances of generic methods */
2783 if (method->is_inflated) {
2784 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2785 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2786 } else {
2787 if (!is_proxy)
2788 g_assert_not_reached ();
2792 MonoMethod *res = NULL;
2793 /* check method->slot is a valid index: perform isinstance? */
2794 if (method->slot != -1) {
2795 if (mono_class_is_interface (method->klass)) {
2796 if (!is_proxy) {
2797 gboolean variance_used = FALSE;
2798 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2799 g_assert (iface_offset > 0);
2800 res = vtable [iface_offset + method->slot];
2802 } else {
2803 res = vtable [method->slot];
2807 #ifndef DISABLE_REMOTING
2808 if (is_proxy) {
2809 /* It may be an interface, abstract class method or generic method */
2810 if (!res || mono_method_signature (res)->generic_param_count)
2811 res = method;
2813 /* generic methods demand invoke_with_check */
2814 if (mono_method_signature (res)->generic_param_count)
2815 res = mono_marshal_get_remoting_invoke_with_check (res);
2816 else {
2817 #ifndef DISABLE_COM
2818 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2819 res = mono_cominterop_get_invoke (res);
2820 else
2821 #endif
2822 res = mono_marshal_get_remoting_invoke (res);
2824 } else
2825 #endif
2827 if (method->is_inflated) {
2828 /* Have to inflate the result */
2829 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2833 return res;
2836 static MonoObject*
2837 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2839 MONO_REQ_GC_UNSAFE_MODE;
2841 MonoObject *result = NULL;
2843 g_assert (callbacks.runtime_invoke);
2845 mono_error_init (error);
2847 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2848 mono_profiler_method_start_invoke (method);
2850 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2852 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2853 mono_profiler_method_end_invoke (method);
2855 if (!mono_error_ok (error))
2856 return NULL;
2858 return result;
2862 * mono_runtime_invoke:
2863 * @method: method to invoke
2864 * @obJ: object instance
2865 * @params: arguments to the method
2866 * @exc: exception information.
2868 * Invokes the method represented by @method on the object @obj.
2870 * obj is the 'this' pointer, it should be NULL for static
2871 * methods, a MonoObject* for object instances and a pointer to
2872 * the value type for value types.
2874 * The params array contains the arguments to the method with the
2875 * same convention: MonoObject* pointers for object instances and
2876 * pointers to the value type otherwise.
2878 * From unmanaged code you'll usually use the
2879 * mono_runtime_invoke() variant.
2881 * Note that this function doesn't handle virtual methods for
2882 * you, it will exec the exact method you pass: we still need to
2883 * expose a function to lookup the derived class implementation
2884 * of a virtual method (there are examples of this in the code,
2885 * though).
2887 * You can pass NULL as the exc argument if you don't want to
2888 * catch exceptions, otherwise, *exc will be set to the exception
2889 * thrown, if any. if an exception is thrown, you can't use the
2890 * MonoObject* result from the function.
2892 * If the method returns a value type, it is boxed in an object
2893 * reference.
2895 MonoObject*
2896 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2898 MonoError error;
2899 MonoObject *res;
2900 if (exc) {
2901 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2902 if (*exc == NULL && !mono_error_ok(&error)) {
2903 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2904 } else
2905 mono_error_cleanup (&error);
2906 } else {
2907 res = mono_runtime_invoke_checked (method, obj, params, &error);
2908 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2910 return res;
2914 * mono_runtime_try_invoke:
2915 * @method: method to invoke
2916 * @obJ: object instance
2917 * @params: arguments to the method
2918 * @exc: exception information.
2919 * @error: set on error
2921 * Invokes the method represented by @method on the object @obj.
2923 * obj is the 'this' pointer, it should be NULL for static
2924 * methods, a MonoObject* for object instances and a pointer to
2925 * the value type for value types.
2927 * The params array contains the arguments to the method with the
2928 * same convention: MonoObject* pointers for object instances and
2929 * pointers to the value type otherwise.
2931 * From unmanaged code you'll usually use the
2932 * mono_runtime_invoke() variant.
2934 * Note that this function doesn't handle virtual methods for
2935 * you, it will exec the exact method you pass: we still need to
2936 * expose a function to lookup the derived class implementation
2937 * of a virtual method (there are examples of this in the code,
2938 * though).
2940 * For this function, you must not pass NULL as the exc argument if
2941 * you don't want to catch exceptions, use
2942 * mono_runtime_invoke_checked(). If an exception is thrown, you
2943 * can't use the MonoObject* result from the function.
2945 * If this method cannot be invoked, @error will be set and @exc and
2946 * the return value must not be used.
2948 * If the method returns a value type, it is boxed in an object
2949 * reference.
2951 MonoObject*
2952 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2954 MONO_REQ_GC_UNSAFE_MODE;
2956 g_assert (exc != NULL);
2958 if (mono_runtime_get_no_exec ())
2959 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2961 return do_runtime_invoke (method, obj, params, exc, error);
2965 * mono_runtime_invoke_checked:
2966 * @method: method to invoke
2967 * @obJ: object instance
2968 * @params: arguments to the method
2969 * @error: set on error
2971 * Invokes the method represented by @method on the object @obj.
2973 * obj is the 'this' pointer, it should be NULL for static
2974 * methods, a MonoObject* for object instances and a pointer to
2975 * the value type for value types.
2977 * The params array contains the arguments to the method with the
2978 * same convention: MonoObject* pointers for object instances and
2979 * pointers to the value type otherwise.
2981 * From unmanaged code you'll usually use the
2982 * mono_runtime_invoke() variant.
2984 * Note that this function doesn't handle virtual methods for
2985 * you, it will exec the exact method you pass: we still need to
2986 * expose a function to lookup the derived class implementation
2987 * of a virtual method (there are examples of this in the code,
2988 * though).
2990 * If an exception is thrown, you can't use the MonoObject* result
2991 * from the function.
2993 * If this method cannot be invoked, @error will be set. If the
2994 * method throws an exception (and we're in coop mode) the exception
2995 * will be set in @error.
2997 * If the method returns a value type, it is boxed in an object
2998 * reference.
3000 MonoObject*
3001 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3003 MONO_REQ_GC_UNSAFE_MODE;
3005 if (mono_runtime_get_no_exec ())
3006 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3008 return do_runtime_invoke (method, obj, params, NULL, error);
3012 * mono_method_get_unmanaged_thunk:
3013 * @method: method to generate a thunk for.
3015 * Returns an unmanaged->managed thunk that can be used to call
3016 * a managed method directly from C.
3018 * The thunk's C signature closely matches the managed signature:
3020 * C#: public bool Equals (object obj);
3021 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3022 * MonoObject*, MonoException**);
3024 * The 1st ("this") parameter must not be used with static methods:
3026 * C#: public static bool ReferenceEquals (object a, object b);
3027 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3028 * MonoException**);
3030 * The last argument must be a non-null pointer of a MonoException* pointer.
3031 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3032 * exception has been thrown in managed code. Otherwise it will point
3033 * to the MonoException* caught by the thunk. In this case, the result of
3034 * the thunk is undefined:
3036 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3037 * MonoException *ex = NULL;
3038 * Equals func = mono_method_get_unmanaged_thunk (method);
3039 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3040 * if (ex) {
3041 * // handle exception
3044 * The calling convention of the thunk matches the platform's default
3045 * convention. This means that under Windows, C declarations must
3046 * contain the __stdcall attribute:
3048 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3049 * MonoObject*, MonoException**);
3051 * LIMITATIONS
3053 * Value type arguments and return values are treated as they were objects:
3055 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3056 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3058 * Arguments must be properly boxed upon trunk's invocation, while return
3059 * values must be unboxed.
3061 gpointer
3062 mono_method_get_unmanaged_thunk (MonoMethod *method)
3064 MONO_REQ_GC_NEUTRAL_MODE;
3065 MONO_REQ_API_ENTRYPOINT;
3067 MonoError error;
3068 gpointer res;
3070 g_assert (!mono_threads_is_coop_enabled ());
3072 MONO_ENTER_GC_UNSAFE;
3073 method = mono_marshal_get_thunk_invoke_wrapper (method);
3074 res = mono_compile_method_checked (method, &error);
3075 mono_error_cleanup (&error);
3076 MONO_EXIT_GC_UNSAFE;
3078 return res;
3081 void
3082 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3084 MONO_REQ_GC_UNSAFE_MODE;
3086 int t;
3087 if (type->byref) {
3088 /* object fields cannot be byref, so we don't need a
3089 wbarrier here */
3090 gpointer *p = (gpointer*)dest;
3091 *p = value;
3092 return;
3094 t = type->type;
3095 handle_enum:
3096 switch (t) {
3097 case MONO_TYPE_BOOLEAN:
3098 case MONO_TYPE_I1:
3099 case MONO_TYPE_U1: {
3100 guint8 *p = (guint8*)dest;
3101 *p = value ? *(guint8*)value : 0;
3102 return;
3104 case MONO_TYPE_I2:
3105 case MONO_TYPE_U2:
3106 case MONO_TYPE_CHAR: {
3107 guint16 *p = (guint16*)dest;
3108 *p = value ? *(guint16*)value : 0;
3109 return;
3111 #if SIZEOF_VOID_P == 4
3112 case MONO_TYPE_I:
3113 case MONO_TYPE_U:
3114 #endif
3115 case MONO_TYPE_I4:
3116 case MONO_TYPE_U4: {
3117 gint32 *p = (gint32*)dest;
3118 *p = value ? *(gint32*)value : 0;
3119 return;
3121 #if SIZEOF_VOID_P == 8
3122 case MONO_TYPE_I:
3123 case MONO_TYPE_U:
3124 #endif
3125 case MONO_TYPE_I8:
3126 case MONO_TYPE_U8: {
3127 gint64 *p = (gint64*)dest;
3128 *p = value ? *(gint64*)value : 0;
3129 return;
3131 case MONO_TYPE_R4: {
3132 float *p = (float*)dest;
3133 *p = value ? *(float*)value : 0;
3134 return;
3136 case MONO_TYPE_R8: {
3137 double *p = (double*)dest;
3138 *p = value ? *(double*)value : 0;
3139 return;
3141 case MONO_TYPE_STRING:
3142 case MONO_TYPE_SZARRAY:
3143 case MONO_TYPE_CLASS:
3144 case MONO_TYPE_OBJECT:
3145 case MONO_TYPE_ARRAY:
3146 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3147 return;
3148 case MONO_TYPE_FNPTR:
3149 case MONO_TYPE_PTR: {
3150 gpointer *p = (gpointer*)dest;
3151 *p = deref_pointer? *(gpointer*)value: value;
3152 return;
3154 case MONO_TYPE_VALUETYPE:
3155 /* note that 't' and 'type->type' can be different */
3156 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3157 t = mono_class_enum_basetype (type->data.klass)->type;
3158 goto handle_enum;
3159 } else {
3160 MonoClass *klass = mono_class_from_mono_type (type);
3161 int size = mono_class_value_size (klass, NULL);
3162 if (value == NULL)
3163 mono_gc_bzero_atomic (dest, size);
3164 else
3165 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3167 return;
3168 case MONO_TYPE_GENERICINST:
3169 t = type->data.generic_class->container_class->byval_arg.type;
3170 goto handle_enum;
3171 default:
3172 g_error ("got type %x", type->type);
3177 * mono_field_set_value:
3178 * @obj: Instance object
3179 * @field: MonoClassField describing the field to set
3180 * @value: The value to be set
3182 * Sets the value of the field described by @field in the object instance @obj
3183 * to the value passed in @value. This method should only be used for instance
3184 * fields. For static fields, use mono_field_static_set_value.
3186 * The value must be on the native format of the field type.
3188 void
3189 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3191 MONO_REQ_GC_UNSAFE_MODE;
3193 void *dest;
3195 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3197 dest = (char*)obj + field->offset;
3198 mono_copy_value (field->type, dest, value, FALSE);
3202 * mono_field_static_set_value:
3203 * @field: MonoClassField describing the field to set
3204 * @value: The value to be set
3206 * Sets the value of the static field described by @field
3207 * to the value passed in @value.
3209 * The value must be on the native format of the field type.
3211 void
3212 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3214 MONO_REQ_GC_UNSAFE_MODE;
3216 void *dest;
3218 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3219 /* you cant set a constant! */
3220 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3222 if (field->offset == -1) {
3223 /* Special static */
3224 gpointer addr;
3226 mono_domain_lock (vt->domain);
3227 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3228 mono_domain_unlock (vt->domain);
3229 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3230 } else {
3231 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3233 mono_copy_value (field->type, dest, value, FALSE);
3237 * mono_vtable_get_static_field_data:
3239 * Internal use function: return a pointer to the memory holding the static fields
3240 * for a class or NULL if there are no static fields.
3241 * This is exported only for use by the debugger.
3243 void *
3244 mono_vtable_get_static_field_data (MonoVTable *vt)
3246 MONO_REQ_GC_NEUTRAL_MODE
3248 if (!vt->has_static_fields)
3249 return NULL;
3250 return vt->vtable [vt->klass->vtable_size];
3253 static guint8*
3254 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3256 MONO_REQ_GC_UNSAFE_MODE;
3258 guint8 *src;
3260 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3261 if (field->offset == -1) {
3262 /* Special static */
3263 gpointer addr;
3265 mono_domain_lock (vt->domain);
3266 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3267 mono_domain_unlock (vt->domain);
3268 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3269 } else {
3270 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3272 } else {
3273 src = (guint8*)obj + field->offset;
3276 return src;
3280 * mono_field_get_value:
3281 * @obj: Object instance
3282 * @field: MonoClassField describing the field to fetch information from
3283 * @value: pointer to the location where the value will be stored
3285 * Use this routine to get the value of the field @field in the object
3286 * passed.
3288 * The pointer provided by value must be of the field type, for reference
3289 * types this is a MonoObject*, for value types its the actual pointer to
3290 * the value type.
3292 * For example:
3293 * int i;
3294 * mono_field_get_value (obj, int_field, &i);
3296 void
3297 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3299 MONO_REQ_GC_UNSAFE_MODE;
3301 void *src;
3303 g_assert (obj);
3305 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3307 src = (char*)obj + field->offset;
3308 mono_copy_value (field->type, value, src, TRUE);
3312 * mono_field_get_value_object:
3313 * @domain: domain where the object will be created (if boxing)
3314 * @field: MonoClassField describing the field to fetch information from
3315 * @obj: The object instance for the field.
3317 * Returns: a new MonoObject with the value from the given field. If the
3318 * field represents a value type, the value is boxed.
3321 MonoObject *
3322 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3324 MonoError error;
3325 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3326 mono_error_assert_ok (&error);
3327 return result;
3331 * mono_field_get_value_object_checked:
3332 * @domain: domain where the object will be created (if boxing)
3333 * @field: MonoClassField describing the field to fetch information from
3334 * @obj: The object instance for the field.
3335 * @error: Set on error.
3337 * Returns: a new MonoObject with the value from the given field. If the
3338 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3341 MonoObject *
3342 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3344 MONO_REQ_GC_UNSAFE_MODE;
3346 mono_error_init (error);
3348 MonoObject *o;
3349 MonoClass *klass;
3350 MonoVTable *vtable = NULL;
3351 gchar *v;
3352 gboolean is_static = FALSE;
3353 gboolean is_ref = FALSE;
3354 gboolean is_literal = FALSE;
3355 gboolean is_ptr = FALSE;
3356 MonoType *type = mono_field_get_type_checked (field, error);
3358 return_val_if_nok (error, NULL);
3360 switch (type->type) {
3361 case MONO_TYPE_STRING:
3362 case MONO_TYPE_OBJECT:
3363 case MONO_TYPE_CLASS:
3364 case MONO_TYPE_ARRAY:
3365 case MONO_TYPE_SZARRAY:
3366 is_ref = TRUE;
3367 break;
3368 case MONO_TYPE_U1:
3369 case MONO_TYPE_I1:
3370 case MONO_TYPE_BOOLEAN:
3371 case MONO_TYPE_U2:
3372 case MONO_TYPE_I2:
3373 case MONO_TYPE_CHAR:
3374 case MONO_TYPE_U:
3375 case MONO_TYPE_I:
3376 case MONO_TYPE_U4:
3377 case MONO_TYPE_I4:
3378 case MONO_TYPE_R4:
3379 case MONO_TYPE_U8:
3380 case MONO_TYPE_I8:
3381 case MONO_TYPE_R8:
3382 case MONO_TYPE_VALUETYPE:
3383 is_ref = type->byref;
3384 break;
3385 case MONO_TYPE_GENERICINST:
3386 is_ref = !mono_type_generic_inst_is_valuetype (type);
3387 break;
3388 case MONO_TYPE_PTR:
3389 is_ptr = TRUE;
3390 break;
3391 default:
3392 g_error ("type 0x%x not handled in "
3393 "mono_field_get_value_object", type->type);
3394 return NULL;
3397 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3398 is_literal = TRUE;
3400 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3401 is_static = TRUE;
3403 if (!is_literal) {
3404 vtable = mono_class_vtable_full (domain, field->parent, error);
3405 return_val_if_nok (error, NULL);
3407 if (!vtable->initialized) {
3408 mono_runtime_class_init_full (vtable, error);
3409 return_val_if_nok (error, NULL);
3412 } else {
3413 g_assert (obj);
3416 if (is_ref) {
3417 if (is_literal) {
3418 get_default_field_value (domain, field, &o, error);
3419 return_val_if_nok (error, NULL);
3420 } else if (is_static) {
3421 mono_field_static_get_value_checked (vtable, field, &o, error);
3422 return_val_if_nok (error, NULL);
3423 } else {
3424 mono_field_get_value (obj, field, &o);
3426 return o;
3429 if (is_ptr) {
3430 static MonoMethod *m;
3431 gpointer args [2];
3432 gpointer *ptr;
3433 gpointer v;
3435 if (!m) {
3436 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3437 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3438 g_assert (m);
3441 v = &ptr;
3442 if (is_literal) {
3443 get_default_field_value (domain, field, v, error);
3444 return_val_if_nok (error, NULL);
3445 } else if (is_static) {
3446 mono_field_static_get_value_checked (vtable, field, v, error);
3447 return_val_if_nok (error, NULL);
3448 } else {
3449 mono_field_get_value (obj, field, v);
3452 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3453 args [0] = ptr ? *ptr : NULL;
3454 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3455 return_val_if_nok (error, NULL);
3457 o = mono_runtime_invoke_checked (m, NULL, args, error);
3458 return_val_if_nok (error, NULL);
3460 return o;
3463 /* boxed value type */
3464 klass = mono_class_from_mono_type (type);
3466 if (mono_class_is_nullable (klass))
3467 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3469 o = mono_object_new_checked (domain, klass, error);
3470 return_val_if_nok (error, NULL);
3471 v = ((gchar *) o) + sizeof (MonoObject);
3473 if (is_literal) {
3474 get_default_field_value (domain, field, v, error);
3475 return_val_if_nok (error, NULL);
3476 } else if (is_static) {
3477 mono_field_static_get_value_checked (vtable, field, v, error);
3478 return_val_if_nok (error, NULL);
3479 } else {
3480 mono_field_get_value (obj, field, v);
3483 return o;
3487 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3489 MONO_REQ_GC_UNSAFE_MODE;
3491 mono_error_init (error);
3492 int retval = 0;
3493 const char *p = blob;
3494 mono_metadata_decode_blob_size (p, &p);
3496 switch (type) {
3497 case MONO_TYPE_BOOLEAN:
3498 case MONO_TYPE_U1:
3499 case MONO_TYPE_I1:
3500 *(guint8 *) value = *p;
3501 break;
3502 case MONO_TYPE_CHAR:
3503 case MONO_TYPE_U2:
3504 case MONO_TYPE_I2:
3505 *(guint16*) value = read16 (p);
3506 break;
3507 case MONO_TYPE_U4:
3508 case MONO_TYPE_I4:
3509 *(guint32*) value = read32 (p);
3510 break;
3511 case MONO_TYPE_U8:
3512 case MONO_TYPE_I8:
3513 *(guint64*) value = read64 (p);
3514 break;
3515 case MONO_TYPE_R4:
3516 readr4 (p, (float*) value);
3517 break;
3518 case MONO_TYPE_R8:
3519 readr8 (p, (double*) value);
3520 break;
3521 case MONO_TYPE_STRING:
3522 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3523 break;
3524 case MONO_TYPE_CLASS:
3525 *(gpointer*) value = NULL;
3526 break;
3527 default:
3528 retval = -1;
3529 g_warning ("type 0x%02x should not be in constant table", type);
3531 return retval;
3534 static void
3535 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3537 MONO_REQ_GC_NEUTRAL_MODE;
3539 MonoTypeEnum def_type;
3540 const char* data;
3542 mono_error_init (error);
3544 data = mono_class_get_field_default_value (field, &def_type);
3545 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3548 void
3549 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3551 MONO_REQ_GC_UNSAFE_MODE;
3553 void *src;
3555 mono_error_init (error);
3557 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3559 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3560 get_default_field_value (vt->domain, field, value, error);
3561 return;
3564 if (field->offset == -1) {
3565 /* Special static */
3566 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3567 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3568 } else {
3569 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3571 mono_copy_value (field->type, value, src, TRUE);
3575 * mono_field_static_get_value:
3576 * @vt: vtable to the object
3577 * @field: MonoClassField describing the field to fetch information from
3578 * @value: where the value is returned
3580 * Use this routine to get the value of the static field @field value.
3582 * The pointer provided by value must be of the field type, for reference
3583 * types this is a MonoObject*, for value types its the actual pointer to
3584 * the value type.
3586 * For example:
3587 * int i;
3588 * mono_field_static_get_value (vt, int_field, &i);
3590 void
3591 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3593 MONO_REQ_GC_NEUTRAL_MODE;
3595 MonoError error;
3596 mono_field_static_get_value_checked (vt, field, value, &error);
3597 mono_error_cleanup (&error);
3601 * mono_field_static_get_value_checked:
3602 * @vt: vtable to the object
3603 * @field: MonoClassField describing the field to fetch information from
3604 * @value: where the value is returned
3605 * @error: set on error
3607 * Use this routine to get the value of the static field @field value.
3609 * The pointer provided by value must be of the field type, for reference
3610 * types this is a MonoObject*, for value types its the actual pointer to
3611 * the value type.
3613 * For example:
3614 * int i;
3615 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3616 * if (!is_ok (error)) { ... }
3618 * On failure sets @error.
3620 void
3621 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3623 MONO_REQ_GC_NEUTRAL_MODE;
3625 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3629 * mono_property_set_value:
3630 * @prop: MonoProperty to set
3631 * @obj: instance object on which to act
3632 * @params: parameters to pass to the propery
3633 * @exc: optional exception
3635 * Invokes the property's set method with the given arguments on the
3636 * object instance obj (or NULL for static properties).
3638 * You can pass NULL as the exc argument if you don't want to
3639 * catch exceptions, otherwise, *exc will be set to the exception
3640 * thrown, if any. if an exception is thrown, you can't use the
3641 * MonoObject* result from the function.
3643 void
3644 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3646 MONO_REQ_GC_UNSAFE_MODE;
3648 MonoError error;
3649 do_runtime_invoke (prop->set, obj, params, exc, &error);
3650 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3651 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3652 } else {
3653 mono_error_cleanup (&error);
3658 * mono_property_set_value_checked:
3659 * @prop: MonoProperty to set
3660 * @obj: instance object on which to act
3661 * @params: parameters to pass to the propery
3662 * @error: set on error
3664 * Invokes the property's set method with the given arguments on the
3665 * object instance obj (or NULL for static properties).
3667 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3668 * If an exception is thrown, it will be caught and returned via @error.
3670 gboolean
3671 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3673 MONO_REQ_GC_UNSAFE_MODE;
3675 MonoObject *exc;
3677 mono_error_init (error);
3678 do_runtime_invoke (prop->set, obj, params, &exc, error);
3679 if (exc != NULL && is_ok (error))
3680 mono_error_set_exception_instance (error, (MonoException*)exc);
3681 return is_ok (error);
3685 * mono_property_get_value:
3686 * @prop: MonoProperty to fetch
3687 * @obj: instance object on which to act
3688 * @params: parameters to pass to the propery
3689 * @exc: optional exception
3691 * Invokes the property's get method with the given arguments on the
3692 * object instance obj (or NULL for static properties).
3694 * You can pass NULL as the exc argument if you don't want to
3695 * catch exceptions, otherwise, *exc will be set to the exception
3696 * thrown, if any. if an exception is thrown, you can't use the
3697 * MonoObject* result from the function.
3699 * Returns: the value from invoking the get method on the property.
3701 MonoObject*
3702 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3704 MONO_REQ_GC_UNSAFE_MODE;
3706 MonoError error;
3707 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3708 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3709 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3710 } else {
3711 mono_error_cleanup (&error); /* FIXME don't raise here */
3714 return val;
3718 * mono_property_get_value_checked:
3719 * @prop: MonoProperty to fetch
3720 * @obj: instance object on which to act
3721 * @params: parameters to pass to the propery
3722 * @error: set on error
3724 * Invokes the property's get method with the given arguments on the
3725 * object instance obj (or NULL for static properties).
3727 * If an exception is thrown, you can't use the
3728 * MonoObject* result from the function. The exception will be propagated via @error.
3730 * Returns: the value from invoking the get method on the property. On
3731 * failure returns NULL and sets @error.
3733 MonoObject*
3734 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3736 MONO_REQ_GC_UNSAFE_MODE;
3738 MonoObject *exc;
3739 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3740 if (exc != NULL && !is_ok (error))
3741 mono_error_set_exception_instance (error, (MonoException*) exc);
3742 if (!is_ok (error))
3743 val = NULL;
3744 return val;
3749 * mono_nullable_init:
3750 * @buf: The nullable structure to initialize.
3751 * @value: the value to initialize from
3752 * @klass: the type for the object
3754 * Initialize the nullable structure pointed to by @buf from @value which
3755 * should be a boxed value type. The size of @buf should be able to hold
3756 * as much data as the @klass->instance_size (which is the number of bytes
3757 * that will be copies).
3759 * Since Nullables have variable structure, we can not define a C
3760 * structure for them.
3762 void
3763 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3765 MONO_REQ_GC_UNSAFE_MODE;
3767 MonoClass *param_class = klass->cast_class;
3769 mono_class_setup_fields (klass);
3770 g_assert (klass->fields_inited);
3772 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3773 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3775 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3776 if (value) {
3777 if (param_class->has_references)
3778 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3779 else
3780 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3781 } else {
3782 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3787 * mono_nullable_box:
3788 * @buf: The buffer representing the data to be boxed
3789 * @klass: the type to box it as.
3790 * @error: set on oerr
3792 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3793 * @buf. On failure returns NULL and sets @error
3795 MonoObject*
3796 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3798 MONO_REQ_GC_UNSAFE_MODE;
3800 mono_error_init (error);
3801 MonoClass *param_class = klass->cast_class;
3803 mono_class_setup_fields (klass);
3804 g_assert (klass->fields_inited);
3806 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3807 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3809 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3810 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3811 return_val_if_nok (error, NULL);
3812 if (param_class->has_references)
3813 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3814 else
3815 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3816 return o;
3818 else
3819 return NULL;
3823 * mono_get_delegate_invoke:
3824 * @klass: The delegate class
3826 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3828 MonoMethod *
3829 mono_get_delegate_invoke (MonoClass *klass)
3831 MONO_REQ_GC_NEUTRAL_MODE;
3833 MonoMethod *im;
3835 /* This is called at runtime, so avoid the slower search in metadata */
3836 mono_class_setup_methods (klass);
3837 if (mono_class_has_failure (klass))
3838 return NULL;
3839 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3840 return im;
3844 * mono_get_delegate_begin_invoke:
3845 * @klass: The delegate class
3847 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3849 MonoMethod *
3850 mono_get_delegate_begin_invoke (MonoClass *klass)
3852 MONO_REQ_GC_NEUTRAL_MODE;
3854 MonoMethod *im;
3856 /* This is called at runtime, so avoid the slower search in metadata */
3857 mono_class_setup_methods (klass);
3858 if (mono_class_has_failure (klass))
3859 return NULL;
3860 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3861 return im;
3865 * mono_get_delegate_end_invoke:
3866 * @klass: The delegate class
3868 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3870 MonoMethod *
3871 mono_get_delegate_end_invoke (MonoClass *klass)
3873 MONO_REQ_GC_NEUTRAL_MODE;
3875 MonoMethod *im;
3877 /* This is called at runtime, so avoid the slower search in metadata */
3878 mono_class_setup_methods (klass);
3879 if (mono_class_has_failure (klass))
3880 return NULL;
3881 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3882 return im;
3886 * mono_runtime_delegate_invoke:
3887 * @delegate: pointer to a delegate object.
3888 * @params: parameters for the delegate.
3889 * @exc: Pointer to the exception result.
3891 * Invokes the delegate method @delegate with the parameters provided.
3893 * You can pass NULL as the exc argument if you don't want to
3894 * catch exceptions, otherwise, *exc will be set to the exception
3895 * thrown, if any. if an exception is thrown, you can't use the
3896 * MonoObject* result from the function.
3898 MonoObject*
3899 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3901 MONO_REQ_GC_UNSAFE_MODE;
3903 MonoError error;
3904 if (exc) {
3905 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3906 if (*exc) {
3907 mono_error_cleanup (&error);
3908 return NULL;
3909 } else {
3910 if (!is_ok (&error))
3911 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3912 return result;
3914 } else {
3915 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3916 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3917 return result;
3922 * mono_runtime_delegate_try_invoke:
3923 * @delegate: pointer to a delegate object.
3924 * @params: parameters for the delegate.
3925 * @exc: Pointer to the exception result.
3926 * @error: set on error
3928 * Invokes the delegate method @delegate with the parameters provided.
3930 * You can pass NULL as the exc argument if you don't want to
3931 * catch exceptions, otherwise, *exc will be set to the exception
3932 * thrown, if any. On failure to execute, @error will be set.
3933 * if an exception is thrown, you can't use the
3934 * MonoObject* result from the function.
3936 MonoObject*
3937 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3939 MONO_REQ_GC_UNSAFE_MODE;
3941 mono_error_init (error);
3942 MonoMethod *im;
3943 MonoClass *klass = delegate->vtable->klass;
3944 MonoObject *o;
3946 im = mono_get_delegate_invoke (klass);
3947 if (!im)
3948 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3950 if (exc) {
3951 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3952 } else {
3953 o = mono_runtime_invoke_checked (im, delegate, params, error);
3956 return o;
3960 * mono_runtime_delegate_invoke_checked:
3961 * @delegate: pointer to a delegate object.
3962 * @params: parameters for the delegate.
3963 * @error: set on error
3965 * Invokes the delegate method @delegate with the parameters provided.
3967 * On failure @error will be set and you can't use the MonoObject*
3968 * result from the function.
3970 MonoObject*
3971 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3973 mono_error_init (error);
3974 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3977 static char **main_args = NULL;
3978 static int num_main_args = 0;
3981 * mono_runtime_get_main_args:
3983 * Returns: a MonoArray with the arguments passed to the main program
3985 MonoArray*
3986 mono_runtime_get_main_args (void)
3988 MONO_REQ_GC_UNSAFE_MODE;
3989 MonoError error;
3990 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3991 mono_error_assert_ok (&error);
3992 return result;
3996 * mono_runtime_get_main_args:
3997 * @error: set on error
3999 * Returns: a MonoArray with the arguments passed to the main
4000 * program. On failure returns NULL and sets @error.
4002 MonoArray*
4003 mono_runtime_get_main_args_checked (MonoError *error)
4005 MonoArray *res;
4006 int i;
4007 MonoDomain *domain = mono_domain_get ();
4009 mono_error_init (error);
4011 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4012 return_val_if_nok (error, NULL);
4014 for (i = 0; i < num_main_args; ++i)
4015 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4017 return res;
4020 static void
4021 free_main_args (void)
4023 MONO_REQ_GC_NEUTRAL_MODE;
4025 int i;
4027 for (i = 0; i < num_main_args; ++i)
4028 g_free (main_args [i]);
4029 g_free (main_args);
4030 num_main_args = 0;
4031 main_args = NULL;
4035 * mono_runtime_set_main_args:
4036 * @argc: number of arguments from the command line
4037 * @argv: array of strings from the command line
4039 * Set the command line arguments from an embedding application that doesn't otherwise call
4040 * mono_runtime_run_main ().
4043 mono_runtime_set_main_args (int argc, char* argv[])
4045 MONO_REQ_GC_NEUTRAL_MODE;
4047 int i;
4049 free_main_args ();
4050 main_args = g_new0 (char*, argc);
4051 num_main_args = argc;
4053 for (i = 0; i < argc; ++i) {
4054 gchar *utf8_arg;
4056 utf8_arg = mono_utf8_from_external (argv[i]);
4057 if (utf8_arg == NULL) {
4058 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4059 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4060 exit (-1);
4063 main_args [i] = utf8_arg;
4066 return 0;
4070 * Prepare an array of arguments in order to execute a standard Main()
4071 * method (argc/argv contains the executable name). This method also
4072 * sets the command line argument value needed by System.Environment.
4075 static MonoArray*
4076 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4078 MONO_REQ_GC_UNSAFE_MODE;
4080 MonoError error;
4081 int i;
4082 MonoArray *args = NULL;
4083 MonoDomain *domain = mono_domain_get ();
4084 gchar *utf8_fullpath;
4085 MonoMethodSignature *sig;
4087 g_assert (method != NULL);
4089 mono_thread_set_main (mono_thread_current ());
4091 main_args = g_new0 (char*, argc);
4092 num_main_args = argc;
4094 if (!g_path_is_absolute (argv [0])) {
4095 gchar *basename = g_path_get_basename (argv [0]);
4096 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4097 basename,
4098 NULL);
4100 utf8_fullpath = mono_utf8_from_external (fullpath);
4101 if(utf8_fullpath == NULL) {
4102 /* Printing the arg text will cause glib to
4103 * whinge about "Invalid UTF-8", but at least
4104 * its relevant, and shows the problem text
4105 * string.
4107 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4108 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4109 exit (-1);
4112 g_free (fullpath);
4113 g_free (basename);
4114 } else {
4115 utf8_fullpath = mono_utf8_from_external (argv[0]);
4116 if(utf8_fullpath == NULL) {
4117 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4118 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4119 exit (-1);
4123 main_args [0] = utf8_fullpath;
4125 for (i = 1; i < argc; ++i) {
4126 gchar *utf8_arg;
4128 utf8_arg=mono_utf8_from_external (argv[i]);
4129 if(utf8_arg==NULL) {
4130 /* Ditto the comment about Invalid UTF-8 here */
4131 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4132 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4133 exit (-1);
4136 main_args [i] = utf8_arg;
4138 argc--;
4139 argv++;
4141 sig = mono_method_signature (method);
4142 if (!sig) {
4143 g_print ("Unable to load Main method.\n");
4144 exit (-1);
4147 if (sig->param_count) {
4148 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4149 mono_error_assert_ok (&error);
4150 for (i = 0; i < argc; ++i) {
4151 /* The encodings should all work, given that
4152 * we've checked all these args for the
4153 * main_args array.
4155 gchar *str = mono_utf8_from_external (argv [i]);
4156 MonoString *arg = mono_string_new (domain, str);
4157 mono_array_setref (args, i, arg);
4158 g_free (str);
4160 } else {
4161 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4162 mono_error_assert_ok (&error);
4165 mono_assembly_set_main (method->klass->image->assembly);
4167 return args;
4171 * mono_runtime_run_main:
4172 * @method: the method to start the application with (usually Main)
4173 * @argc: number of arguments from the command line
4174 * @argv: array of strings from the command line
4175 * @exc: excetption results
4177 * Execute a standard Main() method (argc/argv contains the
4178 * executable name). This method also sets the command line argument value
4179 * needed by System.Environment.
4184 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4185 MonoObject **exc)
4187 MONO_REQ_GC_UNSAFE_MODE;
4189 MonoError error;
4190 MonoArray *args = prepare_run_main (method, argc, argv);
4191 int res;
4192 if (exc) {
4193 res = mono_runtime_try_exec_main (method, args, exc);
4194 } else {
4195 res = mono_runtime_exec_main_checked (method, args, &error);
4196 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4198 return res;
4202 * mono_runtime_run_main_checked:
4203 * @method: the method to start the application with (usually Main)
4204 * @argc: number of arguments from the command line
4205 * @argv: array of strings from the command line
4206 * @error: set on error
4208 * Execute a standard Main() method (argc/argv contains the
4209 * executable name). This method also sets the command line argument value
4210 * needed by System.Environment. On failure sets @error.
4215 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4216 MonoError *error)
4218 mono_error_init (error);
4219 MonoArray *args = prepare_run_main (method, argc, argv);
4220 return mono_runtime_exec_main_checked (method, args, error);
4224 * mono_runtime_try_run_main:
4225 * @method: the method to start the application with (usually Main)
4226 * @argc: number of arguments from the command line
4227 * @argv: array of strings from the command line
4228 * @exc: set if Main throws an exception
4229 * @error: set if Main can't be executed
4231 * Execute a standard Main() method (argc/argv contains the executable
4232 * name). This method also sets the command line argument value needed
4233 * by System.Environment. On failure sets @error if Main can't be
4234 * executed or @exc if it threw and exception.
4239 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4240 MonoObject **exc)
4242 g_assert (exc);
4243 MonoArray *args = prepare_run_main (method, argc, argv);
4244 return mono_runtime_try_exec_main (method, args, exc);
4248 static MonoObject*
4249 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4251 static MonoMethod *serialize_method;
4253 MonoError error;
4254 void *params [1];
4255 MonoObject *array;
4257 if (!serialize_method) {
4258 MonoClass *klass = mono_class_get_remoting_services_class ();
4259 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4262 if (!serialize_method) {
4263 *failure = TRUE;
4264 return NULL;
4267 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4269 params [0] = obj;
4270 *exc = NULL;
4272 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4273 if (*exc == NULL && !mono_error_ok (&error))
4274 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4275 else
4276 mono_error_cleanup (&error);
4278 if (*exc)
4279 *failure = TRUE;
4281 return array;
4284 static MonoObject*
4285 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4287 MONO_REQ_GC_UNSAFE_MODE;
4289 static MonoMethod *deserialize_method;
4291 MonoError error;
4292 void *params [1];
4293 MonoObject *result;
4295 if (!deserialize_method) {
4296 MonoClass *klass = mono_class_get_remoting_services_class ();
4297 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4299 if (!deserialize_method) {
4300 *failure = TRUE;
4301 return NULL;
4304 params [0] = obj;
4305 *exc = NULL;
4307 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4308 if (*exc == NULL && !mono_error_ok (&error))
4309 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4310 else
4311 mono_error_cleanup (&error);
4313 if (*exc)
4314 *failure = TRUE;
4316 return result;
4319 #ifndef DISABLE_REMOTING
4320 static MonoObject*
4321 make_transparent_proxy (MonoObject *obj, MonoError *error)
4323 MONO_REQ_GC_UNSAFE_MODE;
4325 static MonoMethod *get_proxy_method;
4327 MonoDomain *domain = mono_domain_get ();
4328 MonoRealProxy *real_proxy;
4329 MonoReflectionType *reflection_type;
4330 MonoTransparentProxy *transparent_proxy;
4332 mono_error_init (error);
4334 if (!get_proxy_method)
4335 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4337 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4339 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4340 return_val_if_nok (error, NULL);
4341 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4342 return_val_if_nok (error, NULL);
4344 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4345 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4347 MonoObject *exc = NULL;
4349 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4350 if (exc != NULL && is_ok (error))
4351 mono_error_set_exception_instance (error, (MonoException*)exc);
4353 return (MonoObject*) transparent_proxy;
4355 #endif /* DISABLE_REMOTING */
4358 * mono_object_xdomain_representation
4359 * @obj: an object
4360 * @target_domain: a domain
4361 * @error: set on error.
4363 * Creates a representation of obj in the domain target_domain. This
4364 * is either a copy of obj arrived through via serialization and
4365 * deserialization or a proxy, depending on whether the object is
4366 * serializable or marshal by ref. obj must not be in target_domain.
4368 * If the object cannot be represented in target_domain, NULL is
4369 * returned and @error is set appropriately.
4371 MonoObject*
4372 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4374 MONO_REQ_GC_UNSAFE_MODE;
4376 mono_error_init (error);
4377 MonoObject *deserialized = NULL;
4379 #ifndef DISABLE_REMOTING
4380 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4381 deserialized = make_transparent_proxy (obj, error);
4383 else
4384 #endif
4386 gboolean failure = FALSE;
4387 MonoDomain *domain = mono_domain_get ();
4388 MonoObject *serialized;
4389 MonoObject *exc = NULL;
4391 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4392 serialized = serialize_object (obj, &failure, &exc);
4393 mono_domain_set_internal_with_options (target_domain, FALSE);
4394 if (!failure)
4395 deserialized = deserialize_object (serialized, &failure, &exc);
4396 if (domain != target_domain)
4397 mono_domain_set_internal_with_options (domain, FALSE);
4398 if (failure)
4399 mono_error_set_exception_instance (error, (MonoException*)exc);
4402 return deserialized;
4405 /* Used in call_unhandled_exception_delegate */
4406 static MonoObject *
4407 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4409 MONO_REQ_GC_UNSAFE_MODE;
4411 mono_error_init (error);
4412 MonoClass *klass;
4413 gpointer args [2];
4414 MonoMethod *method = NULL;
4415 MonoBoolean is_terminating = TRUE;
4416 MonoObject *obj;
4418 klass = mono_class_get_unhandled_exception_event_args_class ();
4419 mono_class_init (klass);
4421 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4422 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4423 g_assert (method);
4425 args [0] = exc;
4426 args [1] = &is_terminating;
4428 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4429 return_val_if_nok (error, NULL);
4431 mono_runtime_invoke_checked (method, obj, args, error);
4432 return_val_if_nok (error, NULL);
4434 return obj;
4437 /* Used in mono_unhandled_exception */
4438 static void
4439 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4440 MONO_REQ_GC_UNSAFE_MODE;
4442 MonoError error;
4443 MonoObject *e = NULL;
4444 gpointer pa [2];
4445 MonoDomain *current_domain = mono_domain_get ();
4447 if (domain != current_domain)
4448 mono_domain_set_internal_with_options (domain, FALSE);
4450 g_assert (domain == mono_object_domain (domain->domain));
4452 if (mono_object_domain (exc) != domain) {
4454 exc = mono_object_xdomain_representation (exc, domain, &error);
4455 if (!exc) {
4456 if (!is_ok (&error)) {
4457 MonoError inner_error;
4458 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4459 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4460 mono_error_assert_ok (&inner_error);
4461 } else {
4462 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4463 "System.Runtime.Serialization", "SerializationException",
4464 "Could not serialize unhandled exception.");
4468 g_assert (mono_object_domain (exc) == domain);
4470 pa [0] = domain->domain;
4471 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4472 mono_error_assert_ok (&error);
4473 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4474 if (!is_ok (&error)) {
4475 if (e == NULL)
4476 e = (MonoObject*)mono_error_convert_to_exception (&error);
4477 else
4478 mono_error_cleanup (&error);
4481 if (domain != current_domain)
4482 mono_domain_set_internal_with_options (current_domain, FALSE);
4484 if (e) {
4485 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4486 if (!mono_error_ok (&error)) {
4487 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4488 mono_error_cleanup (&error);
4489 } else {
4490 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4491 g_free (msg);
4496 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4499 * mono_runtime_unhandled_exception_policy_set:
4500 * @policy: the new policy
4502 * This is a VM internal routine.
4504 * Sets the runtime policy for handling unhandled exceptions.
4506 void
4507 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4508 runtime_unhandled_exception_policy = policy;
4512 * mono_runtime_unhandled_exception_policy_get:
4514 * This is a VM internal routine.
4516 * Gets the runtime policy for handling unhandled exceptions.
4518 MonoRuntimeUnhandledExceptionPolicy
4519 mono_runtime_unhandled_exception_policy_get (void) {
4520 return runtime_unhandled_exception_policy;
4524 * mono_unhandled_exception:
4525 * @exc: exception thrown
4527 * This is a VM internal routine.
4529 * We call this function when we detect an unhandled exception
4530 * in the default domain.
4532 * It invokes the * UnhandledException event in AppDomain or prints
4533 * a warning to the console
4535 void
4536 mono_unhandled_exception (MonoObject *exc)
4538 MONO_REQ_GC_UNSAFE_MODE;
4540 MonoError error;
4541 MonoClassField *field;
4542 MonoDomain *current_domain, *root_domain;
4543 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4545 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4546 return;
4548 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4549 g_assert (field);
4551 current_domain = mono_domain_get ();
4552 root_domain = mono_get_root_domain ();
4554 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4555 mono_error_assert_ok (&error);
4556 if (current_domain != root_domain) {
4557 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4558 mono_error_assert_ok (&error);
4561 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4562 mono_print_unhandled_exception (exc);
4563 } else {
4564 /* unhandled exception callbacks must not be aborted */
4565 mono_threads_begin_abort_protected_block ();
4566 if (root_appdomain_delegate)
4567 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4568 if (current_appdomain_delegate)
4569 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4570 mono_threads_end_abort_protected_block ();
4573 /* set exitcode only if we will abort the process */
4574 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4575 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4577 mono_environment_exitcode_set (1);
4582 * mono_runtime_exec_managed_code:
4583 * @domain: Application domain
4584 * @main_func: function to invoke from the execution thread
4585 * @main_args: parameter to the main_func
4587 * Launch a new thread to execute a function
4589 * main_func is called back from the thread with main_args as the
4590 * parameter. The callback function is expected to start Main()
4591 * eventually. This function then waits for all managed threads to
4592 * finish.
4593 * It is not necesseray anymore to execute managed code in a subthread,
4594 * so this function should not be used anymore by default: just
4595 * execute the code and then call mono_thread_manage ().
4597 void
4598 mono_runtime_exec_managed_code (MonoDomain *domain,
4599 MonoMainThreadFunc main_func,
4600 gpointer main_args)
4602 MonoError error;
4603 mono_thread_create_checked (domain, main_func, main_args, &error);
4604 mono_error_assert_ok (&error);
4606 mono_thread_manage ();
4609 static void
4610 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4612 MonoInternalThread* thread = mono_thread_internal_current ();
4613 MonoCustomAttrInfo* cinfo;
4614 gboolean has_stathread_attribute;
4616 if (!domain->entry_assembly) {
4617 gchar *str;
4618 MonoAssembly *assembly;
4620 assembly = method->klass->image->assembly;
4621 domain->entry_assembly = assembly;
4622 /* Domains created from another domain already have application_base and configuration_file set */
4623 if (domain->setup->application_base == NULL) {
4624 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4627 if (domain->setup->configuration_file == NULL) {
4628 str = g_strconcat (assembly->image->name, ".config", NULL);
4629 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4630 g_free (str);
4631 mono_domain_set_options_from_config (domain);
4635 MonoError cattr_error;
4636 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4637 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4638 if (cinfo) {
4639 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4640 if (!cinfo->cached)
4641 mono_custom_attrs_free (cinfo);
4642 } else {
4643 has_stathread_attribute = FALSE;
4645 if (has_stathread_attribute) {
4646 thread->apartment_state = ThreadApartmentState_STA;
4647 } else {
4648 thread->apartment_state = ThreadApartmentState_MTA;
4650 mono_thread_init_apartment_state ();
4654 static int
4655 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4657 MONO_REQ_GC_UNSAFE_MODE;
4659 gpointer pa [1];
4660 int rval;
4662 mono_error_init (error);
4663 g_assert (args);
4665 pa [0] = args;
4667 /* FIXME: check signature of method */
4668 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4669 MonoObject *res;
4670 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4671 if (is_ok (error))
4672 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4673 else
4674 rval = -1;
4675 mono_environment_exitcode_set (rval);
4676 } else {
4677 mono_runtime_invoke_checked (method, NULL, pa, error);
4679 if (is_ok (error))
4680 rval = 0;
4681 else {
4682 rval = -1;
4685 return rval;
4688 static int
4689 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4691 MONO_REQ_GC_UNSAFE_MODE;
4693 gpointer pa [1];
4694 int rval;
4696 g_assert (args);
4697 g_assert (exc);
4699 pa [0] = args;
4701 /* FIXME: check signature of method */
4702 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4703 MonoError inner_error;
4704 MonoObject *res;
4705 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4706 if (*exc == NULL && !mono_error_ok (&inner_error))
4707 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4708 else
4709 mono_error_cleanup (&inner_error);
4711 if (*exc == NULL)
4712 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4713 else
4714 rval = -1;
4716 mono_environment_exitcode_set (rval);
4717 } else {
4718 MonoError inner_error;
4719 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4720 if (*exc == NULL && !mono_error_ok (&inner_error))
4721 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4722 else
4723 mono_error_cleanup (&inner_error);
4725 if (*exc == NULL)
4726 rval = 0;
4727 else {
4728 /* If the return type of Main is void, only
4729 * set the exitcode if an exception was thrown
4730 * (we don't want to blow away an
4731 * explicitly-set exit code)
4733 rval = -1;
4734 mono_environment_exitcode_set (rval);
4738 return rval;
4742 * Execute a standard Main() method (args doesn't contain the
4743 * executable name).
4746 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4748 MonoError error;
4749 prepare_thread_to_exec_main (mono_object_domain (args), method);
4750 if (exc) {
4751 int rval = do_try_exec_main (method, args, exc);
4752 return rval;
4753 } else {
4754 int rval = do_exec_main_checked (method, args, &error);
4755 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4756 return rval;
4761 * Execute a standard Main() method (args doesn't contain the
4762 * executable name).
4764 * On failure sets @error
4767 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4769 mono_error_init (error);
4770 prepare_thread_to_exec_main (mono_object_domain (args), method);
4771 return do_exec_main_checked (method, args, error);
4775 * Execute a standard Main() method (args doesn't contain the
4776 * executable name).
4778 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4781 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4783 prepare_thread_to_exec_main (mono_object_domain (args), method);
4784 return do_try_exec_main (method, args, exc);
4789 /** invoke_array_extract_argument:
4790 * @params: array of arguments to the method.
4791 * @i: the index of the argument to extract.
4792 * @t: ith type from the method signature.
4793 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4794 * @error: set on error.
4796 * Given an array of method arguments, return the ith one using the corresponding type
4797 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4799 * On failure sets @error and returns NULL.
4801 static gpointer
4802 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4804 MonoType *t_orig = t;
4805 gpointer result = NULL;
4806 mono_error_init (error);
4807 again:
4808 switch (t->type) {
4809 case MONO_TYPE_U1:
4810 case MONO_TYPE_I1:
4811 case MONO_TYPE_BOOLEAN:
4812 case MONO_TYPE_U2:
4813 case MONO_TYPE_I2:
4814 case MONO_TYPE_CHAR:
4815 case MONO_TYPE_U:
4816 case MONO_TYPE_I:
4817 case MONO_TYPE_U4:
4818 case MONO_TYPE_I4:
4819 case MONO_TYPE_U8:
4820 case MONO_TYPE_I8:
4821 case MONO_TYPE_R4:
4822 case MONO_TYPE_R8:
4823 case MONO_TYPE_VALUETYPE:
4824 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4825 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4826 result = mono_array_get (params, MonoObject*, i);
4827 if (t->byref)
4828 *has_byref_nullables = TRUE;
4829 } else {
4830 /* MS seems to create the objects if a null is passed in */
4831 if (!mono_array_get (params, MonoObject*, i)) {
4832 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4833 return_val_if_nok (error, NULL);
4834 mono_array_setref (params, i, o);
4837 if (t->byref) {
4839 * We can't pass the unboxed vtype byref to the callee, since
4840 * that would mean the callee would be able to modify boxed
4841 * primitive types. So we (and MS) make a copy of the boxed
4842 * object, pass that to the callee, and replace the original
4843 * boxed object in the arg array with the copy.
4845 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4846 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4847 return_val_if_nok (error, NULL);
4848 mono_array_setref (params, i, copy);
4851 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4853 break;
4854 case MONO_TYPE_STRING:
4855 case MONO_TYPE_OBJECT:
4856 case MONO_TYPE_CLASS:
4857 case MONO_TYPE_ARRAY:
4858 case MONO_TYPE_SZARRAY:
4859 if (t->byref)
4860 result = mono_array_addr (params, MonoObject*, i);
4861 // FIXME: I need to check this code path
4862 else
4863 result = mono_array_get (params, MonoObject*, i);
4864 break;
4865 case MONO_TYPE_GENERICINST:
4866 if (t->byref)
4867 t = &t->data.generic_class->container_class->this_arg;
4868 else
4869 t = &t->data.generic_class->container_class->byval_arg;
4870 goto again;
4871 case MONO_TYPE_PTR: {
4872 MonoObject *arg;
4874 /* The argument should be an IntPtr */
4875 arg = mono_array_get (params, MonoObject*, i);
4876 if (arg == NULL) {
4877 result = NULL;
4878 } else {
4879 g_assert (arg->vtable->klass == mono_defaults.int_class);
4880 result = ((MonoIntPtr*)arg)->m_value;
4882 break;
4884 default:
4885 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4887 return result;
4890 * mono_runtime_invoke_array:
4891 * @method: method to invoke
4892 * @obJ: object instance
4893 * @params: arguments to the method
4894 * @exc: exception information.
4896 * Invokes the method represented by @method on the object @obj.
4898 * obj is the 'this' pointer, it should be NULL for static
4899 * methods, a MonoObject* for object instances and a pointer to
4900 * the value type for value types.
4902 * The params array contains the arguments to the method with the
4903 * same convention: MonoObject* pointers for object instances and
4904 * pointers to the value type otherwise. The _invoke_array
4905 * variant takes a C# object[] as the params argument (MonoArray
4906 * *params): in this case the value types are boxed inside the
4907 * respective reference representation.
4909 * From unmanaged code you'll usually use the
4910 * mono_runtime_invoke_checked() variant.
4912 * Note that this function doesn't handle virtual methods for
4913 * you, it will exec the exact method you pass: we still need to
4914 * expose a function to lookup the derived class implementation
4915 * of a virtual method (there are examples of this in the code,
4916 * though).
4918 * You can pass NULL as the exc argument if you don't want to
4919 * catch exceptions, otherwise, *exc will be set to the exception
4920 * thrown, if any. if an exception is thrown, you can't use the
4921 * MonoObject* result from the function.
4923 * If the method returns a value type, it is boxed in an object
4924 * reference.
4926 MonoObject*
4927 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4928 MonoObject **exc)
4930 MonoError error;
4931 if (exc) {
4932 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4933 if (*exc) {
4934 mono_error_cleanup (&error);
4935 return NULL;
4936 } else {
4937 if (!is_ok (&error))
4938 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4939 return result;
4941 } else {
4942 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4943 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4944 return result;
4949 * mono_runtime_invoke_array_checked:
4950 * @method: method to invoke
4951 * @obJ: object instance
4952 * @params: arguments to the method
4953 * @error: set on failure.
4955 * Invokes the method represented by @method on the object @obj.
4957 * obj is the 'this' pointer, it should be NULL for static
4958 * methods, a MonoObject* for object instances and a pointer to
4959 * the value type for value types.
4961 * The params array contains the arguments to the method with the
4962 * same convention: MonoObject* pointers for object instances and
4963 * pointers to the value type otherwise. The _invoke_array
4964 * variant takes a C# object[] as the params argument (MonoArray
4965 * *params): in this case the value types are boxed inside the
4966 * respective reference representation.
4968 * From unmanaged code you'll usually use the
4969 * mono_runtime_invoke_checked() variant.
4971 * Note that this function doesn't handle virtual methods for
4972 * you, it will exec the exact method you pass: we still need to
4973 * expose a function to lookup the derived class implementation
4974 * of a virtual method (there are examples of this in the code,
4975 * though).
4977 * On failure or exception, @error will be set. In that case, you
4978 * can't use the MonoObject* result from the function.
4980 * If the method returns a value type, it is boxed in an object
4981 * reference.
4983 MonoObject*
4984 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4985 MonoError *error)
4987 mono_error_init (error);
4988 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4992 * mono_runtime_try_invoke_array:
4993 * @method: method to invoke
4994 * @obJ: object instance
4995 * @params: arguments to the method
4996 * @exc: exception information.
4997 * @error: set on failure.
4999 * Invokes the method represented by @method on the object @obj.
5001 * obj is the 'this' pointer, it should be NULL for static
5002 * methods, a MonoObject* for object instances and a pointer to
5003 * the value type for value types.
5005 * The params array contains the arguments to the method with the
5006 * same convention: MonoObject* pointers for object instances and
5007 * pointers to the value type otherwise. The _invoke_array
5008 * variant takes a C# object[] as the params argument (MonoArray
5009 * *params): in this case the value types are boxed inside the
5010 * respective reference representation.
5012 * From unmanaged code you'll usually use the
5013 * mono_runtime_invoke_checked() variant.
5015 * Note that this function doesn't handle virtual methods for
5016 * you, it will exec the exact method you pass: we still need to
5017 * expose a function to lookup the derived class implementation
5018 * of a virtual method (there are examples of this in the code,
5019 * though).
5021 * You can pass NULL as the exc argument if you don't want to catch
5022 * exceptions, otherwise, *exc will be set to the exception thrown, if
5023 * any. On other failures, @error will be set. If an exception is
5024 * thrown or there's an error, you can't use the MonoObject* result
5025 * from the function.
5027 * If the method returns a value type, it is boxed in an object
5028 * reference.
5030 MonoObject*
5031 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5032 MonoObject **exc, MonoError *error)
5034 MONO_REQ_GC_UNSAFE_MODE;
5036 mono_error_init (error);
5038 MonoMethodSignature *sig = mono_method_signature (method);
5039 gpointer *pa = NULL;
5040 MonoObject *res;
5041 int i;
5042 gboolean has_byref_nullables = FALSE;
5044 if (NULL != params) {
5045 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5046 for (i = 0; i < mono_array_length (params); i++) {
5047 MonoType *t = sig->params [i];
5048 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5049 return_val_if_nok (error, NULL);
5053 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5054 void *o = obj;
5056 if (mono_class_is_nullable (method->klass)) {
5057 /* Need to create a boxed vtype instead */
5058 g_assert (!obj);
5060 if (!params)
5061 return NULL;
5062 else {
5063 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5067 if (!obj) {
5068 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5069 mono_error_assert_ok (error);
5070 g_assert (obj); /*maybe we should raise a TLE instead?*/
5071 #ifndef DISABLE_REMOTING
5072 if (mono_object_is_transparent_proxy (obj)) {
5073 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5075 #endif
5076 if (method->klass->valuetype)
5077 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5078 else
5079 o = obj;
5080 } else if (method->klass->valuetype) {
5081 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5082 return_val_if_nok (error, NULL);
5085 if (exc) {
5086 mono_runtime_try_invoke (method, o, pa, exc, error);
5087 } else {
5088 mono_runtime_invoke_checked (method, o, pa, error);
5091 return (MonoObject *)obj;
5092 } else {
5093 if (mono_class_is_nullable (method->klass)) {
5094 MonoObject *nullable;
5096 /* Convert the unboxed vtype into a Nullable structure */
5097 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5098 return_val_if_nok (error, NULL);
5100 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5101 return_val_if_nok (error, NULL);
5102 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5103 obj = mono_object_unbox (nullable);
5106 /* obj must be already unboxed if needed */
5107 if (exc) {
5108 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5109 } else {
5110 res = mono_runtime_invoke_checked (method, obj, pa, error);
5112 return_val_if_nok (error, NULL);
5114 if (sig->ret->type == MONO_TYPE_PTR) {
5115 MonoClass *pointer_class;
5116 static MonoMethod *box_method;
5117 void *box_args [2];
5118 MonoObject *box_exc;
5121 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5122 * convert it to a Pointer object.
5124 pointer_class = mono_class_get_pointer_class ();
5125 if (!box_method)
5126 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5128 g_assert (res->vtable->klass == mono_defaults.int_class);
5129 box_args [0] = ((MonoIntPtr*)res)->m_value;
5130 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5131 return_val_if_nok (error, NULL);
5133 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5134 g_assert (box_exc == NULL);
5135 mono_error_assert_ok (error);
5138 if (has_byref_nullables) {
5140 * The runtime invoke wrapper already converted byref nullables back,
5141 * and stored them in pa, we just need to copy them back to the
5142 * managed array.
5144 for (i = 0; i < mono_array_length (params); i++) {
5145 MonoType *t = sig->params [i];
5147 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5148 mono_array_setref (params, i, pa [i]);
5152 return res;
5157 * mono_object_new:
5158 * @klass: the class of the object that we want to create
5160 * Returns: a newly created object whose definition is
5161 * looked up using @klass. This will not invoke any constructors,
5162 * so the consumer of this routine has to invoke any constructors on
5163 * its own to initialize the object.
5165 * It returns NULL on failure.
5167 MonoObject *
5168 mono_object_new (MonoDomain *domain, MonoClass *klass)
5170 MONO_REQ_GC_UNSAFE_MODE;
5172 MonoError error;
5174 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5176 mono_error_cleanup (&error);
5177 return result;
5180 MonoObject *
5181 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5183 MONO_REQ_GC_UNSAFE_MODE;
5185 MonoError error;
5187 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5189 mono_error_set_pending_exception (&error);
5190 return result;
5194 * mono_object_new_checked:
5195 * @klass: the class of the object that we want to create
5196 * @error: set on error
5198 * Returns: a newly created object whose definition is
5199 * looked up using @klass. This will not invoke any constructors,
5200 * so the consumer of this routine has to invoke any constructors on
5201 * its own to initialize the object.
5203 * It returns NULL on failure and sets @error.
5205 MonoObject *
5206 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5208 MONO_REQ_GC_UNSAFE_MODE;
5210 MonoVTable *vtable;
5212 vtable = mono_class_vtable (domain, klass);
5213 g_assert (vtable); /* FIXME don't swallow the error */
5215 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5216 return o;
5220 * mono_object_new_pinned:
5222 * Same as mono_object_new, but the returned object will be pinned.
5223 * For SGEN, these objects will only be freed at appdomain unload.
5225 MonoObject *
5226 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5228 MONO_REQ_GC_UNSAFE_MODE;
5230 MonoVTable *vtable;
5232 mono_error_init (error);
5234 vtable = mono_class_vtable (domain, klass);
5235 g_assert (vtable); /* FIXME don't swallow the error */
5237 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5239 if (G_UNLIKELY (!o))
5240 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5241 else if (G_UNLIKELY (vtable->klass->has_finalize))
5242 mono_object_register_finalizer (o);
5244 return o;
5248 * mono_object_new_specific:
5249 * @vtable: the vtable of the object that we want to create
5251 * Returns: A newly created object with class and domain specified
5252 * by @vtable
5254 MonoObject *
5255 mono_object_new_specific (MonoVTable *vtable)
5257 MonoError error;
5258 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5259 mono_error_cleanup (&error);
5261 return o;
5264 MonoObject *
5265 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5267 MONO_REQ_GC_UNSAFE_MODE;
5269 MonoObject *o;
5271 mono_error_init (error);
5273 /* check for is_com_object for COM Interop */
5274 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5276 gpointer pa [1];
5277 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5279 if (im == NULL) {
5280 MonoClass *klass = mono_class_get_activation_services_class ();
5282 if (!klass->inited)
5283 mono_class_init (klass);
5285 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5286 if (!im) {
5287 mono_error_set_not_supported (error, "Linked away.");
5288 return NULL;
5290 vtable->domain->create_proxy_for_type_method = im;
5293 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5294 if (!mono_error_ok (error))
5295 return NULL;
5297 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5298 if (!mono_error_ok (error))
5299 return NULL;
5301 if (o != NULL)
5302 return o;
5305 return mono_object_new_alloc_specific_checked (vtable, error);
5308 MonoObject *
5309 ves_icall_object_new_specific (MonoVTable *vtable)
5311 MonoError error;
5312 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5313 mono_error_set_pending_exception (&error);
5315 return o;
5319 * mono_object_new_alloc_specific:
5320 * @vtable: virtual table for the object.
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 * This method might raise an exception on errors. Use the
5327 * `mono_object_new_fast_checked` method if you want to manually raise
5328 * the exception.
5330 * Returns: the allocated object.
5332 MonoObject *
5333 mono_object_new_alloc_specific (MonoVTable *vtable)
5335 MonoError error;
5336 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5337 mono_error_cleanup (&error);
5339 return o;
5343 * mono_object_new_alloc_specific_checked:
5344 * @vtable: virtual table for the object.
5345 * @error: holds the error return value.
5347 * This function allocates a new `MonoObject` with the type derived
5348 * from the @vtable information. If the class of this object has a
5349 * finalizer, then the object will be tracked for finalization.
5351 * If there is not enough memory, the @error parameter will be set
5352 * and will contain a user-visible message with the amount of bytes
5353 * that were requested.
5355 * Returns: the allocated object, or NULL if there is not enough memory
5358 MonoObject *
5359 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5361 MONO_REQ_GC_UNSAFE_MODE;
5363 MonoObject *o;
5365 mono_error_init (error);
5367 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5369 if (G_UNLIKELY (!o))
5370 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5371 else if (G_UNLIKELY (vtable->klass->has_finalize))
5372 mono_object_register_finalizer (o);
5374 return o;
5378 * mono_object_new_fast:
5379 * @vtable: virtual table for the object.
5381 * This function allocates a new `MonoObject` with the type derived
5382 * from the @vtable information. The returned object is not tracked
5383 * for finalization. If your object implements a finalizer, you should
5384 * use `mono_object_new_alloc_specific` instead.
5386 * This method might raise an exception on errors. Use the
5387 * `mono_object_new_fast_checked` method if you want to manually raise
5388 * the exception.
5390 * Returns: the allocated object.
5392 MonoObject*
5393 mono_object_new_fast (MonoVTable *vtable)
5395 MonoError error;
5396 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5397 mono_error_cleanup (&error);
5399 return o;
5403 * mono_object_new_fast_checked:
5404 * @vtable: virtual table for the object.
5405 * @error: holds the error return value.
5407 * This function allocates a new `MonoObject` with the type derived
5408 * from the @vtable information. The returned object is not tracked
5409 * for finalization. If your object implements a finalizer, you should
5410 * use `mono_object_new_alloc_specific_checked` instead.
5412 * If there is not enough memory, the @error parameter will be set
5413 * and will contain a user-visible message with the amount of bytes
5414 * that were requested.
5416 * Returns: the allocated object, or NULL if there is not enough memory
5419 MonoObject*
5420 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5422 MONO_REQ_GC_UNSAFE_MODE;
5424 MonoObject *o;
5426 mono_error_init (error);
5428 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5430 if (G_UNLIKELY (!o))
5431 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5433 return o;
5436 MonoObject *
5437 ves_icall_object_new_fast (MonoVTable *vtable)
5439 MonoError error;
5440 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5441 mono_error_set_pending_exception (&error);
5443 return o;
5446 MonoObject*
5447 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5449 MONO_REQ_GC_UNSAFE_MODE;
5451 MonoObject *o;
5453 mono_error_init (error);
5455 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5457 if (G_UNLIKELY (!o))
5458 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5459 else if (G_UNLIKELY (vtable->klass->has_finalize))
5460 mono_object_register_finalizer (o);
5462 return o;
5466 * mono_class_get_allocation_ftn:
5467 * @vtable: vtable
5468 * @for_box: the object will be used for boxing
5469 * @pass_size_in_words:
5471 * Return the allocation function appropriate for the given class.
5474 void*
5475 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5477 MONO_REQ_GC_NEUTRAL_MODE;
5479 *pass_size_in_words = FALSE;
5481 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5482 return ves_icall_object_new_specific;
5484 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5486 return ves_icall_object_new_fast;
5489 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5490 * of the overhead of parameter passing.
5493 *pass_size_in_words = TRUE;
5494 #ifdef GC_REDIRECT_TO_LOCAL
5495 return GC_local_gcj_fast_malloc;
5496 #else
5497 return GC_gcj_fast_malloc;
5498 #endif
5502 return ves_icall_object_new_specific;
5506 * mono_object_new_from_token:
5507 * @image: Context where the type_token is hosted
5508 * @token: a token of the type that we want to create
5510 * Returns: A newly created object whose definition is
5511 * looked up using @token in the @image image
5513 MonoObject *
5514 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5516 MONO_REQ_GC_UNSAFE_MODE;
5518 MonoError error;
5519 MonoObject *result;
5520 MonoClass *klass;
5522 klass = mono_class_get_checked (image, token, &error);
5523 mono_error_assert_ok (&error);
5525 result = mono_object_new_checked (domain, klass, &error);
5527 mono_error_cleanup (&error);
5528 return result;
5534 * mono_object_clone:
5535 * @obj: the object to clone
5537 * Returns: A newly created object who is a shallow copy of @obj
5539 MonoObject *
5540 mono_object_clone (MonoObject *obj)
5542 MonoError error;
5543 MonoObject *o = mono_object_clone_checked (obj, &error);
5544 mono_error_cleanup (&error);
5546 return o;
5549 MonoObject *
5550 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5552 MONO_REQ_GC_UNSAFE_MODE;
5554 MonoObject *o;
5555 int size;
5557 mono_error_init (error);
5559 size = obj->vtable->klass->instance_size;
5561 if (obj->vtable->klass->rank)
5562 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5564 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5566 if (G_UNLIKELY (!o)) {
5567 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5568 return NULL;
5571 /* If the object doesn't contain references this will do a simple memmove. */
5572 mono_gc_wbarrier_object_copy (o, obj);
5574 if (obj->vtable->klass->has_finalize)
5575 mono_object_register_finalizer (o);
5576 return o;
5580 * mono_array_full_copy:
5581 * @src: source array to copy
5582 * @dest: destination array
5584 * Copies the content of one array to another with exactly the same type and size.
5586 void
5587 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5589 MONO_REQ_GC_UNSAFE_MODE;
5591 uintptr_t size;
5592 MonoClass *klass = src->obj.vtable->klass;
5594 g_assert (klass == dest->obj.vtable->klass);
5596 size = mono_array_length (src);
5597 g_assert (size == mono_array_length (dest));
5598 size *= mono_array_element_size (klass);
5600 array_full_copy_unchecked_size (src, dest, klass, size);
5603 static void
5604 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5606 #ifdef HAVE_SGEN_GC
5607 if (klass->element_class->valuetype) {
5608 if (klass->element_class->has_references)
5609 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5610 else
5611 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5612 } else {
5613 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5615 #else
5616 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5617 #endif
5621 * mono_array_clone_in_domain:
5622 * @domain: the domain in which the array will be cloned into
5623 * @array: the array to clone
5624 * @error: set on error
5626 * This routine returns a copy of the array that is hosted on the
5627 * specified MonoDomain. On failure returns NULL and sets @error.
5629 MonoArrayHandle
5630 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5632 MONO_REQ_GC_UNSAFE_MODE;
5634 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5635 uintptr_t size = 0;
5636 MonoClass *klass = mono_handle_class (array_handle);
5638 mono_error_init (error);
5640 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5641 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5643 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5644 MonoArrayHandle o;
5645 if (array_bounds == NULL) {
5646 size = mono_array_handle_length (array_handle);
5647 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5648 if (!is_ok (error))
5649 goto leave;
5650 size *= mono_array_element_size (klass);
5651 } else {
5652 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5653 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5654 size = mono_array_element_size (klass);
5655 for (int i = 0; i < klass->rank; ++i) {
5656 sizes [i] = array_bounds [i].length;
5657 size *= array_bounds [i].length;
5658 lower_bounds [i] = array_bounds [i].lower_bound;
5660 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5661 if (!is_ok (error))
5662 goto leave;
5665 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5666 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5667 mono_gchandle_free (dst_handle);
5669 MONO_HANDLE_ASSIGN (result, o);
5671 leave:
5672 mono_gchandle_free (src_handle);
5673 return result;
5677 * mono_array_clone:
5678 * @array: the array to clone
5680 * Returns: A newly created array who is a shallow copy of @array
5682 MonoArray*
5683 mono_array_clone (MonoArray *array)
5685 MONO_REQ_GC_UNSAFE_MODE;
5687 MonoError error;
5688 MonoArray *result = mono_array_clone_checked (array, &error);
5689 mono_error_cleanup (&error);
5690 return result;
5694 * mono_array_clone_checked:
5695 * @array: the array to clone
5696 * @error: set on error
5698 * Returns: A newly created array who is a shallow copy of @array. On
5699 * failure returns NULL and sets @error.
5701 MonoArray*
5702 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5704 MONO_REQ_GC_UNSAFE_MODE;
5705 HANDLE_FUNCTION_ENTER ();
5706 /* FIXME: callers of mono_array_clone_checked should use handles */
5707 mono_error_init (error);
5708 MONO_HANDLE_DCL (MonoArray, array);
5709 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5710 HANDLE_FUNCTION_RETURN_OBJ (result);
5713 /* helper macros to check for overflow when calculating the size of arrays */
5714 #ifdef MONO_BIG_ARRAYS
5715 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5716 #define MYGUINT_MAX MYGUINT64_MAX
5717 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5718 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5719 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5720 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5721 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5722 #else
5723 #define MYGUINT32_MAX 4294967295U
5724 #define MYGUINT_MAX MYGUINT32_MAX
5725 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5726 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5727 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5728 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5729 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5730 #endif
5732 gboolean
5733 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5735 MONO_REQ_GC_NEUTRAL_MODE;
5737 uintptr_t byte_len;
5739 byte_len = mono_array_element_size (klass);
5740 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5741 return FALSE;
5742 byte_len *= len;
5743 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5744 return FALSE;
5745 byte_len += MONO_SIZEOF_MONO_ARRAY;
5747 *res = byte_len;
5749 return TRUE;
5753 * mono_array_new_full:
5754 * @domain: domain where the object is created
5755 * @array_class: array class
5756 * @lengths: lengths for each dimension in the array
5757 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5759 * This routine creates a new array objects with the given dimensions,
5760 * lower bounds and type.
5762 MonoArray*
5763 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5765 MonoError error;
5766 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5767 mono_error_cleanup (&error);
5769 return array;
5772 MonoArray*
5773 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5775 MONO_REQ_GC_UNSAFE_MODE;
5777 uintptr_t byte_len = 0, len, bounds_size;
5778 MonoObject *o;
5779 MonoArray *array;
5780 MonoArrayBounds *bounds;
5781 MonoVTable *vtable;
5782 int i;
5784 mono_error_init (error);
5786 if (!array_class->inited)
5787 mono_class_init (array_class);
5789 len = 1;
5791 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5792 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5793 len = lengths [0];
5794 if (len > MONO_ARRAY_MAX_INDEX) {
5795 mono_error_set_generic_error (error, "System", "OverflowException", "");
5796 return NULL;
5798 bounds_size = 0;
5799 } else {
5800 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5802 for (i = 0; i < array_class->rank; ++i) {
5803 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5804 mono_error_set_generic_error (error, "System", "OverflowException", "");
5805 return NULL;
5807 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5808 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5809 return NULL;
5811 len *= lengths [i];
5815 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5816 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5817 return NULL;
5820 if (bounds_size) {
5821 /* align */
5822 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5823 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5824 return NULL;
5826 byte_len = (byte_len + 3) & ~3;
5827 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5828 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5829 return NULL;
5831 byte_len += bounds_size;
5834 * Following three lines almost taken from mono_object_new ():
5835 * they need to be kept in sync.
5837 vtable = mono_class_vtable_full (domain, array_class, error);
5838 return_val_if_nok (error, NULL);
5840 if (bounds_size)
5841 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5842 else
5843 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5845 if (G_UNLIKELY (!o)) {
5846 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5847 return NULL;
5850 array = (MonoArray*)o;
5852 bounds = array->bounds;
5854 if (bounds_size) {
5855 for (i = 0; i < array_class->rank; ++i) {
5856 bounds [i].length = lengths [i];
5857 if (lower_bounds)
5858 bounds [i].lower_bound = lower_bounds [i];
5862 return array;
5866 * mono_array_new:
5867 * @domain: domain where the object is created
5868 * @eclass: element class
5869 * @n: number of array elements
5871 * This routine creates a new szarray with @n elements of type @eclass.
5873 MonoArray *
5874 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5876 MONO_REQ_GC_UNSAFE_MODE;
5878 MonoError error;
5879 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5880 mono_error_cleanup (&error);
5881 return result;
5885 * mono_array_new_checked:
5886 * @domain: domain where the object is created
5887 * @eclass: element class
5888 * @n: number of array elements
5889 * @error: set on error
5891 * This routine creates a new szarray with @n elements of type @eclass.
5892 * On failure returns NULL and sets @error.
5894 MonoArray *
5895 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5897 MonoClass *ac;
5899 mono_error_init (error);
5901 ac = mono_array_class_get (eclass, 1);
5902 g_assert (ac);
5904 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5905 return_val_if_nok (error, NULL);
5907 return mono_array_new_specific_checked (vtable, n, error);
5910 MonoArray*
5911 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5913 MonoError error;
5914 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5915 mono_error_set_pending_exception (&error);
5917 return arr;
5921 * mono_array_new_specific:
5922 * @vtable: a vtable in the appropriate domain for an initialized class
5923 * @n: number of array elements
5925 * This routine is a fast alternative to mono_array_new() for code which
5926 * can be sure about the domain it operates in.
5928 MonoArray *
5929 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5931 MonoError error;
5932 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5933 mono_error_cleanup (&error);
5935 return arr;
5938 MonoArray*
5939 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5941 MONO_REQ_GC_UNSAFE_MODE;
5943 MonoObject *o;
5944 uintptr_t byte_len;
5946 mono_error_init (error);
5948 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5949 mono_error_set_generic_error (error, "System", "OverflowException", "");
5950 return NULL;
5953 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5954 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5955 return NULL;
5957 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5959 if (G_UNLIKELY (!o)) {
5960 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5961 return NULL;
5964 return (MonoArray*)o;
5967 MonoArray*
5968 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5970 MonoError error;
5971 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5972 mono_error_set_pending_exception (&error);
5974 return arr;
5978 * mono_string_empty_wrapper:
5980 * Returns: The same empty string instance as the managed string.Empty
5982 MonoString*
5983 mono_string_empty_wrapper (void)
5985 MonoDomain *domain = mono_domain_get ();
5986 return mono_string_empty (domain);
5990 * mono_string_empty:
5992 * Returns: The same empty string instance as the managed string.Empty
5994 MonoString*
5995 mono_string_empty (MonoDomain *domain)
5997 g_assert (domain);
5998 g_assert (domain->empty_string);
5999 return domain->empty_string;
6003 * mono_string_new_utf16:
6004 * @text: a pointer to an utf16 string
6005 * @len: the length of the string
6007 * Returns: A newly created string object which contains @text.
6009 MonoString *
6010 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6012 MONO_REQ_GC_UNSAFE_MODE;
6014 MonoError error;
6015 MonoString *res = NULL;
6016 res = mono_string_new_utf16_checked (domain, text, len, &error);
6017 mono_error_cleanup (&error);
6019 return res;
6023 * mono_string_new_utf16_checked:
6024 * @text: a pointer to an utf16 string
6025 * @len: the length of the string
6026 * @error: written on error.
6028 * Returns: A newly created string object which contains @text.
6029 * On error, returns NULL and sets @error.
6031 MonoString *
6032 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6034 MONO_REQ_GC_UNSAFE_MODE;
6036 MonoString *s;
6038 mono_error_init (error);
6040 s = mono_string_new_size_checked (domain, len, error);
6041 if (s != NULL)
6042 memcpy (mono_string_chars (s), text, len * 2);
6044 return s;
6048 * mono_string_new_utf16_handle:
6049 * @text: a pointer to an utf16 string
6050 * @len: the length of the string
6051 * @error: written on error.
6053 * Returns: A newly created string object which contains @text.
6054 * On error, returns NULL and sets @error.
6056 MonoStringHandle
6057 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6059 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6063 * mono_string_new_utf32:
6064 * @text: a pointer to an utf32 string
6065 * @len: the length of the string
6066 * @error: set on failure.
6068 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6070 static MonoString *
6071 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6073 MONO_REQ_GC_UNSAFE_MODE;
6075 MonoString *s;
6076 mono_unichar2 *utf16_output = NULL;
6077 gint32 utf16_len = 0;
6078 GError *gerror = NULL;
6079 glong items_written;
6081 mono_error_init (error);
6082 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6084 if (gerror)
6085 g_error_free (gerror);
6087 while (utf16_output [utf16_len]) utf16_len++;
6089 s = mono_string_new_size_checked (domain, utf16_len, error);
6090 return_val_if_nok (error, NULL);
6092 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6094 g_free (utf16_output);
6096 return s;
6100 * mono_string_new_utf32:
6101 * @text: a pointer to an utf32 string
6102 * @len: the length of the string
6104 * Returns: A newly created string object which contains @text.
6106 MonoString *
6107 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6109 MonoError error;
6110 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6111 mono_error_cleanup (&error);
6112 return result;
6116 * mono_string_new_size:
6117 * @text: a pointer to an utf16 string
6118 * @len: the length of the string
6120 * Returns: A newly created string object of @len
6122 MonoString *
6123 mono_string_new_size (MonoDomain *domain, gint32 len)
6125 MonoError error;
6126 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6127 mono_error_cleanup (&error);
6129 return str;
6132 MonoString *
6133 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6135 MONO_REQ_GC_UNSAFE_MODE;
6137 MonoString *s;
6138 MonoVTable *vtable;
6139 size_t size;
6141 mono_error_init (error);
6143 /* check for overflow */
6144 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6145 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6146 return NULL;
6149 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6150 g_assert (size > 0);
6152 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6153 g_assert (vtable);
6155 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6157 if (G_UNLIKELY (!s)) {
6158 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6159 return NULL;
6162 return s;
6166 * mono_string_new_len:
6167 * @text: a pointer to an utf8 string
6168 * @length: number of bytes in @text to consider
6170 * Returns: A newly created string object which contains @text.
6172 MonoString*
6173 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6175 MONO_REQ_GC_UNSAFE_MODE;
6177 MonoError error;
6178 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6179 mono_error_cleanup (&error);
6180 return result;
6184 * mono_string_new_len_checked:
6185 * @text: a pointer to an utf8 string
6186 * @length: number of bytes in @text to consider
6187 * @error: set on error
6189 * Returns: A newly created string object which contains @text. On
6190 * failure returns NULL and sets @error.
6192 MonoString*
6193 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6195 MONO_REQ_GC_UNSAFE_MODE;
6197 mono_error_init (error);
6199 GError *eg_error = NULL;
6200 MonoString *o = NULL;
6201 guint16 *ut = NULL;
6202 glong items_written;
6204 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6206 if (!eg_error)
6207 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6208 else
6209 g_error_free (eg_error);
6211 g_free (ut);
6213 return o;
6217 * mono_string_new:
6218 * @text: a pointer to an utf8 string
6220 * Returns: A newly created string object which contains @text.
6222 * This function asserts if it cannot allocate a new string.
6224 * @deprecated Use mono_string_new_checked in new code.
6226 MonoString*
6227 mono_string_new (MonoDomain *domain, const char *text)
6229 MonoError error;
6230 MonoString *res = NULL;
6231 res = mono_string_new_checked (domain, text, &error);
6232 mono_error_assert_ok (&error);
6233 return res;
6237 * mono_string_new_checked:
6238 * @text: a pointer to an utf8 string
6239 * @merror: set on error
6241 * Returns: A newly created string object which contains @text.
6242 * On error returns NULL and sets @merror.
6244 MonoString*
6245 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6247 MONO_REQ_GC_UNSAFE_MODE;
6249 GError *eg_error = NULL;
6250 MonoString *o = NULL;
6251 guint16 *ut;
6252 glong items_written;
6253 int l;
6255 mono_error_init (error);
6257 l = strlen (text);
6259 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6261 if (!eg_error)
6262 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6263 else
6264 g_error_free (eg_error);
6266 g_free (ut);
6268 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6269 #if 0
6270 gunichar2 *str;
6271 const gchar *end;
6272 int len;
6273 MonoString *o = NULL;
6275 if (!g_utf8_validate (text, -1, &end)) {
6276 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6277 goto leave;
6280 len = g_utf8_strlen (text, -1);
6281 o = mono_string_new_size_checked (domain, len, error);
6282 if (!o)
6283 goto leave;
6284 str = mono_string_chars (o);
6286 while (text < end) {
6287 *str++ = g_utf8_get_char (text);
6288 text = g_utf8_next_char (text);
6291 leave:
6292 #endif
6293 return o;
6297 * mono_string_new_wrapper:
6298 * @text: pointer to utf8 characters.
6300 * Helper function to create a string object from @text in the current domain.
6302 MonoString*
6303 mono_string_new_wrapper (const char *text)
6305 MONO_REQ_GC_UNSAFE_MODE;
6307 MonoDomain *domain = mono_domain_get ();
6309 if (text)
6310 return mono_string_new (domain, text);
6312 return NULL;
6316 * mono_value_box:
6317 * @class: the class of the value
6318 * @value: a pointer to the unboxed data
6320 * Returns: A newly created object which contains @value.
6322 MonoObject *
6323 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6325 MonoError error;
6326 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6327 mono_error_cleanup (&error);
6328 return result;
6332 * mono_value_box_checked:
6333 * @domain: the domain of the new object
6334 * @class: the class of the value
6335 * @value: a pointer to the unboxed data
6336 * @error: set on error
6338 * Returns: A newly created object which contains @value. On failure
6339 * returns NULL and sets @error.
6341 MonoObject *
6342 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6344 MONO_REQ_GC_UNSAFE_MODE;
6345 MonoObject *res;
6346 int size;
6347 MonoVTable *vtable;
6349 mono_error_init (error);
6351 g_assert (klass->valuetype);
6352 if (mono_class_is_nullable (klass))
6353 return mono_nullable_box ((guint8 *)value, klass, error);
6355 vtable = mono_class_vtable (domain, klass);
6356 if (!vtable)
6357 return NULL;
6358 size = mono_class_instance_size (klass);
6359 res = mono_object_new_alloc_specific_checked (vtable, error);
6360 return_val_if_nok (error, NULL);
6362 size = size - sizeof (MonoObject);
6364 #ifdef HAVE_SGEN_GC
6365 g_assert (size == mono_class_value_size (klass, NULL));
6366 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6367 #else
6368 #if NO_UNALIGNED_ACCESS
6369 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6370 #else
6371 switch (size) {
6372 case 1:
6373 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6374 break;
6375 case 2:
6376 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6377 break;
6378 case 4:
6379 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6380 break;
6381 case 8:
6382 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6383 break;
6384 default:
6385 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6387 #endif
6388 #endif
6389 if (klass->has_finalize) {
6390 mono_object_register_finalizer (res);
6391 return_val_if_nok (error, NULL);
6393 return res;
6397 * mono_value_copy:
6398 * @dest: destination pointer
6399 * @src: source pointer
6400 * @klass: a valuetype class
6402 * Copy a valuetype from @src to @dest. This function must be used
6403 * when @klass contains references fields.
6405 void
6406 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6408 MONO_REQ_GC_UNSAFE_MODE;
6410 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6414 * mono_value_copy_array:
6415 * @dest: destination array
6416 * @dest_idx: index in the @dest array
6417 * @src: source pointer
6418 * @count: number of items
6420 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6421 * This function must be used when @klass contains references fields.
6422 * Overlap is handled.
6424 void
6425 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6427 MONO_REQ_GC_UNSAFE_MODE;
6429 int size = mono_array_element_size (dest->obj.vtable->klass);
6430 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6431 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6432 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6436 * mono_object_get_domain:
6437 * @obj: object to query
6439 * Returns: the MonoDomain where the object is hosted
6441 MonoDomain*
6442 mono_object_get_domain (MonoObject *obj)
6444 MONO_REQ_GC_UNSAFE_MODE;
6446 return mono_object_domain (obj);
6450 * mono_object_get_class:
6451 * @obj: object to query
6453 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6455 * Returns: the MonoClass of the object.
6457 MonoClass*
6458 mono_object_get_class (MonoObject *obj)
6460 MONO_REQ_GC_UNSAFE_MODE;
6462 return mono_object_class (obj);
6465 * mono_object_get_size:
6466 * @o: object to query
6468 * Returns: the size, in bytes, of @o
6470 guint
6471 mono_object_get_size (MonoObject* o)
6473 MONO_REQ_GC_UNSAFE_MODE;
6475 MonoClass* klass = mono_object_class (o);
6476 if (klass == mono_defaults.string_class) {
6477 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6478 } else if (o->vtable->rank) {
6479 MonoArray *array = (MonoArray*)o;
6480 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6481 if (array->bounds) {
6482 size += 3;
6483 size &= ~3;
6484 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6486 return size;
6487 } else {
6488 return mono_class_instance_size (klass);
6493 * mono_object_unbox:
6494 * @obj: object to unbox
6496 * Returns: a pointer to the start of the valuetype boxed in this
6497 * object.
6499 * This method will assert if the object passed is not a valuetype.
6501 gpointer
6502 mono_object_unbox (MonoObject *obj)
6504 MONO_REQ_GC_UNSAFE_MODE;
6506 /* add assert for valuetypes? */
6507 g_assert (obj->vtable->klass->valuetype);
6508 return ((char*)obj) + sizeof (MonoObject);
6512 * mono_object_isinst:
6513 * @obj: an object
6514 * @klass: a pointer to a class
6516 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6518 MonoObject *
6519 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6521 MONO_REQ_GC_UNSAFE_MODE;
6523 HANDLE_FUNCTION_ENTER ();
6524 MONO_HANDLE_DCL (MonoObject, obj);
6525 MonoError error;
6526 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6527 mono_error_cleanup (&error);
6528 HANDLE_FUNCTION_RETURN_OBJ (result);
6533 * mono_object_isinst_checked:
6534 * @obj: an object
6535 * @klass: a pointer to a class
6536 * @error: set on error
6538 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6539 * On failure returns NULL and sets @error.
6541 MonoObject *
6542 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6544 MONO_REQ_GC_UNSAFE_MODE;
6546 HANDLE_FUNCTION_ENTER ();
6547 mono_error_init (error);
6548 MONO_HANDLE_DCL (MonoObject, obj);
6549 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6550 HANDLE_FUNCTION_RETURN_OBJ (result);
6554 * mono_object_handle_isinst:
6555 * @obj: an object
6556 * @klass: a pointer to a class
6557 * @error: set on error
6559 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6560 * On failure returns NULL and sets @error.
6562 MonoObjectHandle
6563 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6565 mono_error_init (error);
6567 if (!klass->inited)
6568 mono_class_init (klass);
6570 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6571 return mono_object_handle_isinst_mbyref (obj, klass, error);
6574 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6576 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6577 MONO_HANDLE_ASSIGN (result, obj);
6578 return result;
6581 MonoObject *
6582 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6584 MONO_REQ_GC_UNSAFE_MODE;
6586 HANDLE_FUNCTION_ENTER ();
6587 MonoError error;
6588 MONO_HANDLE_DCL (MonoObject, obj);
6589 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6590 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6591 HANDLE_FUNCTION_RETURN_OBJ (result);
6594 MonoObjectHandle
6595 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6597 mono_error_init (error);
6599 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6601 if (MONO_HANDLE_IS_NULL (obj))
6602 goto leave;
6604 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6606 if (mono_class_is_interface (klass)) {
6607 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6608 MONO_HANDLE_ASSIGN (result, obj);
6609 goto leave;
6612 /* casting an array one of the invariant interfaces that must act as such */
6613 if (klass->is_array_special_interface) {
6614 if (mono_class_is_assignable_from (klass, vt->klass)) {
6615 MONO_HANDLE_ASSIGN (result, obj);
6616 goto leave;
6620 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6621 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6622 MONO_HANDLE_ASSIGN (result, obj);
6623 goto leave;
6625 } else {
6626 MonoClass *oklass = vt->klass;
6627 if (mono_class_is_transparent_proxy (oklass)){
6628 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6629 oklass = remote_class->proxy_class;
6632 mono_class_setup_supertypes (klass);
6633 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6634 MONO_HANDLE_ASSIGN (result, obj);
6635 goto leave;
6638 #ifndef DISABLE_REMOTING
6639 if (mono_class_is_transparent_proxy (vt->klass))
6641 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6642 if (!custom_type_info)
6643 goto leave;
6644 MonoDomain *domain = mono_domain_get ();
6645 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6646 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6647 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6648 MonoMethod *im = NULL;
6649 gpointer pa [2];
6651 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6652 if (!im) {
6653 mono_error_set_not_supported (error, "Linked away.");
6654 goto leave;
6656 im = mono_object_handle_get_virtual_method (rp, im, error);
6657 if (!is_ok (error))
6658 goto leave;
6659 g_assert (im);
6661 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6662 if (!is_ok (error))
6663 goto leave;
6665 pa [0] = MONO_HANDLE_RAW (reftype);
6666 pa [1] = MONO_HANDLE_RAW (obj);
6667 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6668 if (!is_ok (error))
6669 goto leave;
6671 if (*(MonoBoolean *) mono_object_unbox(res)) {
6672 /* Update the vtable of the remote type, so it can safely cast to this new type */
6673 mono_upgrade_remote_class (domain, obj, klass, error);
6674 if (!is_ok (error))
6675 goto leave;
6676 MONO_HANDLE_ASSIGN (result, obj);
6679 #endif /* DISABLE_REMOTING */
6680 leave:
6681 return result;
6685 * mono_object_castclass_mbyref:
6686 * @obj: an object
6687 * @klass: a pointer to a class
6689 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6691 MonoObject *
6692 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6694 MONO_REQ_GC_UNSAFE_MODE;
6695 HANDLE_FUNCTION_ENTER ();
6696 MonoError error;
6697 MONO_HANDLE_DCL (MonoObject, obj);
6698 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6699 if (MONO_HANDLE_IS_NULL (obj))
6700 goto leave;
6701 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6702 mono_error_cleanup (&error);
6703 leave:
6704 HANDLE_FUNCTION_RETURN_OBJ (result);
6707 typedef struct {
6708 MonoDomain *orig_domain;
6709 MonoString *ins;
6710 MonoString *res;
6711 } LDStrInfo;
6713 static void
6714 str_lookup (MonoDomain *domain, gpointer user_data)
6716 MONO_REQ_GC_UNSAFE_MODE;
6718 LDStrInfo *info = (LDStrInfo *)user_data;
6719 if (info->res || domain == info->orig_domain)
6720 return;
6721 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6724 static MonoString*
6725 mono_string_get_pinned (MonoString *str, MonoError *error)
6727 MONO_REQ_GC_UNSAFE_MODE;
6729 mono_error_init (error);
6731 /* We only need to make a pinned version of a string if this is a moving GC */
6732 if (!mono_gc_is_moving ())
6733 return str;
6734 int size;
6735 MonoString *news;
6736 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6737 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6738 if (news) {
6739 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6740 news->length = mono_string_length (str);
6741 } else {
6742 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6744 return news;
6747 static MonoString*
6748 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6750 MONO_REQ_GC_UNSAFE_MODE;
6752 MonoGHashTable *ldstr_table;
6753 MonoString *s, *res;
6754 MonoDomain *domain;
6756 mono_error_init (error);
6758 domain = ((MonoObject *)str)->vtable->domain;
6759 ldstr_table = domain->ldstr_table;
6760 ldstr_lock ();
6761 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6762 if (res) {
6763 ldstr_unlock ();
6764 return res;
6766 if (insert) {
6767 /* Allocate outside the lock */
6768 ldstr_unlock ();
6769 s = mono_string_get_pinned (str, error);
6770 return_val_if_nok (error, NULL);
6771 if (s) {
6772 ldstr_lock ();
6773 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6774 if (res) {
6775 ldstr_unlock ();
6776 return res;
6778 mono_g_hash_table_insert (ldstr_table, s, s);
6779 ldstr_unlock ();
6781 return s;
6782 } else {
6783 LDStrInfo ldstr_info;
6784 ldstr_info.orig_domain = domain;
6785 ldstr_info.ins = str;
6786 ldstr_info.res = NULL;
6788 mono_domain_foreach (str_lookup, &ldstr_info);
6789 if (ldstr_info.res) {
6791 * the string was already interned in some other domain:
6792 * intern it in the current one as well.
6794 mono_g_hash_table_insert (ldstr_table, str, str);
6795 ldstr_unlock ();
6796 return str;
6799 ldstr_unlock ();
6800 return NULL;
6804 * mono_string_is_interned:
6805 * @o: String to probe
6807 * Returns whether the string has been interned.
6809 MonoString*
6810 mono_string_is_interned (MonoString *o)
6812 MonoError error;
6813 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6814 /* This function does not fail. */
6815 mono_error_assert_ok (&error);
6816 return result;
6820 * mono_string_intern:
6821 * @o: String to intern
6823 * Interns the string passed.
6824 * Returns: The interned string.
6826 MonoString*
6827 mono_string_intern (MonoString *str)
6829 MonoError error;
6830 MonoString *result = mono_string_intern_checked (str, &error);
6831 mono_error_assert_ok (&error);
6832 return result;
6836 * mono_string_intern_checked:
6837 * @o: String to intern
6838 * @error: set on error.
6840 * Interns the string passed.
6841 * Returns: The interned string. On failure returns NULL and sets @error
6843 MonoString*
6844 mono_string_intern_checked (MonoString *str, MonoError *error)
6846 MONO_REQ_GC_UNSAFE_MODE;
6848 mono_error_init (error);
6850 return mono_string_is_interned_lookup (str, TRUE, error);
6854 * mono_ldstr:
6855 * @domain: the domain where the string will be used.
6856 * @image: a metadata context
6857 * @idx: index into the user string table.
6859 * Implementation for the ldstr opcode.
6860 * Returns: a loaded string from the @image/@idx combination.
6862 MonoString*
6863 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6865 MonoError error;
6866 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6867 mono_error_cleanup (&error);
6868 return result;
6872 * mono_ldstr_checked:
6873 * @domain: the domain where the string will be used.
6874 * @image: a metadata context
6875 * @idx: index into the user string table.
6876 * @error: set on error.
6878 * Implementation for the ldstr opcode.
6879 * Returns: a loaded string from the @image/@idx combination.
6880 * On failure returns NULL and sets @error.
6882 MonoString*
6883 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6885 MONO_REQ_GC_UNSAFE_MODE;
6886 mono_error_init (error);
6888 if (image->dynamic) {
6889 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6890 return str;
6891 } else {
6892 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6893 return NULL; /*FIXME we should probably be raising an exception here*/
6894 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6895 return str;
6900 * mono_ldstr_metadata_sig
6901 * @domain: the domain for the string
6902 * @sig: the signature of a metadata string
6903 * @error: set on error
6905 * Returns: a MonoString for a string stored in the metadata. On
6906 * failure returns NULL and sets @error.
6908 static MonoString*
6909 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6911 MONO_REQ_GC_UNSAFE_MODE;
6913 mono_error_init (error);
6914 const char *str = sig;
6915 MonoString *o, *interned;
6916 size_t len2;
6918 len2 = mono_metadata_decode_blob_size (str, &str);
6919 len2 >>= 1;
6921 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6922 return_val_if_nok (error, NULL);
6923 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6925 int i;
6926 guint16 *p2 = (guint16*)mono_string_chars (o);
6927 for (i = 0; i < len2; ++i) {
6928 *p2 = GUINT16_FROM_LE (*p2);
6929 ++p2;
6932 #endif
6933 ldstr_lock ();
6934 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6935 ldstr_unlock ();
6936 if (interned)
6937 return interned; /* o will get garbage collected */
6939 o = mono_string_get_pinned (o, error);
6940 if (o) {
6941 ldstr_lock ();
6942 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6943 if (!interned) {
6944 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6945 interned = o;
6947 ldstr_unlock ();
6950 return interned;
6954 * mono_ldstr_utf8:
6956 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6957 * of an object.
6959 char*
6960 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6962 const char *str;
6963 size_t len2;
6964 long written = 0;
6965 char *as;
6966 GError *gerror = NULL;
6968 mono_error_init (error);
6970 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6971 return NULL; /*FIXME we should probably be raising an exception here*/
6972 str = mono_metadata_user_string (image, idx);
6974 len2 = mono_metadata_decode_blob_size (str, &str);
6975 len2 >>= 1;
6977 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6978 if (gerror) {
6979 mono_error_set_argument (error, "string", "%s", gerror->message);
6980 g_error_free (gerror);
6981 return NULL;
6983 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6984 if (len2 > written) {
6985 /* allocate the total length and copy the part of the string that has been converted */
6986 char *as2 = (char *)g_malloc0 (len2);
6987 memcpy (as2, as, written);
6988 g_free (as);
6989 as = as2;
6992 return as;
6996 * mono_string_to_utf8:
6997 * @s: a System.String
6999 * Returns the UTF8 representation for @s.
7000 * The resulting buffer needs to be freed with mono_free().
7002 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7004 char *
7005 mono_string_to_utf8 (MonoString *s)
7007 MONO_REQ_GC_UNSAFE_MODE;
7009 MonoError error;
7010 char *result = mono_string_to_utf8_checked (s, &error);
7012 if (!is_ok (&error)) {
7013 mono_error_cleanup (&error);
7014 return NULL;
7016 return result;
7020 * mono_string_to_utf8_checked:
7021 * @s: a System.String
7022 * @error: a MonoError.
7024 * Converts a MonoString to its UTF8 representation. May fail; check
7025 * @error to determine whether the conversion was successful.
7026 * The resulting buffer should be freed with mono_free().
7028 char *
7029 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7031 MONO_REQ_GC_UNSAFE_MODE;
7033 long written = 0;
7034 char *as;
7035 GError *gerror = NULL;
7037 mono_error_init (error);
7039 if (s == NULL)
7040 return NULL;
7042 if (!s->length)
7043 return g_strdup ("");
7045 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7046 if (gerror) {
7047 mono_error_set_argument (error, "string", "%s", gerror->message);
7048 g_error_free (gerror);
7049 return NULL;
7051 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7052 if (s->length > written) {
7053 /* allocate the total length and copy the part of the string that has been converted */
7054 char *as2 = (char *)g_malloc0 (s->length);
7055 memcpy (as2, as, written);
7056 g_free (as);
7057 as = as2;
7060 return as;
7063 char *
7064 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7066 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7070 * mono_string_to_utf8_ignore:
7071 * @s: a MonoString
7073 * Converts a MonoString to its UTF8 representation. Will ignore
7074 * invalid surrogate pairs.
7075 * The resulting buffer should be freed with mono_free().
7078 char *
7079 mono_string_to_utf8_ignore (MonoString *s)
7081 MONO_REQ_GC_UNSAFE_MODE;
7083 long written = 0;
7084 char *as;
7086 if (s == NULL)
7087 return NULL;
7089 if (!s->length)
7090 return g_strdup ("");
7092 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7094 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7095 if (s->length > written) {
7096 /* allocate the total length and copy the part of the string that has been converted */
7097 char *as2 = (char *)g_malloc0 (s->length);
7098 memcpy (as2, as, written);
7099 g_free (as);
7100 as = as2;
7103 return as;
7107 * mono_string_to_utf8_image_ignore:
7108 * @s: a System.String
7110 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7112 char *
7113 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7115 MONO_REQ_GC_UNSAFE_MODE;
7117 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7121 * mono_string_to_utf8_mp_ignore:
7122 * @s: a System.String
7124 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7126 char *
7127 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7129 MONO_REQ_GC_UNSAFE_MODE;
7131 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7136 * mono_string_to_utf16:
7137 * @s: a MonoString
7139 * Return an null-terminated array of the utf-16 chars
7140 * contained in @s. The result must be freed with g_free().
7141 * This is a temporary helper until our string implementation
7142 * is reworked to always include the null terminating char.
7144 mono_unichar2*
7145 mono_string_to_utf16 (MonoString *s)
7147 MONO_REQ_GC_UNSAFE_MODE;
7149 char *as;
7151 if (s == NULL)
7152 return NULL;
7154 as = (char *)g_malloc ((s->length * 2) + 2);
7155 as [(s->length * 2)] = '\0';
7156 as [(s->length * 2) + 1] = '\0';
7158 if (!s->length) {
7159 return (gunichar2 *)(as);
7162 memcpy (as, mono_string_chars(s), s->length * 2);
7163 return (gunichar2 *)(as);
7167 * mono_string_to_utf32:
7168 * @s: a MonoString
7170 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7171 * contained in @s. The result must be freed with g_free().
7173 mono_unichar4*
7174 mono_string_to_utf32 (MonoString *s)
7176 MONO_REQ_GC_UNSAFE_MODE;
7178 mono_unichar4 *utf32_output = NULL;
7179 GError *error = NULL;
7180 glong items_written;
7182 if (s == NULL)
7183 return NULL;
7185 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7187 if (error)
7188 g_error_free (error);
7190 return utf32_output;
7194 * mono_string_from_utf16:
7195 * @data: the UTF16 string (LPWSTR) to convert
7197 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7199 * Returns: a MonoString.
7201 MonoString *
7202 mono_string_from_utf16 (gunichar2 *data)
7204 MonoError error;
7205 MonoString *result = mono_string_from_utf16_checked (data, &error);
7206 mono_error_cleanup (&error);
7207 return result;
7211 * mono_string_from_utf16_checked:
7212 * @data: the UTF16 string (LPWSTR) to convert
7213 * @error: set on error
7215 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7217 * Returns: a MonoString. On failure sets @error and returns NULL.
7219 MonoString *
7220 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7223 MONO_REQ_GC_UNSAFE_MODE;
7225 mono_error_init (error);
7226 MonoDomain *domain = mono_domain_get ();
7227 int len = 0;
7229 if (!data)
7230 return NULL;
7232 while (data [len]) len++;
7234 return mono_string_new_utf16_checked (domain, data, len, error);
7238 * mono_string_from_utf32:
7239 * @data: the UTF32 string (LPWSTR) to convert
7241 * Converts a UTF32 (UCS-4)to a MonoString.
7243 * Returns: a MonoString.
7245 MonoString *
7246 mono_string_from_utf32 (mono_unichar4 *data)
7248 MonoError error;
7249 MonoString *result = mono_string_from_utf32_checked (data, &error);
7250 mono_error_cleanup (&error);
7251 return result;
7255 * mono_string_from_utf32_checked:
7256 * @data: the UTF32 string (LPWSTR) to convert
7257 * @error: set on error
7259 * Converts a UTF32 (UCS-4)to a MonoString.
7261 * Returns: a MonoString. On failure returns NULL and sets @error.
7263 MonoString *
7264 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7266 MONO_REQ_GC_UNSAFE_MODE;
7268 mono_error_init (error);
7269 MonoString* result = NULL;
7270 mono_unichar2 *utf16_output = NULL;
7271 GError *gerror = NULL;
7272 glong items_written;
7273 int len = 0;
7275 if (!data)
7276 return NULL;
7278 while (data [len]) len++;
7280 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7282 if (gerror)
7283 g_error_free (gerror);
7285 result = mono_string_from_utf16_checked (utf16_output, error);
7286 g_free (utf16_output);
7287 return result;
7290 static char *
7291 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7293 MONO_REQ_GC_UNSAFE_MODE;
7295 char *r;
7296 char *mp_s;
7297 int len;
7299 if (ignore_error) {
7300 r = mono_string_to_utf8_ignore (s);
7301 } else {
7302 r = mono_string_to_utf8_checked (s, error);
7303 if (!mono_error_ok (error))
7304 return NULL;
7307 if (!mp && !image)
7308 return r;
7310 len = strlen (r) + 1;
7311 if (mp)
7312 mp_s = (char *)mono_mempool_alloc (mp, len);
7313 else
7314 mp_s = (char *)mono_image_alloc (image, len);
7316 memcpy (mp_s, r, len);
7318 g_free (r);
7320 return mp_s;
7324 * mono_string_to_utf8_image:
7325 * @s: a System.String
7327 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7329 char *
7330 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7332 MONO_REQ_GC_UNSAFE_MODE;
7334 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7338 * mono_string_to_utf8_mp:
7339 * @s: a System.String
7341 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7343 char *
7344 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7346 MONO_REQ_GC_UNSAFE_MODE;
7348 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7352 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7354 void
7355 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7357 eh_callbacks = *cbs;
7360 MonoRuntimeExceptionHandlingCallbacks *
7361 mono_get_eh_callbacks (void)
7363 return &eh_callbacks;
7367 * mono_raise_exception:
7368 * @ex: exception object
7370 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7372 void
7373 mono_raise_exception (MonoException *ex)
7375 MONO_REQ_GC_UNSAFE_MODE;
7378 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7379 * that will cause gcc to omit the function epilog, causing problems when
7380 * the JIT tries to walk the stack, since the return address on the stack
7381 * will point into the next function in the executable, not this one.
7383 eh_callbacks.mono_raise_exception (ex);
7386 void
7387 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7389 MONO_REQ_GC_UNSAFE_MODE;
7391 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7395 * mono_wait_handle_new:
7396 * @domain: Domain where the object will be created
7397 * @handle: Handle for the wait handle
7398 * @error: set on error.
7400 * Returns: A new MonoWaitHandle created in the given domain for the
7401 * given handle. On failure returns NULL and sets @rror.
7403 MonoWaitHandle *
7404 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7406 MONO_REQ_GC_UNSAFE_MODE;
7408 MonoWaitHandle *res;
7409 gpointer params [1];
7410 static MonoMethod *handle_set;
7412 mono_error_init (error);
7413 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7414 return_val_if_nok (error, NULL);
7416 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7417 if (!handle_set)
7418 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7420 params [0] = &handle;
7422 mono_runtime_invoke_checked (handle_set, res, params, error);
7423 return res;
7426 HANDLE
7427 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7429 MONO_REQ_GC_UNSAFE_MODE;
7431 static MonoClassField *f_safe_handle = NULL;
7432 MonoSafeHandle *sh;
7434 if (!f_safe_handle) {
7435 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7436 g_assert (f_safe_handle);
7439 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7440 return sh->handle;
7444 static MonoObject*
7445 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7447 MONO_REQ_GC_UNSAFE_MODE;
7449 RuntimeInvokeFunction runtime_invoke;
7451 mono_error_init (error);
7453 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7454 MonoMethod *method = mono_get_context_capture_method ();
7455 MonoMethod *wrapper;
7456 if (!method)
7457 return NULL;
7458 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7459 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7460 return_val_if_nok (error, NULL);
7461 domain->capture_context_method = mono_compile_method_checked (method, error);
7462 return_val_if_nok (error, NULL);
7465 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7467 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7470 * mono_async_result_new:
7471 * @domain:domain where the object will be created.
7472 * @handle: wait handle.
7473 * @state: state to pass to AsyncResult
7474 * @data: C closure data.
7475 * @error: set on error.
7477 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7478 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7479 * On failure returns NULL and sets @error.
7482 MonoAsyncResult *
7483 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7485 MONO_REQ_GC_UNSAFE_MODE;
7487 mono_error_init (error);
7488 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7489 return_val_if_nok (error, NULL);
7490 MonoObject *context = mono_runtime_capture_context (domain, error);
7491 return_val_if_nok (error, NULL);
7492 /* we must capture the execution context from the original thread */
7493 if (context) {
7494 MONO_OBJECT_SETREF (res, execution_context, context);
7495 /* note: result may be null if the flow is suppressed */
7498 res->data = (void **)data;
7499 MONO_OBJECT_SETREF (res, object_data, object_data);
7500 MONO_OBJECT_SETREF (res, async_state, state);
7501 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7502 return_val_if_nok (error, NULL);
7503 if (handle != NULL)
7504 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7506 res->sync_completed = FALSE;
7507 res->completed = FALSE;
7509 return res;
7512 MonoObject *
7513 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7515 MONO_REQ_GC_UNSAFE_MODE;
7517 MonoError error;
7518 MonoAsyncCall *ac;
7519 MonoObject *res;
7521 g_assert (ares);
7522 g_assert (ares->async_delegate);
7524 ac = (MonoAsyncCall*) ares->object_data;
7525 if (!ac) {
7526 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7527 if (mono_error_set_pending_exception (&error))
7528 return NULL;
7529 } else {
7530 gpointer wait_event = NULL;
7532 ac->msg->exc = NULL;
7534 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7536 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7537 mono_threads_begin_abort_protected_block ();
7539 if (!ac->msg->exc) {
7540 MonoException *ex = mono_error_convert_to_exception (&error);
7541 ac->msg->exc = (MonoObject *)ex;
7542 } else {
7543 mono_error_cleanup (&error);
7546 MONO_OBJECT_SETREF (ac, res, res);
7548 mono_monitor_enter ((MonoObject*) ares);
7549 ares->completed = 1;
7550 if (ares->handle)
7551 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7552 mono_monitor_exit ((MonoObject*) ares);
7554 if (wait_event != NULL)
7555 mono_w32event_set (wait_event);
7557 mono_error_init (&error); //the else branch would leave it in an undefined state
7558 if (ac->cb_method)
7559 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7561 mono_threads_end_abort_protected_block ();
7563 if (mono_error_set_pending_exception (&error))
7564 return NULL;
7567 return res;
7570 gboolean
7571 mono_message_init (MonoDomain *domain,
7572 MonoMethodMessage *this_obj,
7573 MonoReflectionMethod *method,
7574 MonoArray *out_args,
7575 MonoError *error)
7577 MONO_REQ_GC_UNSAFE_MODE;
7579 static MonoMethod *init_message_method = NULL;
7581 if (!init_message_method) {
7582 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7583 g_assert (init_message_method != NULL);
7586 mono_error_init (error);
7587 /* FIXME set domain instead? */
7588 g_assert (domain == mono_domain_get ());
7590 gpointer args[2];
7592 args[0] = method;
7593 args[1] = out_args;
7595 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7596 return is_ok (error);
7599 #ifndef DISABLE_REMOTING
7601 * mono_remoting_invoke:
7602 * @real_proxy: pointer to a RealProxy object
7603 * @msg: The MonoMethodMessage to execute
7604 * @exc: used to store exceptions
7605 * @out_args: used to store output arguments
7607 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7608 * IMessage interface and it is not trivial to extract results from there. So
7609 * we call an helper method PrivateInvoke instead of calling
7610 * RealProxy::Invoke() directly.
7612 * Returns: the result object.
7614 MonoObject *
7615 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7617 MONO_REQ_GC_UNSAFE_MODE;
7619 MonoObject *o;
7620 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7621 gpointer pa [4];
7623 g_assert (exc);
7625 mono_error_init (error);
7627 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7629 if (!im) {
7630 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7631 if (!im) {
7632 mono_error_set_not_supported (error, "Linked away.");
7633 return NULL;
7635 real_proxy->vtable->domain->private_invoke_method = im;
7638 pa [0] = real_proxy;
7639 pa [1] = msg;
7640 pa [2] = exc;
7641 pa [3] = out_args;
7643 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7644 return_val_if_nok (error, NULL);
7646 return o;
7648 #endif
7650 MonoObject *
7651 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7652 MonoObject **exc, MonoArray **out_args, MonoError *error)
7654 MONO_REQ_GC_UNSAFE_MODE;
7656 static MonoClass *object_array_klass;
7657 mono_error_init (error);
7659 MonoDomain *domain;
7660 MonoMethod *method;
7661 MonoMethodSignature *sig;
7662 MonoArray *arr;
7663 int i, j, outarg_count = 0;
7665 #ifndef DISABLE_REMOTING
7666 if (target && mono_object_is_transparent_proxy (target)) {
7667 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7668 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7669 target = tp->rp->unwrapped_server;
7670 } else {
7671 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7674 #endif
7676 domain = mono_domain_get ();
7677 method = msg->method->method;
7678 sig = mono_method_signature (method);
7680 for (i = 0; i < sig->param_count; i++) {
7681 if (sig->params [i]->byref)
7682 outarg_count++;
7685 if (!object_array_klass) {
7686 MonoClass *klass;
7688 klass = mono_array_class_get (mono_defaults.object_class, 1);
7689 g_assert (klass);
7691 mono_memory_barrier ();
7692 object_array_klass = klass;
7695 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7696 return_val_if_nok (error, NULL);
7698 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7699 *exc = NULL;
7701 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7702 return_val_if_nok (error, NULL);
7704 for (i = 0, j = 0; i < sig->param_count; i++) {
7705 if (sig->params [i]->byref) {
7706 MonoObject* arg;
7707 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7708 mono_array_setref (*out_args, j, arg);
7709 j++;
7713 return ret;
7717 * prepare_to_string_method:
7718 * @obj: The object
7719 * @target: Set to @obj or unboxed value if a valuetype
7721 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7723 static MonoMethod *
7724 prepare_to_string_method (MonoObject *obj, void **target)
7726 MONO_REQ_GC_UNSAFE_MODE;
7728 static MonoMethod *to_string = NULL;
7729 MonoMethod *method;
7730 g_assert (target);
7731 g_assert (obj);
7733 *target = obj;
7735 if (!to_string)
7736 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7738 method = mono_object_get_virtual_method (obj, to_string);
7740 // Unbox value type if needed
7741 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7742 *target = mono_object_unbox (obj);
7744 return method;
7748 * mono_object_to_string:
7749 * @obj: The object
7750 * @exc: Any exception thrown by ToString (). May be NULL.
7752 * Returns: the result of calling ToString () on an object.
7754 MonoString *
7755 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7757 MonoError error;
7758 MonoString *s = NULL;
7759 void *target;
7760 MonoMethod *method = prepare_to_string_method (obj, &target);
7761 if (exc) {
7762 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7763 if (*exc == NULL && !mono_error_ok (&error))
7764 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7765 else
7766 mono_error_cleanup (&error);
7767 } else {
7768 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7769 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7772 return s;
7776 * mono_object_to_string_checked:
7777 * @obj: The object
7778 * @error: Set on error.
7780 * Returns: the result of calling ToString () on an object. If the
7781 * method cannot be invoked or if it raises an exception, sets @error
7782 * and returns NULL.
7784 MonoString *
7785 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7787 mono_error_init (error);
7788 void *target;
7789 MonoMethod *method = prepare_to_string_method (obj, &target);
7790 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7794 * mono_object_try_to_string:
7795 * @obj: The object
7796 * @exc: Any exception thrown by ToString (). Must not be NULL.
7797 * @error: Set if method cannot be invoked.
7799 * Returns: the result of calling ToString () on an object. If the
7800 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7801 * and returns NULL.
7803 MonoString *
7804 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7806 g_assert (exc);
7807 mono_error_init (error);
7808 void *target;
7809 MonoMethod *method = prepare_to_string_method (obj, &target);
7810 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7815 static char *
7816 get_native_backtrace (MonoException *exc_raw)
7818 HANDLE_FUNCTION_ENTER ();
7819 MONO_HANDLE_DCL(MonoException, exc);
7820 char * trace = mono_exception_handle_get_native_backtrace (exc);
7821 HANDLE_FUNCTION_RETURN_VAL (trace);
7825 * mono_print_unhandled_exception:
7826 * @exc: The exception
7828 * Prints the unhandled exception.
7830 void
7831 mono_print_unhandled_exception (MonoObject *exc)
7833 MONO_REQ_GC_UNSAFE_MODE;
7835 MonoString * str;
7836 char *message = (char*)"";
7837 gboolean free_message = FALSE;
7838 MonoError error;
7840 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7841 message = g_strdup ("OutOfMemoryException");
7842 free_message = TRUE;
7843 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7844 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7845 free_message = TRUE;
7846 } else {
7848 if (((MonoException*)exc)->native_trace_ips) {
7849 message = get_native_backtrace ((MonoException*)exc);
7850 free_message = TRUE;
7851 } else {
7852 MonoObject *other_exc = NULL;
7853 str = mono_object_try_to_string (exc, &other_exc, &error);
7854 if (other_exc == NULL && !is_ok (&error))
7855 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7856 else
7857 mono_error_cleanup (&error);
7858 if (other_exc) {
7859 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7860 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7862 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7863 original_backtrace, nested_backtrace);
7865 g_free (original_backtrace);
7866 g_free (nested_backtrace);
7867 free_message = TRUE;
7868 } else if (str) {
7869 message = mono_string_to_utf8_checked (str, &error);
7870 if (!mono_error_ok (&error)) {
7871 mono_error_cleanup (&error);
7872 message = (char *) "";
7873 } else {
7874 free_message = TRUE;
7881 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7882 * exc->vtable->klass->name, message);
7884 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7886 if (free_message)
7887 g_free (message);
7891 * mono_delegate_ctor_with_method:
7892 * @this: pointer to an uninitialized delegate object
7893 * @target: target object
7894 * @addr: pointer to native code
7895 * @method: method
7896 * @error: set on error.
7898 * Initialize a delegate and sets a specific method, not the one
7899 * associated with addr. This is useful when sharing generic code.
7900 * In that case addr will most probably not be associated with the
7901 * correct instantiation of the method.
7902 * On failure returns FALSE and sets @error.
7904 gboolean
7905 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7907 MONO_REQ_GC_UNSAFE_MODE;
7909 mono_error_init (error);
7910 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7912 g_assert (this_obj);
7913 g_assert (addr);
7915 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7917 if (method)
7918 delegate->method = method;
7920 mono_stats.delegate_creations++;
7922 #ifndef DISABLE_REMOTING
7923 if (target && mono_object_is_transparent_proxy (target)) {
7924 g_assert (method);
7925 method = mono_marshal_get_remoting_invoke (method);
7926 delegate->method_ptr = mono_compile_method_checked (method, error);
7927 return_val_if_nok (error, FALSE);
7928 MONO_OBJECT_SETREF (delegate, target, target);
7929 } else
7930 #endif
7932 delegate->method_ptr = addr;
7933 MONO_OBJECT_SETREF (delegate, target, target);
7936 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7937 if (callbacks.init_delegate)
7938 callbacks.init_delegate (delegate);
7939 return TRUE;
7943 * mono_delegate_ctor:
7944 * @this: pointer to an uninitialized delegate object
7945 * @target: target object
7946 * @addr: pointer to native code
7947 * @error: set on error.
7949 * This is used to initialize a delegate.
7950 * On failure returns FALSE and sets @error.
7952 gboolean
7953 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7955 MONO_REQ_GC_UNSAFE_MODE;
7957 mono_error_init (error);
7958 MonoDomain *domain = mono_domain_get ();
7959 MonoJitInfo *ji;
7960 MonoMethod *method = NULL;
7962 g_assert (addr);
7964 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7965 /* Shared code */
7966 if (!ji && domain != mono_get_root_domain ())
7967 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7968 if (ji) {
7969 method = mono_jit_info_get_method (ji);
7970 g_assert (!mono_class_is_gtd (method->klass));
7973 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7977 * mono_method_call_message_new:
7978 * @method: method to encapsulate
7979 * @params: parameters to the method
7980 * @invoke: optional, delegate invoke.
7981 * @cb: async callback delegate.
7982 * @state: state passed to the async callback.
7983 * @error: set on error.
7985 * Translates arguments pointers into a MonoMethodMessage.
7986 * On failure returns NULL and sets @error.
7988 MonoMethodMessage *
7989 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7990 MonoDelegate **cb, MonoObject **state, MonoError *error)
7992 MONO_REQ_GC_UNSAFE_MODE;
7994 mono_error_init (error);
7996 MonoDomain *domain = mono_domain_get ();
7997 MonoMethodSignature *sig = mono_method_signature (method);
7998 MonoMethodMessage *msg;
7999 int i, count;
8001 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8002 return_val_if_nok (error, NULL);
8004 if (invoke) {
8005 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8006 return_val_if_nok (error, NULL);
8007 mono_message_init (domain, msg, rm, NULL, error);
8008 return_val_if_nok (error, NULL);
8009 count = sig->param_count - 2;
8010 } else {
8011 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8012 return_val_if_nok (error, NULL);
8013 mono_message_init (domain, msg, rm, NULL, error);
8014 return_val_if_nok (error, NULL);
8015 count = sig->param_count;
8018 for (i = 0; i < count; i++) {
8019 gpointer vpos;
8020 MonoClass *klass;
8021 MonoObject *arg;
8023 if (sig->params [i]->byref)
8024 vpos = *((gpointer *)params [i]);
8025 else
8026 vpos = params [i];
8028 klass = mono_class_from_mono_type (sig->params [i]);
8030 if (klass->valuetype) {
8031 arg = mono_value_box_checked (domain, klass, vpos, error);
8032 return_val_if_nok (error, NULL);
8033 } else
8034 arg = *((MonoObject **)vpos);
8036 mono_array_setref (msg->args, i, arg);
8039 if (cb != NULL && state != NULL) {
8040 *cb = *((MonoDelegate **)params [i]);
8041 i++;
8042 *state = *((MonoObject **)params [i]);
8045 return msg;
8049 * mono_method_return_message_restore:
8051 * Restore results from message based processing back to arguments pointers
8053 void
8054 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8056 MONO_REQ_GC_UNSAFE_MODE;
8058 mono_error_init (error);
8060 MonoMethodSignature *sig = mono_method_signature (method);
8061 int i, j, type, size, out_len;
8063 if (out_args == NULL)
8064 return;
8065 out_len = mono_array_length (out_args);
8066 if (out_len == 0)
8067 return;
8069 for (i = 0, j = 0; i < sig->param_count; i++) {
8070 MonoType *pt = sig->params [i];
8072 if (pt->byref) {
8073 char *arg;
8074 if (j >= out_len) {
8075 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8076 return;
8079 arg = (char *)mono_array_get (out_args, gpointer, j);
8080 type = pt->type;
8082 g_assert (type != MONO_TYPE_VOID);
8084 if (MONO_TYPE_IS_REFERENCE (pt)) {
8085 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8086 } else {
8087 if (arg) {
8088 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8089 size = mono_class_value_size (klass, NULL);
8090 if (klass->has_references)
8091 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8092 else
8093 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8094 } else {
8095 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8096 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8100 j++;
8105 #ifndef DISABLE_REMOTING
8108 * mono_load_remote_field:
8109 * @this: pointer to an object
8110 * @klass: klass of the object containing @field
8111 * @field: the field to load
8112 * @res: a storage to store the result
8114 * This method is called by the runtime on attempts to load fields of
8115 * transparent proxy objects. @this points to such TP, @klass is the class of
8116 * the object containing @field. @res is a storage location which can be
8117 * used to store the result.
8119 * Returns: an address pointing to the value of field.
8121 gpointer
8122 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8124 MonoError error;
8125 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8126 mono_error_cleanup (&error);
8127 return result;
8131 * mono_load_remote_field_checked:
8132 * @this: pointer to an object
8133 * @klass: klass of the object containing @field
8134 * @field: the field to load
8135 * @res: a storage to store the result
8136 * @error: set on error
8138 * This method is called by the runtime on attempts to load fields of
8139 * transparent proxy objects. @this points to such TP, @klass is the class of
8140 * the object containing @field. @res is a storage location which can be
8141 * used to store the result.
8143 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8145 gpointer
8146 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8148 MONO_REQ_GC_UNSAFE_MODE;
8150 static MonoMethod *getter = NULL;
8152 mono_error_init (error);
8154 MonoDomain *domain = mono_domain_get ();
8155 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8156 MonoClass *field_class;
8157 MonoMethodMessage *msg;
8158 MonoArray *out_args;
8159 MonoObject *exc;
8160 char* full_name;
8162 g_assert (mono_object_is_transparent_proxy (this_obj));
8163 g_assert (res != NULL);
8165 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8166 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8167 return res;
8170 if (!getter) {
8171 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8172 if (!getter) {
8173 mono_error_set_not_supported (error, "Linked away.");
8174 return NULL;
8178 field_class = mono_class_from_mono_type (field->type);
8180 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8181 return_val_if_nok (error, NULL);
8182 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8183 return_val_if_nok (error, NULL);
8184 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8185 return_val_if_nok (error, NULL);
8186 mono_message_init (domain, msg, rm, out_args, error);
8187 return_val_if_nok (error, NULL);
8189 full_name = mono_type_get_full_name (klass);
8190 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8191 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8192 g_free (full_name);
8194 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8195 return_val_if_nok (error, NULL);
8197 if (exc) {
8198 mono_error_set_exception_instance (error, (MonoException *)exc);
8199 return NULL;
8202 if (mono_array_length (out_args) == 0)
8203 return NULL;
8205 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8207 if (field_class->valuetype) {
8208 return ((char *)*res) + sizeof (MonoObject);
8209 } else
8210 return res;
8214 * mono_load_remote_field_new:
8215 * @this:
8216 * @klass:
8217 * @field:
8219 * Missing documentation.
8221 MonoObject *
8222 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8224 MonoError error;
8226 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8227 mono_error_cleanup (&error);
8228 return result;
8232 * mono_load_remote_field_new_checked:
8233 * @this: pointer to an object
8234 * @klass: klass of the object containing @field
8235 * @field: the field to load
8236 * @error: set on error.
8238 * This method is called by the runtime on attempts to load fields of
8239 * transparent proxy objects. @this points to such TP, @klass is the class of
8240 * the object containing @field.
8242 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8244 MonoObject *
8245 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8247 MONO_REQ_GC_UNSAFE_MODE;
8249 mono_error_init (error);
8251 static MonoMethod *tp_load = NULL;
8253 g_assert (mono_object_is_transparent_proxy (this_obj));
8255 if (!tp_load) {
8256 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8257 if (!tp_load) {
8258 mono_error_set_not_supported (error, "Linked away.");
8259 return NULL;
8263 /* MonoType *type = mono_class_get_type (klass); */
8265 gpointer args[2];
8266 args [0] = &klass;
8267 args [1] = &field;
8269 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8273 * mono_store_remote_field:
8274 * @this_obj: pointer to an object
8275 * @klass: klass of the object containing @field
8276 * @field: the field to load
8277 * @val: the value/object to store
8279 * This method is called by the runtime on attempts to store fields of
8280 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8281 * the object containing @field. @val is the new value to store in @field.
8283 void
8284 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8286 MonoError error;
8287 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8288 mono_error_cleanup (&error);
8292 * mono_store_remote_field_checked:
8293 * @this_obj: pointer to an object
8294 * @klass: klass of the object containing @field
8295 * @field: the field to load
8296 * @val: the value/object to store
8297 * @error: set on error
8299 * This method is called by the runtime on attempts to store fields of
8300 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8301 * the object containing @field. @val is the new value to store in @field.
8303 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8305 gboolean
8306 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8309 MONO_REQ_GC_UNSAFE_MODE;
8311 mono_error_init (error);
8313 MonoDomain *domain = mono_domain_get ();
8314 MonoClass *field_class;
8315 MonoObject *arg;
8317 g_assert (mono_object_is_transparent_proxy (this_obj));
8319 field_class = mono_class_from_mono_type (field->type);
8321 if (field_class->valuetype) {
8322 arg = mono_value_box_checked (domain, field_class, val, error);
8323 return_val_if_nok (error, FALSE);
8324 } else {
8325 arg = *((MonoObject**)val);
8328 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8332 * mono_store_remote_field_new:
8333 * @this_obj:
8334 * @klass:
8335 * @field:
8336 * @arg:
8338 * Missing documentation
8340 void
8341 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8343 MonoError error;
8344 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8345 mono_error_cleanup (&error);
8349 * mono_store_remote_field_new_checked:
8350 * @this_obj:
8351 * @klass:
8352 * @field:
8353 * @arg:
8354 * @error:
8356 * Missing documentation
8358 gboolean
8359 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8361 MONO_REQ_GC_UNSAFE_MODE;
8363 static MonoMethod *tp_store = NULL;
8365 mono_error_init (error);
8367 g_assert (mono_object_is_transparent_proxy (this_obj));
8369 if (!tp_store) {
8370 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8371 if (!tp_store) {
8372 mono_error_set_not_supported (error, "Linked away.");
8373 return FALSE;
8377 gpointer args[3];
8378 args [0] = &klass;
8379 args [1] = &field;
8380 args [2] = arg;
8382 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8383 return is_ok (error);
8385 #endif
8388 * mono_create_ftnptr:
8390 * Given a function address, create a function descriptor for it.
8391 * This is only needed on some platforms.
8393 gpointer
8394 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8396 return callbacks.create_ftnptr (domain, addr);
8400 * mono_get_addr_from_ftnptr:
8402 * Given a pointer to a function descriptor, return the function address.
8403 * This is only needed on some platforms.
8405 gpointer
8406 mono_get_addr_from_ftnptr (gpointer descr)
8408 return callbacks.get_addr_from_ftnptr (descr);
8412 * mono_string_chars:
8413 * @s: a MonoString
8415 * Returns a pointer to the UCS16 characters stored in the MonoString
8417 gunichar2 *
8418 mono_string_chars (MonoString *s)
8420 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8422 return s->chars;
8426 * mono_string_length:
8427 * @s: MonoString
8429 * Returns the lenght in characters of the string
8432 mono_string_length (MonoString *s)
8434 MONO_REQ_GC_UNSAFE_MODE;
8436 return s->length;
8440 * mono_string_handle_length:
8441 * @s: MonoString
8443 * Returns the lenght in characters of the string
8446 mono_string_handle_length (MonoStringHandle s)
8448 MONO_REQ_GC_UNSAFE_MODE;
8450 return MONO_HANDLE_GETVAL (s, length);
8455 * mono_array_length:
8456 * @array: a MonoArray*
8458 * Returns the total number of elements in the array. This works for
8459 * both vectors and multidimensional arrays.
8461 uintptr_t
8462 mono_array_length (MonoArray *array)
8464 MONO_REQ_GC_UNSAFE_MODE;
8466 return array->max_length;
8470 * mono_array_addr_with_size:
8471 * @array: a MonoArray*
8472 * @size: size of the array elements
8473 * @idx: index into the array
8475 * Use this function to obtain the address for the @idx item on the
8476 * @array containing elements of size @size.
8478 * This method performs no bounds checking or type checking.
8480 * Returns the address of the @idx element in the array.
8482 char*
8483 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8485 MONO_REQ_GC_UNSAFE_MODE;
8487 return ((char*)(array)->vector) + size * idx;
8491 MonoArray *
8492 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8494 MonoDomain *domain = mono_domain_get ();
8495 MonoArray *res;
8496 int len, i;
8498 mono_error_init (error);
8499 if (!list)
8500 return NULL;
8502 len = g_list_length (list);
8503 res = mono_array_new_checked (domain, eclass, len, error);
8504 return_val_if_nok (error, NULL);
8506 for (i = 0; list; list = list->next, i++)
8507 mono_array_set (res, gpointer, i, list->data);
8509 return res;
8512 #if NEVER_DEFINED
8514 * The following section is purely to declare prototypes and
8515 * document the API, as these C files are processed by our
8516 * tool
8520 * mono_array_set:
8521 * @array: array to alter
8522 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8523 * @index: index into the array
8524 * @value: value to set
8526 * Value Type version: This sets the @index's element of the @array
8527 * with elements of size sizeof(type) to the provided @value.
8529 * This macro does not attempt to perform type checking or bounds checking.
8531 * Use this to set value types in a `MonoArray`.
8533 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8538 * mono_array_setref:
8539 * @array: array to alter
8540 * @index: index into the array
8541 * @value: value to set
8543 * Reference Type version: This sets the @index's element of the
8544 * @array with elements of size sizeof(type) to the provided @value.
8546 * This macro does not attempt to perform type checking or bounds checking.
8548 * Use this to reference types in a `MonoArray`.
8550 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8555 * mono_array_get:
8556 * @array: array on which to operate on
8557 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8558 * @index: index into the array
8560 * Use this macro to retrieve the @index element of an @array and
8561 * extract the value assuming that the elements of the array match
8562 * the provided type value.
8564 * This method can be used with both arrays holding value types and
8565 * reference types. For reference types, the @type parameter should
8566 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8568 * This macro does not attempt to perform type checking or bounds checking.
8570 * Returns: The element at the @index position in the @array.
8572 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8575 #endif