Merge pull request #5560 from kumpera/wasm-work-p3
[mono.git] / mono / metadata / object.c
1 /**
2  * \file
3  * Object creation for the Mono runtime
4  *
5  * Author:
6  *   Miguel de Icaza (miguel@ximian.com)
7  *   Paolo Molaro (lupus@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11  * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 #include <config.h>
15 #ifdef HAVE_ALLOCA_H
16 #include <alloca.h>
17 #endif
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include <mono/metadata/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>
52 #include <mono/utils/unlocked.h>
53
54 static void
55 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
56
57 static MonoString*
58 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
59
60 static void
61 free_main_args (void);
62
63 static char *
64 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
65
66 static void
67 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
68
69 static MonoMethod*
70 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71
72 /* Class lazy loading functions */
73 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
74 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
75 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
76 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
77 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
78
79
80 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
81 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
82 static mono_mutex_t ldstr_section;
83
84
85 /**
86  * mono_runtime_object_init:
87  * \param this_obj the object to initialize
88  * This function calls the zero-argument constructor (which must
89  * exist) for the given object.
90  */
91 void
92 mono_runtime_object_init (MonoObject *this_obj)
93 {
94         MonoError error;
95         mono_runtime_object_init_checked (this_obj, &error);
96         mono_error_assert_ok (&error);
97 }
98
99 /**
100  * mono_runtime_object_init_checked:
101  * \param this_obj the object to initialize
102  * \param error set on error.
103  * This function calls the zero-argument constructor (which must
104  * exist) for the given object and returns TRUE on success, or FALSE
105  * on error and sets \p error.
106  */
107 gboolean
108 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
109 {
110         MONO_REQ_GC_UNSAFE_MODE;
111
112         MonoMethod *method = NULL;
113         MonoClass *klass = this_obj->vtable->klass;
114
115         error_init (error);
116         method = mono_class_get_method_from_name (klass, ".ctor", 0);
117         if (!method)
118                 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
119
120         if (method->klass->valuetype)
121                 this_obj = (MonoObject *)mono_object_unbox (this_obj);
122
123         mono_runtime_invoke_checked (method, this_obj, NULL, error);
124         return is_ok (error);
125 }
126
127 /* The pseudo algorithm for type initialization from the spec
128 Note it doesn't say anything about domains - only threads.
129
130 2. If the type is initialized you are done.
131 2.1. If the type is not yet initialized, try to take an 
132      initialization lock.  
133 2.2. If successful, record this thread as responsible for 
134      initializing the type and proceed to step 2.3.
135 2.2.1. If not, see whether this thread or any thread 
136      waiting for this thread to complete already holds the lock.
137 2.2.2. If so, return since blocking would create a deadlock.  This thread 
138      will now see an incompletely initialized state for the type, 
139      but no deadlock will arise.
140 2.2.3  If not, block until the type is initialized then return.
141 2.3 Initialize the parent type and then all interfaces implemented 
142     by this type.
143 2.4 Execute the type initialization code for this type.
144 2.5 Mark the type as initialized, release the initialization lock, 
145     awaken any threads waiting for this type to be initialized, 
146     and return.
147
148 */
149
150 typedef struct
151 {
152         MonoNativeThreadId initializing_tid;
153         guint32 waiting_count;
154         gboolean done;
155         MonoCoopMutex mutex;
156         /* condvar used to wait for 'done' becoming TRUE */
157         MonoCoopCond cond;
158 } TypeInitializationLock;
159
160 /* for locking access to type_initialization_hash and blocked_thread_hash */
161 static MonoCoopMutex type_initialization_section;
162
163 static inline void
164 mono_type_initialization_lock (void)
165 {
166         /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
167         mono_coop_mutex_lock (&type_initialization_section);
168 }
169
170 static inline void
171 mono_type_initialization_unlock (void)
172 {
173         mono_coop_mutex_unlock (&type_initialization_section);
174 }
175
176 static void
177 mono_type_init_lock (TypeInitializationLock *lock)
178 {
179         MONO_REQ_GC_NEUTRAL_MODE;
180
181         mono_coop_mutex_lock (&lock->mutex);
182 }
183
184 static void
185 mono_type_init_unlock (TypeInitializationLock *lock)
186 {
187         mono_coop_mutex_unlock (&lock->mutex);
188 }
189
190 /* from vtable to lock */
191 static GHashTable *type_initialization_hash;
192
193 /* from thread id to thread id being waited on */
194 static GHashTable *blocked_thread_hash;
195
196 /* Main thread */
197 static MonoThread *main_thread;
198
199 /* Functions supplied by the runtime */
200 static MonoRuntimeCallbacks callbacks;
201
202 /**
203  * mono_thread_set_main:
204  * \param thread thread to set as the main thread
205  * This function can be used to instruct the runtime to treat \p thread
206  * as the main thread, ie, the thread that would normally execute the \c Main
207  * method. This basically means that at the end of \p thread, the runtime will
208  * wait for the existing foreground threads to quit and other such details.
209  */
210 void
211 mono_thread_set_main (MonoThread *thread)
212 {
213         MONO_REQ_GC_UNSAFE_MODE;
214
215         static gboolean registered = FALSE;
216
217         if (!registered) {
218                 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
219                 registered = TRUE;
220         }
221
222         main_thread = thread;
223 }
224
225 /**
226  * mono_thread_get_main:
227  */
228 MonoThread*
229 mono_thread_get_main (void)
230 {
231         MONO_REQ_GC_UNSAFE_MODE;
232
233         return main_thread;
234 }
235
236 void
237 mono_type_initialization_init (void)
238 {
239         mono_coop_mutex_init_recursive (&type_initialization_section);
240         type_initialization_hash = g_hash_table_new (NULL, NULL);
241         blocked_thread_hash = g_hash_table_new (NULL, NULL);
242         mono_os_mutex_init_recursive (&ldstr_section);
243         mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
244 }
245
246 void
247 mono_type_initialization_cleanup (void)
248 {
249 #if 0
250         /* This is causing race conditions with
251          * mono_release_type_locks
252          */
253         mono_coop_mutex_destroy (&type_initialization_section);
254         g_hash_table_destroy (type_initialization_hash);
255         type_initialization_hash = NULL;
256 #endif
257         mono_os_mutex_destroy (&ldstr_section);
258         g_hash_table_destroy (blocked_thread_hash);
259         blocked_thread_hash = NULL;
260
261         free_main_args ();
262 }
263
264 /**
265  * get_type_init_exception_for_vtable:
266  *
267  *   Return the stored type initialization exception for VTABLE.
268  */
269 static MonoException*
270 get_type_init_exception_for_vtable (MonoVTable *vtable)
271 {
272         MONO_REQ_GC_UNSAFE_MODE;
273
274         MonoError error;
275         MonoDomain *domain = vtable->domain;
276         MonoClass *klass = vtable->klass;
277         MonoException *ex;
278         gchar *full_name;
279
280         if (!vtable->init_failed)
281                 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
282         
283         /* 
284          * If the initializing thread was rudely aborted, the exception is not stored
285          * in the hash.
286          */
287         ex = NULL;
288         mono_domain_lock (domain);
289         if (domain->type_init_exception_hash)
290                 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
291         mono_domain_unlock (domain);
292
293         if (!ex) {
294                 if (klass->name_space && *klass->name_space)
295                         full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
296                 else
297                         full_name = g_strdup (klass->name);
298                 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
299                 g_free (full_name);
300                 return_val_if_nok (&error, NULL);
301         }
302
303         return ex;
304 }
305
306 /**
307  * mono_runtime_class_init:
308  * \param vtable vtable that needs to be initialized
309  * This routine calls the class constructor for \p vtable.
310  */
311 void
312 mono_runtime_class_init (MonoVTable *vtable)
313 {
314         MONO_REQ_GC_UNSAFE_MODE;
315         MonoError error;
316
317         mono_runtime_class_init_full (vtable, &error);
318         mono_error_assert_ok (&error);
319 }
320
321 /*
322  * Returns TRUE if the lock was freed.
323  * LOCKING: Caller should hold type_initialization_lock.
324  */
325 static gboolean
326 unref_type_lock (TypeInitializationLock *lock)
327 {
328         --lock->waiting_count;
329         if (lock->waiting_count == 0) {
330                 mono_coop_mutex_destroy (&lock->mutex);
331                 mono_coop_cond_destroy (&lock->cond);
332                 g_free (lock);
333                 return TRUE;
334         } else {
335                 return FALSE;
336         }
337 }
338
339 /**
340  * mono_runtime_class_init_full:
341  * \param vtable that neeeds to be initialized
342  * \param error set on error
343  * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
344  */
345 gboolean
346 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
347 {
348         MONO_REQ_GC_UNSAFE_MODE;
349
350         MonoMethod *method = NULL;
351         MonoClass *klass;
352         gchar *full_name;
353         MonoDomain *domain = vtable->domain;
354         TypeInitializationLock *lock;
355         MonoNativeThreadId tid;
356         int do_initialization = 0;
357         MonoDomain *last_domain = NULL;
358         gboolean pending_tae = FALSE;
359
360         error_init (error);
361
362         if (vtable->initialized)
363                 return TRUE;
364
365         klass = vtable->klass;
366
367         if (!klass->image->checked_module_cctor) {
368                 mono_image_check_for_module_cctor (klass->image);
369                 if (klass->image->has_module_cctor) {
370                         MonoClass *module_klass;
371                         MonoVTable *module_vtable;
372
373                         module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
374                         if (!module_klass) {
375                                 return FALSE;
376                         }
377                                 
378                         module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
379                         if (!module_vtable)
380                                 return FALSE;
381                         if (!mono_runtime_class_init_full (module_vtable, error))
382                                 return FALSE;
383                 }
384         }
385         method = mono_class_get_cctor (klass);
386         if (!method) {
387                 vtable->initialized = 1;
388                 return TRUE;
389         }
390
391         tid = mono_native_thread_id_get ();
392
393         /*
394          * Due some preprocessing inside a global lock. If we are the first thread
395          * trying to initialize this class, create a separate lock+cond var, and
396          * acquire it before leaving the global lock. The other threads will wait
397          * on this cond var.
398          */
399
400         mono_type_initialization_lock ();
401         /* double check... */
402         if (vtable->initialized) {
403                 mono_type_initialization_unlock ();
404                 return TRUE;
405         }
406         if (vtable->init_failed) {
407                 mono_type_initialization_unlock ();
408
409                 /* The type initialization already failed once, rethrow the same exception */
410                 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
411                 return FALSE;
412         }
413         lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
414         if (lock == NULL) {
415                 /* This thread will get to do the initialization */
416                 if (mono_domain_get () != domain) {
417                         /* Transfer into the target domain */
418                         last_domain = mono_domain_get ();
419                         if (!mono_domain_set (domain, FALSE)) {
420                                 vtable->initialized = 1;
421                                 mono_type_initialization_unlock ();
422                                 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
423                                 return FALSE;
424                         }
425                 }
426                 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
427                 mono_coop_mutex_init_recursive (&lock->mutex);
428                 mono_coop_cond_init (&lock->cond);
429                 lock->initializing_tid = tid;
430                 lock->waiting_count = 1;
431                 lock->done = FALSE;
432                 g_hash_table_insert (type_initialization_hash, vtable, lock);
433                 do_initialization = 1;
434         } else {
435                 gpointer blocked;
436                 TypeInitializationLock *pending_lock;
437
438                 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
439                         mono_type_initialization_unlock ();
440                         return TRUE;
441                 }
442                 /* see if the thread doing the initialization is already blocked on this thread */
443                 gboolean is_blocked = TRUE;
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                                         is_blocked = FALSE;
455                                         break;
456                                 }
457                         }
458                         blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
459                 }
460                 ++lock->waiting_count;
461                 /* record the fact that we are waiting on the initializing thread */
462                 if (is_blocked)
463                         g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
464         }
465         mono_type_initialization_unlock ();
466
467         if (do_initialization) {
468                 MonoException *exc = NULL;
469
470                 /* We are holding the per-vtable lock, do the actual initialization */
471
472                 mono_threads_begin_abort_protected_block ();
473                 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
474                 mono_threads_end_abort_protected_block ();
475
476                 //exception extracted, error will be set to the right value later
477                 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
478                         exc = mono_error_convert_to_exception (error);
479                 else
480                         mono_error_cleanup (error);
481
482                 error_init (error);
483
484                 /* If the initialization failed, mark the class as unusable. */
485                 /* Avoid infinite loops */
486                 if (!(!exc ||
487                           (klass->image == mono_defaults.corlib &&
488                            !strcmp (klass->name_space, "System") &&
489                            !strcmp (klass->name, "TypeInitializationException")))) {
490                         vtable->init_failed = 1;
491
492                         if (klass->name_space && *klass->name_space)
493                                 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
494                         else
495                                 full_name = g_strdup (klass->name);
496
497                         MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
498                         g_free (full_name);
499
500                         mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
501
502                         /*
503                          * Store the exception object so it could be thrown on subsequent
504                          * accesses.
505                          */
506                         mono_domain_lock (domain);
507                         if (!domain->type_init_exception_hash)
508                                 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");
509                         mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
510                         mono_domain_unlock (domain);
511                 }
512
513                 if (last_domain)
514                         mono_domain_set (last_domain, TRUE);
515
516                 /* Signal to the other threads that we are done */
517                 mono_type_init_lock (lock);
518                 lock->done = TRUE;
519                 mono_coop_cond_broadcast (&lock->cond);
520                 mono_type_init_unlock (lock);
521
522                 /*
523                  * This can happen if the cctor self-aborts. We need to reactivate tae
524                  * (next interruption checkpoint will throw it) and make sure we won't
525                  * throw tie for the type.
526                  */
527                 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
528                         pending_tae = TRUE;
529                         mono_thread_resume_interruption (FALSE);
530                 }
531         } else {
532                 /* this just blocks until the initializing thread is done */
533                 mono_type_init_lock (lock);
534                 while (!lock->done)
535                         mono_coop_cond_wait (&lock->cond, &lock->mutex);
536                 mono_type_init_unlock (lock);
537         }
538
539         /* Do cleanup and setting vtable->initialized inside the global lock again */
540         mono_type_initialization_lock ();
541         if (!do_initialization)
542                 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
543         gboolean deleted = unref_type_lock (lock);
544         if (deleted)
545                 g_hash_table_remove (type_initialization_hash, vtable);
546         /* Have to set this here since we check it inside the global lock */
547         if (do_initialization && !vtable->init_failed)
548                 vtable->initialized = 1;
549         mono_type_initialization_unlock ();
550
551         /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
552         if (vtable->init_failed && !pending_tae) {
553                 /* Either we were the initializing thread or we waited for the initialization */
554                 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
555                 return FALSE;
556         }
557         return TRUE;
558 }
559
560 static
561 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
562 {
563         MONO_REQ_GC_NEUTRAL_MODE;
564
565         MonoVTable *vtable = (MonoVTable*)key;
566
567         TypeInitializationLock *lock = (TypeInitializationLock*) value;
568         if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
569                 lock->done = TRUE;
570                 /* 
571                  * Have to set this since it cannot be set by the normal code in 
572                  * mono_runtime_class_init (). In this case, the exception object is not stored,
573                  * and get_type_init_exception_for_class () needs to be aware of this.
574                  */
575                 mono_type_init_lock (lock);
576                 vtable->init_failed = 1;
577                 mono_coop_cond_broadcast (&lock->cond);
578                 mono_type_init_unlock (lock);
579                 gboolean deleted = unref_type_lock (lock);
580                 if (deleted)
581                         return TRUE;
582         }
583         return FALSE;
584 }
585
586 void
587 mono_release_type_locks (MonoInternalThread *thread)
588 {
589         MONO_REQ_GC_UNSAFE_MODE;
590
591         mono_type_initialization_lock ();
592         g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
593         mono_type_initialization_unlock ();
594 }
595
596 #ifndef DISABLE_REMOTING
597
598 static gpointer
599 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
600 {
601         if (!callbacks.create_remoting_trampoline)
602                 g_error ("remoting not installed");
603         return callbacks.create_remoting_trampoline (domain, method, target, error);
604 }
605
606 #endif
607
608 static MonoImtTrampolineBuilder imt_trampoline_builder;
609 static gboolean always_build_imt_trampolines;
610
611 #if (MONO_IMT_SIZE > 32)
612 #error "MONO_IMT_SIZE cannot be larger than 32"
613 #endif
614
615 void
616 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
617 {
618         memcpy (&callbacks, cbs, sizeof (*cbs));
619 }
620
621 MonoRuntimeCallbacks*
622 mono_get_runtime_callbacks (void)
623 {
624         return &callbacks;
625 }
626
627 void
628 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
629 {
630         imt_trampoline_builder = func;
631 }
632
633 void
634 mono_set_always_build_imt_trampolines (gboolean value)
635 {
636         always_build_imt_trampolines = value;
637 }
638
639 /**
640  * mono_compile_method:
641  * \param method The method to compile.
642  * This JIT-compiles the method, and returns the pointer to the native code
643  * produced.
644  */
645 gpointer 
646 mono_compile_method (MonoMethod *method)
647 {
648         MonoError error;
649         gpointer result = mono_compile_method_checked (method, &error);
650         mono_error_cleanup (&error);
651         return result;
652 }
653
654 /**
655  * mono_compile_method_checked:
656  * \param method The method to compile.
657  * \param 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 \p error.
660  */
661 gpointer
662 mono_compile_method_checked (MonoMethod *method, MonoError *error)
663 {
664         gpointer res;
665
666         MONO_REQ_GC_NEUTRAL_MODE
667
668         error_init (error);
669
670         g_assert (callbacks.compile_method);
671         res = callbacks.compile_method (method, error);
672         return res;
673 }
674
675 gpointer
676 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
677 {
678         gpointer res;
679
680         MONO_REQ_GC_NEUTRAL_MODE;
681
682         error_init (error);
683         res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
684         return res;
685 }
686
687 gpointer
688 mono_runtime_create_delegate_trampoline (MonoClass *klass)
689 {
690         MONO_REQ_GC_NEUTRAL_MODE
691
692         g_assert (callbacks.create_delegate_trampoline);
693         return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
694 }
695
696 /**
697  * mono_runtime_free_method:
698  * \param domain domain where the method is hosted
699  * \param method method to release
700  * This routine is invoked to free the resources associated with
701  * a method that has been JIT compiled.  This is used to discard
702  * methods that were used only temporarily (for example, used in marshalling)
703  */
704 void
705 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
706 {
707         MONO_REQ_GC_NEUTRAL_MODE
708
709         if (callbacks.free_method)
710                 callbacks.free_method (domain, method);
711
712         mono_method_clear_object (domain, method);
713
714         mono_free_method (method);
715 }
716
717 /*
718  * The vtables in the root appdomain are assumed to be reachable by other 
719  * roots, and we don't use typed allocation in the other domains.
720  */
721
722 /* The sync block is no longer a GC pointer */
723 #define GC_HEADER_BITMAP (0)
724
725 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
726
727 static gsize*
728 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
729 {
730         MONO_REQ_GC_NEUTRAL_MODE;
731
732         MonoClassField *field;
733         MonoClass *p;
734         guint32 pos;
735         int max_size;
736
737         if (static_fields)
738                 max_size = mono_class_data_size (klass) / sizeof (gpointer);
739         else
740                 max_size = klass->instance_size / sizeof (gpointer);
741         if (max_size > size) {
742                 g_assert (offset <= 0);
743                 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
744                 size = max_size;
745         }
746
747         /* An Ephemeron cannot be marked by sgen */
748         if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
749                 *max_set = 0;
750                 memset (bitmap, 0, size / 8);
751                 return bitmap;
752         }
753
754         for (p = klass; p != NULL; p = p->parent) {
755                 gpointer iter = NULL;
756                 while ((field = mono_class_get_fields (p, &iter))) {
757                         MonoType *type;
758
759                         if (static_fields) {
760                                 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
761                                         continue;
762                                 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
763                                         continue;
764                         } else {
765                                 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
766                                         continue;
767                         }
768                         /* FIXME: should not happen, flag as type load error */
769                         if (field->type->byref)
770                                 break;
771
772                         if (static_fields && field->offset == -1)
773                                 /* special static */
774                                 continue;
775
776                         pos = field->offset / sizeof (gpointer);
777                         pos += offset;
778
779                         type = mono_type_get_underlying_type (field->type);
780                         switch (type->type) {
781                         case MONO_TYPE_U:
782                         case MONO_TYPE_I:
783                         case MONO_TYPE_PTR:
784                         case MONO_TYPE_FNPTR:
785                                 break;
786                         case MONO_TYPE_STRING:
787                         case MONO_TYPE_SZARRAY:
788                         case MONO_TYPE_CLASS:
789                         case MONO_TYPE_OBJECT:
790                         case MONO_TYPE_ARRAY:
791                                 g_assert ((field->offset % sizeof(gpointer)) == 0);
792
793                                 g_assert (pos < size || pos <= max_size);
794                                 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795                                 *max_set = MAX (*max_set, pos);
796                                 break;
797                         case MONO_TYPE_GENERICINST:
798                                 if (!mono_type_generic_inst_is_valuetype (type)) {
799                                         g_assert ((field->offset % sizeof(gpointer)) == 0);
800
801                                         bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
802                                         *max_set = MAX (*max_set, pos);
803                                         break;
804                                 } else {
805                                         /* fall through */
806                                 }
807                         case MONO_TYPE_VALUETYPE: {
808                                 MonoClass *fclass = mono_class_from_mono_type (field->type);
809                                 if (fclass->has_references) {
810                                         /* remove the object header */
811                                         compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
812                                 }
813                                 break;
814                         }
815                         case MONO_TYPE_I1:
816                         case MONO_TYPE_U1:
817                         case MONO_TYPE_I2:
818                         case MONO_TYPE_U2:
819                         case MONO_TYPE_I4:
820                         case MONO_TYPE_U4:
821                         case MONO_TYPE_I8:
822                         case MONO_TYPE_U8:
823                         case MONO_TYPE_R4:
824                         case MONO_TYPE_R8:
825                         case MONO_TYPE_BOOLEAN:
826                         case MONO_TYPE_CHAR:
827                                 break;
828                         default:
829                                 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
830                                 break;
831                         }
832                 }
833                 if (static_fields)
834                         break;
835         }
836         return bitmap;
837 }
838
839 /**
840  * mono_class_compute_bitmap:
841  *
842  * Mono internal function to compute a bitmap of reference fields in a class.
843  */
844 gsize*
845 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
846 {
847         MONO_REQ_GC_NEUTRAL_MODE;
848
849         return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
850 }
851
852 #if 0
853 /* 
854  * similar to the above, but sets the bits in the bitmap for any non-ref field
855  * and ignores static fields
856  */
857 static gsize*
858 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
859 {
860         MonoClassField *field;
861         MonoClass *p;
862         guint32 pos, pos2;
863         int max_size;
864
865         max_size = class->instance_size / sizeof (gpointer);
866         if (max_size >= size) {
867                 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
868         }
869
870         for (p = class; p != NULL; p = p->parent) {
871                 gpointer iter = NULL;
872                 while ((field = mono_class_get_fields (p, &iter))) {
873                         MonoType *type;
874
875                         if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
876                                 continue;
877                         /* FIXME: should not happen, flag as type load error */
878                         if (field->type->byref)
879                                 break;
880
881                         pos = field->offset / sizeof (gpointer);
882                         pos += offset;
883
884                         type = mono_type_get_underlying_type (field->type);
885                         switch (type->type) {
886 #if SIZEOF_VOID_P == 8
887                         case MONO_TYPE_I:
888                         case MONO_TYPE_U:
889                         case MONO_TYPE_PTR:
890                         case MONO_TYPE_FNPTR:
891 #endif
892                         case MONO_TYPE_I8:
893                         case MONO_TYPE_U8:
894                         case MONO_TYPE_R8:
895                                 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
896                                         pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
897                                         bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
898                                 }
899                                 /* fall through */
900 #if SIZEOF_VOID_P == 4
901                         case MONO_TYPE_I:
902                         case MONO_TYPE_U:
903                         case MONO_TYPE_PTR:
904                         case MONO_TYPE_FNPTR:
905 #endif
906                         case MONO_TYPE_I4:
907                         case MONO_TYPE_U4:
908                         case MONO_TYPE_R4:
909                                 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
910                                         pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
911                                         bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
912                                 }
913                                 /* fall through */
914                         case MONO_TYPE_CHAR:
915                         case MONO_TYPE_I2:
916                         case MONO_TYPE_U2:
917                                 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
918                                         pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
919                                         bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
920                                 }
921                                 /* fall through */
922                         case MONO_TYPE_BOOLEAN:
923                         case MONO_TYPE_I1:
924                         case MONO_TYPE_U1:
925                                 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
926                                 break;
927                         case MONO_TYPE_STRING:
928                         case MONO_TYPE_SZARRAY:
929                         case MONO_TYPE_CLASS:
930                         case MONO_TYPE_OBJECT:
931                         case MONO_TYPE_ARRAY:
932                                 break;
933                         case MONO_TYPE_GENERICINST:
934                                 if (!mono_type_generic_inst_is_valuetype (type)) {
935                                         break;
936                                 } else {
937                                         /* fall through */
938                                 }
939                         case MONO_TYPE_VALUETYPE: {
940                                 MonoClass *fclass = mono_class_from_mono_type (field->type);
941                                 /* remove the object header */
942                                 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
943                                 break;
944                         }
945                         default:
946                                 g_assert_not_reached ();
947                                 break;
948                         }
949                 }
950         }
951         return bitmap;
952 }
953
954 /**
955  * mono_class_insecure_overlapping:
956  * check if a class with explicit layout has references and non-references
957  * fields overlapping.
958  *
959  * Returns: TRUE if it is insecure to load the type.
960  */
961 gboolean
962 mono_class_insecure_overlapping (MonoClass *klass)
963 {
964         int max_set = 0;
965         gsize *bitmap;
966         gsize default_bitmap [4] = {0};
967         gsize *nrbitmap;
968         gsize default_nrbitmap [4] = {0};
969         int i, insecure = FALSE;
970                 return FALSE;
971
972         bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
973         nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
974
975         for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
976                 int idx = i % (sizeof (bitmap [0]) * 8);
977                 if (bitmap [idx] & nrbitmap [idx]) {
978                         insecure = TRUE;
979                         break;
980                 }
981         }
982         if (bitmap != default_bitmap)
983                 g_free (bitmap);
984         if (nrbitmap != default_nrbitmap)
985                 g_free (nrbitmap);
986         if (insecure) {
987                 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
988                 return FALSE;
989         }
990         return insecure;
991 }
992 #endif
993
994 MonoString*
995 ves_icall_string_alloc (int length)
996 {
997         MonoError error;
998         MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
999         mono_error_set_pending_exception (&error);
1000
1001         return str;
1002 }
1003
1004 /* LOCKING: Acquires the loader lock */
1005 void
1006 mono_class_compute_gc_descriptor (MonoClass *klass)
1007 {
1008         MONO_REQ_GC_NEUTRAL_MODE;
1009
1010         int max_set = 0;
1011         gsize *bitmap;
1012         gsize default_bitmap [4] = {0};
1013         MonoGCDescriptor gc_descr;
1014
1015         if (!klass->inited)
1016                 mono_class_init (klass);
1017
1018         if (klass->gc_descr_inited)
1019                 return;
1020
1021         bitmap = default_bitmap;
1022         if (klass == mono_defaults.string_class) {
1023                 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1024         } else if (klass->rank) {
1025                 mono_class_compute_gc_descriptor (klass->element_class);
1026                 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1027                         gsize abm = 1;
1028                         gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1029                         /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1030                                 class->name_space, class->name);*/
1031                 } else {
1032                         /* remove the object header */
1033                         bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1034                         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));
1035                         /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1036                                 class->name_space, class->name);*/
1037                         if (bitmap != default_bitmap)
1038                                 g_free (bitmap);
1039                 }
1040         } else {
1041                 /*static int count = 0;
1042                 if (count++ > 58)
1043                         return;*/
1044                 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1045                 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1046                 /*
1047                 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1048                         g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1049                 */
1050                 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1051                 if (bitmap != default_bitmap)
1052                         g_free (bitmap);
1053         }
1054
1055         /* Publish the data */
1056         mono_loader_lock ();
1057         klass->gc_descr = gc_descr;
1058         mono_memory_barrier ();
1059         klass->gc_descr_inited = TRUE;
1060         mono_loader_unlock ();
1061 }
1062
1063 /**
1064  * field_is_special_static:
1065  * @fklass: The MonoClass to look up.
1066  * @field: The MonoClassField describing the field.
1067  *
1068  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1069  * SPECIAL_STATIC_NONE otherwise.
1070  */
1071 static gint32
1072 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1073 {
1074         MONO_REQ_GC_NEUTRAL_MODE;
1075
1076         MonoError error;
1077         MonoCustomAttrInfo *ainfo;
1078         int i;
1079         ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1080         mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1081         if (!ainfo)
1082                 return FALSE;
1083         for (i = 0; i < ainfo->num_attrs; ++i) {
1084                 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1085                 if (klass->image == mono_defaults.corlib) {
1086                         if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1087                                 mono_custom_attrs_free (ainfo);
1088                                 return SPECIAL_STATIC_THREAD;
1089                         }
1090                         else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1091                                 mono_custom_attrs_free (ainfo);
1092                                 return SPECIAL_STATIC_CONTEXT;
1093                         }
1094                 }
1095         }
1096         mono_custom_attrs_free (ainfo);
1097         return SPECIAL_STATIC_NONE;
1098 }
1099
1100 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1101 #define mix(a,b,c) { \
1102         a -= c;  a ^= rot(c, 4);  c += b; \
1103         b -= a;  b ^= rot(a, 6);  a += c; \
1104         c -= b;  c ^= rot(b, 8);  b += a; \
1105         a -= c;  a ^= rot(c,16);  c += b; \
1106         b -= a;  b ^= rot(a,19);  a += c; \
1107         c -= b;  c ^= rot(b, 4);  b += a; \
1108 }
1109 #define final(a,b,c) { \
1110         c ^= b; c -= rot(b,14); \
1111         a ^= c; a -= rot(c,11); \
1112         b ^= a; b -= rot(a,25); \
1113         c ^= b; c -= rot(b,16); \
1114         a ^= c; a -= rot(c,4);  \
1115         b ^= a; b -= rot(a,14); \
1116         c ^= b; c -= rot(b,24); \
1117 }
1118
1119 /*
1120  * mono_method_get_imt_slot:
1121  *
1122  *   The IMT slot is embedded into AOTed code, so this must return the same value
1123  * for the same method across all executions. This means:
1124  * - pointers shouldn't be used as hash values.
1125  * - mono_metadata_str_hash () should be used for hashing strings.
1126  */
1127 guint32
1128 mono_method_get_imt_slot (MonoMethod *method)
1129 {
1130         MONO_REQ_GC_NEUTRAL_MODE;
1131
1132         MonoMethodSignature *sig;
1133         int hashes_count;
1134         guint32 *hashes_start, *hashes;
1135         guint32 a, b, c;
1136         int i;
1137
1138         /* This can be used to stress tests the collision code */
1139         //return 0;
1140
1141         /*
1142          * We do this to simplify generic sharing.  It will hurt
1143          * performance in cases where a class implements two different
1144          * instantiations of the same generic interface.
1145          * The code in build_imt_slots () depends on this.
1146          */
1147         if (method->is_inflated)
1148                 method = ((MonoMethodInflated*)method)->declaring;
1149
1150         sig = mono_method_signature (method);
1151         hashes_count = sig->param_count + 4;
1152         hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1153         hashes = hashes_start;
1154
1155         if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1156                 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1157                                 method->klass->name_space, method->klass->name, method->name);
1158         }
1159         
1160         /* Initialize hashes */
1161         hashes [0] = mono_metadata_str_hash (method->klass->name);
1162         hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1163         hashes [2] = mono_metadata_str_hash (method->name);
1164         hashes [3] = mono_metadata_type_hash (sig->ret);
1165         for (i = 0; i < sig->param_count; i++) {
1166                 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1167         }
1168
1169         /* Setup internal state */
1170         a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1171
1172         /* Handle most of the hashes */
1173         while (hashes_count > 3) {
1174                 a += hashes [0];
1175                 b += hashes [1];
1176                 c += hashes [2];
1177                 mix (a,b,c);
1178                 hashes_count -= 3;
1179                 hashes += 3;
1180         }
1181
1182         /* Handle the last 3 hashes (all the case statements fall through) */
1183         switch (hashes_count) { 
1184         case 3 : c += hashes [2];
1185         case 2 : b += hashes [1];
1186         case 1 : a += hashes [0];
1187                 final (a,b,c);
1188         case 0: /* nothing left to add */
1189                 break;
1190         }
1191         
1192         g_free (hashes_start);
1193         /* Report the result */
1194         return c % MONO_IMT_SIZE;
1195 }
1196 #undef rot
1197 #undef mix
1198 #undef final
1199
1200 #define DEBUG_IMT 0
1201
1202 static void
1203 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1204         MONO_REQ_GC_NEUTRAL_MODE;
1205
1206         guint32 imt_slot = mono_method_get_imt_slot (method);
1207         MonoImtBuilderEntry *entry;
1208
1209         if (slot_num >= 0 && imt_slot != slot_num) {
1210                 /* we build just a single imt slot and this is not it */
1211                 return;
1212         }
1213
1214         entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1215         entry->key = method;
1216         entry->value.vtable_slot = vtable_slot;
1217         entry->next = imt_builder [imt_slot];
1218         if (imt_builder [imt_slot] != NULL) {
1219                 entry->children = imt_builder [imt_slot]->children + 1;
1220                 if (entry->children == 1) {
1221                         UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1222                         *imt_collisions_bitmap |= (1 << imt_slot);
1223                 }
1224         } else {
1225                 entry->children = 0;
1226                 UnlockedIncrement (&mono_stats.imt_used_slots);
1227         }
1228         imt_builder [imt_slot] = entry;
1229 #if DEBUG_IMT
1230         {
1231         char *method_name = mono_method_full_name (method, TRUE);
1232         printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1233                         method, method_name, imt_slot, vtable_slot, entry->children);
1234         g_free (method_name);
1235         }
1236 #endif
1237 }
1238
1239 #if DEBUG_IMT
1240 static void
1241 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1242         if (e != NULL) {
1243                 MonoMethod *method = e->key;
1244                 printf ("  * %s [%d]: (%p) '%s.%s.%s'\n",
1245                                 message,
1246                                 num,
1247                                 method,
1248                                 method->klass->name_space,
1249                                 method->klass->name,
1250                                 method->name);
1251         } else {
1252                 printf ("  * %s: NULL\n", message);
1253         }
1254 }
1255 #endif
1256
1257 static int
1258 compare_imt_builder_entries (const void *p1, const void *p2) {
1259         MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1260         MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1261         
1262         return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1263 }
1264
1265 static int
1266 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1267 {
1268         MONO_REQ_GC_NEUTRAL_MODE;
1269
1270         int count = end - start;
1271         int chunk_start = out_array->len;
1272         if (count < 4) {
1273                 int i;
1274                 for (i = start; i < end; ++i) {
1275                         MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1276                         item->key = sorted_array [i]->key;
1277                         item->value = sorted_array [i]->value;
1278                         item->has_target_code = sorted_array [i]->has_target_code;
1279                         item->is_equals = TRUE;
1280                         if (i < end - 1)
1281                                 item->check_target_idx = out_array->len + 1;
1282                         else
1283                                 item->check_target_idx = 0;
1284                         g_ptr_array_add (out_array, item);
1285                 }
1286         } else {
1287                 int middle = start + count / 2;
1288                 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1289
1290                 item->key = sorted_array [middle]->key;
1291                 item->is_equals = FALSE;
1292                 g_ptr_array_add (out_array, item);
1293                 imt_emit_ir (sorted_array, start, middle, out_array);
1294                 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1295         }
1296         return chunk_start;
1297 }
1298
1299 static GPtrArray*
1300 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1301         MONO_REQ_GC_NEUTRAL_MODE;
1302
1303         int number_of_entries = entries->children + 1;
1304         MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1305         GPtrArray *result = g_ptr_array_new ();
1306         MonoImtBuilderEntry *current_entry;
1307         int i;
1308         
1309         for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1310                 sorted_array [i] = current_entry;
1311         }
1312         qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1313
1314         /*for (i = 0; i < number_of_entries; i++) {
1315                 print_imt_entry (" sorted array:", sorted_array [i], i);
1316         }*/
1317
1318         imt_emit_ir (sorted_array, 0, number_of_entries, result);
1319
1320         g_free (sorted_array);
1321         return result;
1322 }
1323
1324 static gpointer
1325 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1326 {
1327         MONO_REQ_GC_NEUTRAL_MODE;
1328
1329         if (imt_builder_entry != NULL) {
1330                 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1331                         /* No collision, return the vtable slot contents */
1332                         return vtable->vtable [imt_builder_entry->value.vtable_slot];
1333                 } else {
1334                         /* Collision, build the trampoline */
1335                         GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1336                         gpointer result;
1337                         int i;
1338                         result = imt_trampoline_builder (vtable, domain,
1339                                 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1340                         for (i = 0; i < imt_ir->len; ++i)
1341                                 g_free (g_ptr_array_index (imt_ir, i));
1342                         g_ptr_array_free (imt_ir, TRUE);
1343                         return result;
1344                 }
1345         } else {
1346                 if (fail_tramp)
1347                         return fail_tramp;
1348                 else
1349                         /* Empty slot */
1350                         return NULL;
1351         }
1352 }
1353
1354 static MonoImtBuilderEntry*
1355 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1356
1357 /*
1358  * LOCKING: requires the loader and domain locks.
1359  *
1360 */
1361 static void
1362 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1363 {
1364         MONO_REQ_GC_NEUTRAL_MODE;
1365
1366         int i;
1367         GSList *list_item;
1368         guint32 imt_collisions_bitmap = 0;
1369         MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1370         int method_count = 0;
1371         gboolean record_method_count_for_max_collisions = FALSE;
1372         gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1373
1374 #if DEBUG_IMT
1375         printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1376 #endif
1377         for (i = 0; i < klass->interface_offsets_count; ++i) {
1378                 MonoClass *iface = klass->interfaces_packed [i];
1379                 int interface_offset = klass->interface_offsets_packed [i];
1380                 int method_slot_in_interface, vt_slot;
1381
1382                 if (mono_class_has_variant_generic_params (iface))
1383                         has_variant_iface = TRUE;
1384
1385                 mono_class_setup_methods (iface);
1386                 vt_slot = interface_offset;
1387                 int mcount = mono_class_get_method_count (iface);
1388                 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1389                         MonoMethod *method;
1390
1391                         if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1392                                 /*
1393                                  * The imt slot of the method is the same as for its declaring method,
1394                                  * see the comment in mono_method_get_imt_slot (), so we can
1395                                  * avoid inflating methods which will be discarded by 
1396                                  * add_imt_builder_entry anyway.
1397                                  */
1398                                 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1399                                 if (mono_method_get_imt_slot (method) != slot_num) {
1400                                         vt_slot ++;
1401                                         continue;
1402                                 }
1403                         }
1404                         method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1405                         if (method->is_generic) {
1406                                 has_generic_virtual = TRUE;
1407                                 vt_slot ++;
1408                                 continue;
1409                         }
1410
1411                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1412                                 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1413                                 vt_slot ++;
1414                         }
1415                 }
1416         }
1417         if (extra_interfaces) {
1418                 int interface_offset = klass->vtable_size;
1419
1420                 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1421                         MonoClass* iface = (MonoClass *)list_item->data;
1422                         int method_slot_in_interface;
1423                         int mcount = mono_class_get_method_count (iface);
1424                         for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1425                                 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1426
1427                                 if (method->is_generic)
1428                                         has_generic_virtual = TRUE;
1429                                 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1430                         }
1431                         interface_offset += mcount;
1432                 }
1433         }
1434         for (i = 0; i < MONO_IMT_SIZE; ++i) {
1435                 /* overwrite the imt slot only if we're building all the entries or if 
1436                  * we're building this specific one
1437                  */
1438                 if (slot_num < 0 || i == slot_num) {
1439                         MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1440
1441                         if (entries) {
1442                                 if (imt_builder [i]) {
1443                                         MonoImtBuilderEntry *entry;
1444
1445                                         /* Link entries with imt_builder [i] */
1446                                         for (entry = entries; entry->next; entry = entry->next) {
1447 #if DEBUG_IMT
1448                                                 MonoMethod *method = (MonoMethod*)entry->key;
1449                                                 char *method_name = mono_method_full_name (method, TRUE);
1450                                                 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1451                                                 g_free (method_name);
1452 #endif
1453                                         }
1454                                         entry->next = imt_builder [i];
1455                                         entries->children += imt_builder [i]->children + 1;
1456                                 }
1457                                 imt_builder [i] = entries;
1458                         }
1459
1460                         if (has_generic_virtual || has_variant_iface) {
1461                                 /*
1462                                  * There might be collisions later when the the trampoline is expanded.
1463                                  */
1464                                 imt_collisions_bitmap |= (1 << i);
1465
1466                                 /* 
1467                                  * The IMT trampoline might be called with an instance of one of the 
1468                                  * generic virtual methods, so has to fallback to the IMT trampoline.
1469                                  */
1470                                 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1471                         } else {
1472                                 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1473                         }
1474 #if DEBUG_IMT
1475                         printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1476 #endif
1477                 }
1478
1479                 if (imt_builder [i] != NULL) {
1480                         int methods_in_slot = imt_builder [i]->children + 1;
1481                         if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1482                                 UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1483                                 record_method_count_for_max_collisions = TRUE;
1484                         }
1485                         method_count += methods_in_slot;
1486                 }
1487         }
1488         
1489         UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1490         if (record_method_count_for_max_collisions) {
1491                 UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1492         }
1493         
1494         for (i = 0; i < MONO_IMT_SIZE; i++) {
1495                 MonoImtBuilderEntry* entry = imt_builder [i];
1496                 while (entry != NULL) {
1497                         MonoImtBuilderEntry* next = entry->next;
1498                         g_free (entry);
1499                         entry = next;
1500                 }
1501         }
1502         g_free (imt_builder);
1503         /* we OR the bitmap since we may build just a single imt slot at a time */
1504         vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1505 }
1506
1507 static void
1508 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1509         MONO_REQ_GC_NEUTRAL_MODE;
1510
1511         build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1512 }
1513
1514 /**
1515  * mono_vtable_build_imt_slot:
1516  * \param vtable virtual object table struct
1517  * \param imt_slot slot in the IMT table
1518  * Fill the given \p imt_slot in the IMT table of \p vtable with
1519  * a trampoline or a trampoline for the case of collisions.
1520  * This is part of the internal mono API.
1521  * LOCKING: Take the domain lock.
1522  */
1523 void
1524 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1525 {
1526         MONO_REQ_GC_NEUTRAL_MODE;
1527
1528         gpointer *imt = (gpointer*)vtable;
1529         imt -= MONO_IMT_SIZE;
1530         g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1531
1532         /* no support for extra interfaces: the proxy objects will need
1533          * to build the complete IMT
1534          * Update and heck needs to ahppen inside the proper domain lock, as all
1535          * the changes made to a MonoVTable.
1536          */
1537         mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1538         mono_domain_lock (vtable->domain);
1539         /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1540         if (!callbacks.imt_entry_inited (vtable, imt_slot))
1541                 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1542         mono_domain_unlock (vtable->domain);
1543         mono_loader_unlock ();
1544 }
1545
1546 #define THUNK_THRESHOLD         10
1547
1548 /**
1549  * mono_method_alloc_generic_virtual_trampoline:
1550  * \param domain a domain
1551  * \param size size in bytes
1552  * Allocs \p size bytes to be used for the code of a generic virtual
1553  * trampoline.  It's either allocated from the domain's code manager or
1554  * reused from a previously invalidated piece.
1555  * LOCKING: The domain lock must be held.
1556  */
1557 gpointer
1558 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1559 {
1560         MONO_REQ_GC_NEUTRAL_MODE;
1561
1562         static gboolean inited = FALSE;
1563         static int generic_virtual_trampolines_size = 0;
1564
1565         if (!inited) {
1566                 mono_counters_register ("Generic virtual trampoline bytes",
1567                                 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1568                 inited = TRUE;
1569         }
1570         generic_virtual_trampolines_size += size;
1571
1572         return mono_domain_code_reserve (domain, size);
1573 }
1574
1575 typedef struct _GenericVirtualCase {
1576         MonoMethod *method;
1577         gpointer code;
1578         int count;
1579         struct _GenericVirtualCase *next;
1580 } GenericVirtualCase;
1581
1582 /*
1583  * get_generic_virtual_entries:
1584  *
1585  *   Return IMT entries for the generic virtual method instances and
1586  *   variant interface methods for vtable slot
1587  * VTABLE_SLOT.
1588  */ 
1589 static MonoImtBuilderEntry*
1590 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1591 {
1592         MONO_REQ_GC_NEUTRAL_MODE;
1593
1594         GenericVirtualCase *list;
1595         MonoImtBuilderEntry *entries;
1596   
1597         mono_domain_lock (domain);
1598         if (!domain->generic_virtual_cases)
1599                 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1600  
1601         list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1602  
1603         entries = NULL;
1604         for (; list; list = list->next) {
1605                 MonoImtBuilderEntry *entry;
1606  
1607                 if (list->count < THUNK_THRESHOLD)
1608                         continue;
1609  
1610                 entry = g_new0 (MonoImtBuilderEntry, 1);
1611                 entry->key = list->method;
1612                 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1613                 entry->has_target_code = 1;
1614                 if (entries)
1615                         entry->children = entries->children + 1;
1616                 entry->next = entries;
1617                 entries = entry;
1618         }
1619  
1620         mono_domain_unlock (domain);
1621  
1622         /* FIXME: Leaking memory ? */
1623         return entries;
1624 }
1625
1626 /**
1627  * \param domain a domain
1628  * \param vtable_slot pointer to the vtable slot
1629  * \param method the inflated generic virtual method
1630  * \param code the method's code
1631  *
1632  * Registers a call via unmanaged code to a generic virtual method
1633  * instantiation or variant interface method.  If the number of calls reaches a threshold
1634  * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1635  * virtual method trampoline.
1636  */
1637 void
1638 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1639                                                                                         gpointer *vtable_slot,
1640                                                                                         MonoMethod *method, gpointer code)
1641 {
1642         MONO_REQ_GC_NEUTRAL_MODE;
1643
1644         static gboolean inited = FALSE;
1645         static int num_added = 0;
1646         static int num_freed = 0;
1647
1648         GenericVirtualCase *gvc, *list;
1649         MonoImtBuilderEntry *entries;
1650         int i;
1651         GPtrArray *sorted;
1652
1653         mono_domain_lock (domain);
1654         if (!domain->generic_virtual_cases)
1655                 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1656
1657         if (!inited) {
1658                 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1659                 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1660                 inited = TRUE;
1661         }
1662
1663         /* Check whether the case was already added */
1664         list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1665         gvc = list;
1666         while (gvc) {
1667                 if (gvc->method == method)
1668                         break;
1669                 gvc = gvc->next;
1670         }
1671
1672         /* If not found, make a new one */
1673         if (!gvc) {
1674                 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1675                 gvc->method = method;
1676                 gvc->code = code;
1677                 gvc->count = 0;
1678                 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1679
1680                 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1681
1682                 num_added++;
1683         }
1684
1685         if (++gvc->count == THUNK_THRESHOLD) {
1686                 gpointer *old_thunk = (void **)*vtable_slot;
1687                 gpointer vtable_trampoline = NULL;
1688                 gpointer imt_trampoline = NULL;
1689
1690                 if ((gpointer)vtable_slot < (gpointer)vtable) {
1691                         int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1692                         int imt_slot = MONO_IMT_SIZE + displacement;
1693
1694                         /* Force the rebuild of the trampoline at the next call */
1695                         imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1696                         *vtable_slot = imt_trampoline;
1697                 } else {
1698                         vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1699
1700                         entries = get_generic_virtual_entries (domain, vtable_slot);
1701
1702                         sorted = imt_sort_slot_entries (entries);
1703
1704                         *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1705                                                                                                    vtable_trampoline);
1706
1707                         while (entries) {
1708                                 MonoImtBuilderEntry *next = entries->next;
1709                                 g_free (entries);
1710                                 entries = next;
1711                         }
1712
1713                         for (i = 0; i < sorted->len; ++i)
1714                                 g_free (g_ptr_array_index (sorted, i));
1715                         g_ptr_array_free (sorted, TRUE);
1716
1717                         if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1718                                 num_freed ++;
1719                 }
1720         }
1721
1722         mono_domain_unlock (domain);
1723 }
1724
1725 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1726
1727 /**
1728  * mono_class_vtable:
1729  * \param domain the application domain
1730  * \param class the class to initialize
1731  * VTables are domain specific because we create domain specific code, and 
1732  * they contain the domain specific static class data.
1733  * On failure, NULL is returned, and \c class->exception_type is set.
1734  */
1735 MonoVTable *
1736 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1737 {
1738         MonoError error;
1739         MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1740         mono_error_cleanup (&error);
1741         return vtable;
1742 }
1743
1744 /**
1745  * mono_class_vtable_full:
1746  * \param domain the application domain
1747  * \param class the class to initialize
1748  * \param error set on failure.
1749  * VTables are domain specific because we create domain specific code, and 
1750  * they contain the domain specific static class data.
1751  */
1752 MonoVTable *
1753 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1754 {
1755         MONO_REQ_GC_UNSAFE_MODE;
1756
1757         MonoClassRuntimeInfo *runtime_info;
1758
1759         error_init (error);
1760
1761         g_assert (klass);
1762
1763         if (mono_class_has_failure (klass)) {
1764                 mono_error_set_for_class_failure (error, klass);
1765                 return NULL;
1766         }
1767
1768         /* this check can be inlined in jitted code, too */
1769         runtime_info = klass->runtime_info;
1770         if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1771                 return runtime_info->domain_vtables [domain->domain_id];
1772         return mono_class_create_runtime_vtable (domain, klass, error);
1773 }
1774
1775 /**
1776  * mono_class_try_get_vtable:
1777  * \param domain the application domain
1778  * \param class the class to initialize
1779  * This function tries to get the associated vtable from \p class if
1780  * it was already created.
1781  */
1782 MonoVTable *
1783 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1784 {
1785         MONO_REQ_GC_NEUTRAL_MODE;
1786
1787         MonoClassRuntimeInfo *runtime_info;
1788
1789         g_assert (klass);
1790
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 NULL;
1795 }
1796
1797 static gpointer*
1798 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1799 {
1800         MONO_REQ_GC_NEUTRAL_MODE;
1801
1802         size_t alloc_offset;
1803
1804         /*
1805          * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1806          * address bits.  The IMT has an odd number of entries, however, so on 32 bits the
1807          * alignment will be off.  In that case we allocate 4 more bytes and skip over them.
1808          */
1809         if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1810                 g_assert ((imt_table_bytes & 7) == 4);
1811                 vtable_size += 4;
1812                 alloc_offset = 4;
1813         } else {
1814                 alloc_offset = 0;
1815         }
1816
1817         return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1818 }
1819
1820 static MonoVTable *
1821 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1822 {
1823         MONO_REQ_GC_UNSAFE_MODE;
1824
1825         MonoVTable *vt;
1826         MonoClassRuntimeInfo *runtime_info, *old_info;
1827         MonoClassField *field;
1828         char *t;
1829         int i, vtable_slots;
1830         size_t imt_table_bytes;
1831         int gc_bits;
1832         guint32 vtable_size, class_size;
1833         gpointer iter;
1834         gpointer *interface_offsets;
1835
1836         error_init (error);
1837
1838         mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1839         mono_domain_lock (domain);
1840         runtime_info = klass->runtime_info;
1841         if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1842                 mono_domain_unlock (domain);
1843                 mono_loader_unlock ();
1844                 return runtime_info->domain_vtables [domain->domain_id];
1845         }
1846         if (!klass->inited || mono_class_has_failure (klass)) {
1847                 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1848                         mono_domain_unlock (domain);
1849                         mono_loader_unlock ();
1850                         mono_error_set_for_class_failure (error, klass);
1851                         return NULL;
1852                 }
1853         }
1854
1855         /* Array types require that their element type be valid*/
1856         if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1857                 MonoClass *element_class = klass->element_class;
1858                 if (!element_class->inited)
1859                         mono_class_init (element_class);
1860
1861                 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1862                 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1863                         mono_class_setup_vtable (element_class);
1864                 
1865                 if (mono_class_has_failure (element_class)) {
1866                         /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1867                         if (!mono_class_has_failure (klass))
1868                                 mono_class_set_type_load_failure (klass, "");
1869                         mono_domain_unlock (domain);
1870                         mono_loader_unlock ();
1871                         mono_error_set_for_class_failure (error, klass);
1872                         return NULL;
1873                 }
1874         }
1875
1876         /* 
1877          * For some classes, mono_class_init () already computed klass->vtable_size, and 
1878          * that is all that is needed because of the vtable trampolines.
1879          */
1880         if (!klass->vtable_size)
1881                 mono_class_setup_vtable (klass);
1882
1883         if (mono_class_is_ginst (klass) && !klass->vtable)
1884                 mono_class_check_vtable_constraints (klass, NULL);
1885
1886         /* Initialize klass->has_finalize */
1887         mono_class_has_finalizer (klass);
1888
1889         if (mono_class_has_failure (klass)) {
1890                 mono_domain_unlock (domain);
1891                 mono_loader_unlock ();
1892                 mono_error_set_for_class_failure (error, klass);
1893                 return NULL;
1894         }
1895
1896         vtable_slots = klass->vtable_size;
1897         /* we add an additional vtable slot to store the pointer to static field data only when needed */
1898         class_size = mono_class_data_size (klass);
1899         if (class_size)
1900                 vtable_slots++;
1901
1902         if (klass->interface_offsets_count) {
1903                 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1904                 UnlockedIncrement (&mono_stats.imt_number_of_tables);
1905                 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
1906         } else {
1907                 imt_table_bytes = 0;
1908         }
1909
1910         vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1911
1912         UnlockedIncrement (&mono_stats.used_class_count);
1913         UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
1914
1915         interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1916         vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1917         g_assert (!((gsize)vt & 7));
1918
1919         vt->klass = klass;
1920         vt->rank = klass->rank;
1921         vt->domain = domain;
1922
1923         mono_class_compute_gc_descriptor (klass);
1924         /*
1925          * For Boehm:
1926          * We can't use typed allocation in the non-root domains, since the
1927          * collector needs the GC descriptor stored in the vtable even after
1928          * the mempool containing the vtable is destroyed when the domain is
1929          * unloaded. An alternative might be to allocate vtables in the GC
1930          * heap, but this does not seem to work (it leads to crashes inside
1931          * libgc). If that approach is tried, two gc descriptors need to be
1932          * allocated for each class: one for the root domain, and one for all
1933          * other domains. The second descriptor should contain a bit for the
1934          * vtable field in MonoObject, since we can no longer assume the
1935          * vtable is reachable by other roots after the appdomain is unloaded.
1936          */
1937         if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1938                 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1939         else
1940                 vt->gc_descr = klass->gc_descr;
1941
1942         gc_bits = mono_gc_get_vtable_bits (klass);
1943         g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1944
1945         vt->gc_bits = gc_bits;
1946
1947         if (class_size) {
1948                 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1949                 if (klass->has_static_refs) {
1950                         MonoGCDescriptor statics_gc_descr;
1951                         int max_set = 0;
1952                         gsize default_bitmap [4] = {0};
1953                         gsize *bitmap;
1954
1955                         bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1956                         /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1957                         statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1958                         vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1959                         if (bitmap != default_bitmap)
1960                                 g_free (bitmap);
1961                 } else {
1962                         vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1963                 }
1964                 vt->has_static_fields = TRUE;
1965                 UnlockedAdd (&mono_stats.class_static_data_size, class_size);
1966         }
1967
1968         iter = NULL;
1969         while ((field = mono_class_get_fields (klass, &iter))) {
1970                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1971                         continue;
1972                 if (mono_field_is_deleted (field))
1973                         continue;
1974                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1975                         gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1976                         if (special_static != SPECIAL_STATIC_NONE) {
1977                                 guint32 size, offset;
1978                                 gint32 align;
1979                                 gsize default_bitmap [4] = {0};
1980                                 gsize *bitmap;
1981                                 int max_set = 0;
1982                                 int numbits;
1983                                 MonoClass *fclass;
1984                                 if (mono_type_is_reference (field->type)) {
1985                                         default_bitmap [0] = 1;
1986                                         numbits = 1;
1987                                         bitmap = default_bitmap;
1988                                 } else if (mono_type_is_struct (field->type)) {
1989                                         fclass = mono_class_from_mono_type (field->type);
1990                                         bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1991                                         numbits = max_set + 1;
1992                                 } else {
1993                                         default_bitmap [0] = 0;
1994                                         numbits = 0;
1995                                         bitmap = default_bitmap;
1996                                 }
1997                                 size = mono_type_size (field->type, &align);
1998                                 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1999                                 if (!domain->special_static_fields)
2000                                         domain->special_static_fields = g_hash_table_new (NULL, NULL);
2001                                 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2002                                 if (bitmap != default_bitmap)
2003                                         g_free (bitmap);
2004                                 /* 
2005                                  * This marks the field as special static to speed up the
2006                                  * checks in mono_field_static_get/set_value ().
2007                                  */
2008                                 field->offset = -1;
2009                                 continue;
2010                         }
2011                 }
2012                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2013                         MonoClass *fklass = mono_class_from_mono_type (field->type);
2014                         const char *data = mono_field_get_data (field);
2015
2016                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2017                         t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2018                         /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2019                         if (!data)
2020                                 continue;
2021                         if (fklass->valuetype) {
2022                                 memcpy (t, data, mono_class_value_size (fklass, NULL));
2023                         } else {
2024                                 /* it's a pointer type: add check */
2025                                 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2026                                 *t = *(char *)data;
2027                         }
2028                         continue;
2029                 }               
2030         }
2031
2032         vt->max_interface_id = klass->max_interface_id;
2033         vt->interface_bitmap = klass->interface_bitmap;
2034         
2035         //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2036         //              class->name, klass->interface_offsets_count);
2037
2038         /* Initialize vtable */
2039         if (callbacks.get_vtable_trampoline) {
2040                 // This also covers the AOT case
2041                 for (i = 0; i < klass->vtable_size; ++i) {
2042                         vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2043                 }
2044         } else {
2045                 mono_class_setup_vtable (klass);
2046
2047                 for (i = 0; i < klass->vtable_size; ++i) {
2048                         MonoMethod *cm;
2049
2050                         cm = klass->vtable [i];
2051                         if (cm) {
2052                                 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2053                                 if (!is_ok (error)) {
2054                                         mono_domain_unlock (domain);
2055                                         mono_loader_unlock ();
2056                                         return NULL;
2057                                 }
2058                         }
2059                 }
2060         }
2061
2062         if (imt_table_bytes) {
2063                 /* Now that the vtable is full, we can actually fill up the IMT */
2064                         for (i = 0; i < MONO_IMT_SIZE; ++i)
2065                                 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2066         }
2067
2068         /*
2069          * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2070          * re-acquire them and check if another thread has created the vtable in the meantime.
2071          */
2072         /* Special case System.MonoType to avoid infinite recursion */
2073         if (klass != mono_defaults.runtimetype_class) {
2074                 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2075                 if (!is_ok (error)) {
2076                         mono_domain_unlock (domain);
2077                         mono_loader_unlock ();
2078                         return NULL;
2079                 }
2080
2081                 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2082                         /* This is unregistered in
2083                            unregister_vtable_reflection_type() in
2084                            domain.c. */
2085                         MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2086         }
2087
2088         mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2089
2090         /*  class_vtable_array keeps an array of created vtables
2091          */
2092         g_ptr_array_add (domain->class_vtable_array, vt);
2093         /* klass->runtime_info is protected by the loader lock, both when
2094          * it it enlarged and when it is stored info.
2095          */
2096
2097         /*
2098          * Store the vtable in klass->runtime_info.
2099          * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2100          */
2101         mono_memory_barrier ();
2102
2103         old_info = klass->runtime_info;
2104         if (old_info && old_info->max_domain >= domain->domain_id) {
2105                 /* someone already created a large enough runtime info */
2106                 old_info->domain_vtables [domain->domain_id] = vt;
2107         } else {
2108                 int new_size = domain->domain_id;
2109                 if (old_info)
2110                         new_size = MAX (new_size, old_info->max_domain);
2111                 new_size++;
2112                 /* make the new size a power of two */
2113                 i = 2;
2114                 while (new_size > i)
2115                         i <<= 1;
2116                 new_size = i;
2117                 /* this is a bounded memory retention issue: may want to 
2118                  * handle it differently when we'll have a rcu-like system.
2119                  */
2120                 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2121                 runtime_info->max_domain = new_size - 1;
2122                 /* copy the stuff from the older info */
2123                 if (old_info) {
2124                         memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2125                 }
2126                 runtime_info->domain_vtables [domain->domain_id] = vt;
2127                 /* keep this last*/
2128                 mono_memory_barrier ();
2129                 klass->runtime_info = runtime_info;
2130         }
2131
2132         if (klass == mono_defaults.runtimetype_class) {
2133                 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2134                 if (!is_ok (error)) {
2135                         mono_domain_unlock (domain);
2136                         mono_loader_unlock ();
2137                         return NULL;
2138                 }
2139
2140                 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2141                         /* This is unregistered in
2142                            unregister_vtable_reflection_type() in
2143                            domain.c. */
2144                         MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2145         }
2146
2147         mono_domain_unlock (domain);
2148         mono_loader_unlock ();
2149
2150         /* make sure the parent is initialized */
2151         /*FIXME shouldn't this fail the current type?*/
2152         if (klass->parent)
2153                 mono_class_vtable_full (domain, klass->parent, error);
2154
2155         return vt;
2156 }
2157
2158 #ifndef DISABLE_REMOTING
2159 /**
2160  * mono_remote_class_is_interface_proxy:
2161  * \param remote_class
2162  *
2163  * Returns TRUE if the given remote class is a proxying an interface (as
2164  * opposed to a class deriving from MarshalByRefObject).
2165  */
2166 gboolean
2167 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2168 {
2169         /* This if condition is taking advantage of how mono_remote_class ()
2170          * works: if that code changes, this needs to change too. */
2171         return (remote_class->interface_count >= 1 &&
2172                 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2173 }
2174
2175 /**
2176  * mono_class_proxy_vtable:
2177  * \param domain the application domain
2178  * \param remove_class the remote class
2179  * \param error set on error
2180  * Creates a vtable for transparent proxies. It is basically
2181  * a copy of the real vtable of the class wrapped in \p remote_class,
2182  * but all function pointers invoke the remoting functions, and
2183  * \c vtable->klass points to the transparent proxy class, and not to \p class.
2184  *
2185  * On failure returns NULL and sets \p error
2186  */
2187 static MonoVTable *
2188 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2189 {
2190         MONO_REQ_GC_UNSAFE_MODE;
2191
2192         MonoVTable *vt, *pvt;
2193         int i, j, vtsize, extra_interface_vtsize = 0;
2194         guint32 max_interface_id;
2195         MonoClass *k;
2196         GSList *extra_interfaces = NULL;
2197         MonoClass *klass = remote_class->proxy_class;
2198         gpointer *interface_offsets;
2199         uint8_t *bitmap = NULL;
2200         int bsize;
2201         size_t imt_table_bytes;
2202         
2203 #ifdef COMPRESSED_INTERFACE_BITMAP
2204         int bcsize;
2205 #endif
2206
2207         error_init (error);
2208
2209         vt = mono_class_vtable (domain, klass);
2210         g_assert (vt); /*FIXME property handle failure*/
2211         max_interface_id = vt->max_interface_id;
2212         
2213         /* Calculate vtable space for extra interfaces */
2214         for (j = 0; j < remote_class->interface_count; j++) {
2215                 MonoClass* iclass = remote_class->interfaces[j];
2216                 GPtrArray *ifaces;
2217                 int method_count;
2218
2219                 /*FIXME test for interfaces with variant generic arguments*/
2220                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2221                         continue;       /* interface implemented by the class */
2222                 if (g_slist_find (extra_interfaces, iclass))
2223                         continue;
2224                         
2225                 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2226                 
2227                 method_count = mono_class_num_methods (iclass);
2228         
2229                 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2230                 if (!is_ok (error))
2231                         goto failure;
2232                 if (ifaces) {
2233                         for (i = 0; i < ifaces->len; ++i) {
2234                                 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2235                                 /*FIXME test for interfaces with variant generic arguments*/
2236                                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2237                                         continue;       /* interface implemented by the class */
2238                                 if (g_slist_find (extra_interfaces, ic))
2239                                         continue;
2240                                 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2241                                 method_count += mono_class_num_methods (ic);
2242                         }
2243                         g_ptr_array_free (ifaces, TRUE);
2244                         ifaces = NULL;
2245                 }
2246
2247                 extra_interface_vtsize += method_count * sizeof (gpointer);
2248                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2249         }
2250
2251         imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2252         UnlockedIncrement (&mono_stats.imt_number_of_tables);
2253         UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2254
2255         vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2256
2257         UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2258
2259         interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2260         pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2261         g_assert (!((gsize)pvt & 7));
2262
2263         memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2264
2265         pvt->klass = mono_defaults.transparent_proxy_class;
2266         /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2267         pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2268
2269         if (mono_remote_class_is_interface_proxy (remote_class)) {
2270                 /* If it's a transparent proxy for an interface, set the
2271                  * MonoVTable:type to the interface type, not the placeholder
2272                  * MarshalByRefObject class.  This is used when mini JITs calls
2273                  * to Object.GetType ()
2274                  */
2275                 MonoType *itf_proxy_type = &remote_class->interfaces[0]->byval_arg;
2276                 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2277                 if (!is_ok (error))
2278                         goto failure;
2279         }
2280
2281         /* initialize vtable */
2282         mono_class_setup_vtable (klass);
2283         for (i = 0; i < klass->vtable_size; ++i) {
2284                 MonoMethod *cm;
2285                     
2286                 if ((cm = klass->vtable [i])) {
2287                         pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2288                         if (!is_ok (error))
2289                                 goto failure;
2290                 } else
2291                         pvt->vtable [i] = NULL;
2292         }
2293
2294         if (mono_class_is_abstract (klass)) {
2295                 /* create trampolines for abstract methods */
2296                 for (k = klass; k; k = k->parent) {
2297                         MonoMethod* m;
2298                         gpointer iter = NULL;
2299                         while ((m = mono_class_get_methods (k, &iter)))
2300                                 if (!pvt->vtable [m->slot]) {
2301                                         pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2302                                         if (!is_ok (error))
2303                                                 goto failure;
2304                                 }
2305                 }
2306         }
2307
2308         pvt->max_interface_id = max_interface_id;
2309         bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2310 #ifdef COMPRESSED_INTERFACE_BITMAP
2311         bitmap = (uint8_t *)g_malloc0 (bsize);
2312 #else
2313         bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2314 #endif
2315
2316         for (i = 0; i < klass->interface_offsets_count; ++i) {
2317                 int interface_id = klass->interfaces_packed [i]->interface_id;
2318                 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2319         }
2320
2321         if (extra_interfaces) {
2322                 int slot = klass->vtable_size;
2323                 MonoClass* interf;
2324                 gpointer iter;
2325                 MonoMethod* cm;
2326                 GSList *list_item;
2327
2328                 /* Create trampolines for the methods of the interfaces */
2329                 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2330                         interf = (MonoClass *)list_item->data;
2331                         
2332                         bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2333
2334                         iter = NULL;
2335                         j = 0;
2336                         while ((cm = mono_class_get_methods (interf, &iter))) {
2337                                 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2338                                 if (!is_ok (error))
2339                                         goto failure;
2340                         }
2341                         
2342                         slot += mono_class_num_methods (interf);
2343                 }
2344         }
2345
2346         /* Now that the vtable is full, we can actually fill up the IMT */
2347         build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2348         if (extra_interfaces) {
2349                 g_slist_free (extra_interfaces);
2350         }
2351
2352 #ifdef COMPRESSED_INTERFACE_BITMAP
2353         bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2354         pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2355         mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2356         g_free (bitmap);
2357 #else
2358         pvt->interface_bitmap = bitmap;
2359 #endif
2360         return pvt;
2361 failure:
2362         if (extra_interfaces)
2363                 g_slist_free (extra_interfaces);
2364 #ifdef COMPRESSED_INTERFACE_BITMAP
2365         g_free (bitmap);
2366 #endif
2367         return NULL;
2368 }
2369
2370 #endif /* DISABLE_REMOTING */
2371
2372 /**
2373  * mono_class_field_is_special_static:
2374  * \returns whether \p field is a thread/context static field.
2375  */
2376 gboolean
2377 mono_class_field_is_special_static (MonoClassField *field)
2378 {
2379         MONO_REQ_GC_NEUTRAL_MODE
2380
2381         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2382                 return FALSE;
2383         if (mono_field_is_deleted (field))
2384                 return FALSE;
2385         if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2386                 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2387                         return TRUE;
2388         }
2389         return FALSE;
2390 }
2391
2392 /**
2393  * mono_class_field_get_special_static_type:
2394  * \param field The \c MonoClassField describing the field.
2395  * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2396  * \c SPECIAL_STATIC_NONE otherwise.
2397  */
2398 guint32
2399 mono_class_field_get_special_static_type (MonoClassField *field)
2400 {
2401         MONO_REQ_GC_NEUTRAL_MODE
2402
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;
2410 }
2411
2412 /**
2413  * mono_class_has_special_static_fields:
2414  * \returns whether \p klass has any thread/context static fields.
2415  */
2416 gboolean
2417 mono_class_has_special_static_fields (MonoClass *klass)
2418 {
2419         MONO_REQ_GC_NEUTRAL_MODE
2420
2421         MonoClassField *field;
2422         gpointer iter;
2423
2424         iter = NULL;
2425         while ((field = mono_class_get_fields (klass, &iter))) {
2426                 g_assert (field->parent == klass);
2427                 if (mono_class_field_is_special_static (field))
2428                         return TRUE;
2429         }
2430
2431         return FALSE;
2432 }
2433
2434 #ifndef DISABLE_REMOTING
2435 /**
2436  * create_remote_class_key:
2437  * Creates an array of pointers that can be used as a hash key for a remote class.
2438  * The first element of the array is the number of pointers.
2439  */
2440 static gpointer*
2441 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2442 {
2443         MONO_REQ_GC_NEUTRAL_MODE;
2444
2445         gpointer *key;
2446         int i, j;
2447         
2448         if (remote_class == NULL) {
2449                 if (mono_class_is_interface (extra_class)) {
2450                         key = (void **)g_malloc (sizeof(gpointer) * 3);
2451                         key [0] = GINT_TO_POINTER (2);
2452                         key [1] = mono_defaults.marshalbyrefobject_class;
2453                         key [2] = extra_class;
2454                 } else {
2455                         key = (void **)g_malloc (sizeof(gpointer) * 2);
2456                         key [0] = GINT_TO_POINTER (1);
2457                         key [1] = extra_class;
2458                 }
2459         } else {
2460                 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2461                         key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2462                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2463                         key [1] = remote_class->proxy_class;
2464
2465                         // Keep the list of interfaces sorted
2466                         for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2467                                 if (extra_class && remote_class->interfaces [i] > extra_class) {
2468                                         key [j++] = extra_class;
2469                                         extra_class = NULL;
2470                                 }
2471                                 key [j] = remote_class->interfaces [i];
2472                         }
2473                         if (extra_class)
2474                                 key [j] = extra_class;
2475                 } else {
2476                         // Replace the old class. The interface list is the same
2477                         key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2478                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2479                         key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2480                         for (i = 0; i < remote_class->interface_count; i++)
2481                                 key [2 + i] = remote_class->interfaces [i];
2482                 }
2483         }
2484         
2485         return key;
2486 }
2487
2488 /**
2489  * copy_remote_class_key:
2490  *
2491  *   Make a copy of KEY in the domain and return the copy.
2492  */
2493 static gpointer*
2494 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2495 {
2496         MONO_REQ_GC_NEUTRAL_MODE
2497
2498         int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2499         gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2500
2501         memcpy (mp_key, key, key_size);
2502
2503         return mp_key;
2504 }
2505
2506 /**
2507  * mono_remote_class:
2508  * \param domain the application domain
2509  * \param class_name name of the remote class
2510  * \param error set on error
2511  * Creates and initializes a \c MonoRemoteClass object for a remote type. 
2512  * On failure returns NULL and sets \p error
2513  */
2514 MonoRemoteClass*
2515 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2516 {
2517         MONO_REQ_GC_UNSAFE_MODE;
2518
2519         MonoRemoteClass *rc;
2520         gpointer* key, *mp_key;
2521         char *name;
2522         
2523         error_init (error);
2524
2525         key = create_remote_class_key (NULL, proxy_class);
2526         
2527         mono_domain_lock (domain);
2528         rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2529
2530         if (rc) {
2531                 g_free (key);
2532                 mono_domain_unlock (domain);
2533                 return rc;
2534         }
2535
2536         name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2537         if (!is_ok (error)) {
2538                 g_free (key);
2539                 mono_domain_unlock (domain);
2540                 return NULL;
2541         }
2542
2543         mp_key = copy_remote_class_key (domain, key);
2544         g_free (key);
2545         key = mp_key;
2546
2547         if (mono_class_is_interface (proxy_class)) {
2548                 /* If we need to proxy an interface, we use this stylized
2549                  * representation (interface_count >= 1, proxy_class is
2550                  * MarshalByRefObject).  The code in
2551                  * mono_remote_class_is_interface_proxy () depends on being
2552                  * able to detect that we're doing this, so if this
2553                  * representation changes, change GetType, too. */
2554                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2555                 rc->interface_count = 1;
2556                 rc->interfaces [0] = proxy_class;
2557                 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2558         } else {
2559                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2560                 rc->interface_count = 0;
2561                 rc->proxy_class = proxy_class;
2562         }
2563         
2564         rc->default_vtable = NULL;
2565         rc->xdomain_vtable = NULL;
2566         rc->proxy_class_name = name;
2567 #ifndef DISABLE_PERFCOUNTERS
2568         InterlockedAdd (&mono_perfcounters->loader_bytes, mono_string_length (MONO_HANDLE_RAW (class_name)) + 1);
2569 #endif
2570
2571         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2572
2573         mono_domain_unlock (domain);
2574         return rc;
2575 }
2576
2577 /**
2578  * clone_remote_class:
2579  * Creates a copy of the remote_class, adding the provided class or interface
2580  */
2581 static MonoRemoteClass*
2582 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2583 {
2584         MONO_REQ_GC_NEUTRAL_MODE;
2585
2586         MonoRemoteClass *rc;
2587         gpointer* key, *mp_key;
2588         
2589         key = create_remote_class_key (remote_class, extra_class);
2590         rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2591         if (rc != NULL) {
2592                 g_free (key);
2593                 return rc;
2594         }
2595
2596         mp_key = copy_remote_class_key (domain, key);
2597         g_free (key);
2598         key = mp_key;
2599
2600         if (mono_class_is_interface (extra_class)) {
2601                 int i,j;
2602                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2603                 rc->proxy_class = remote_class->proxy_class;
2604                 rc->interface_count = remote_class->interface_count + 1;
2605                 
2606                 // Keep the list of interfaces sorted, since the hash key of
2607                 // the remote class depends on this
2608                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2609                         if (remote_class->interfaces [i] > extra_class && i == j)
2610                                 rc->interfaces [j++] = extra_class;
2611                         rc->interfaces [j] = remote_class->interfaces [i];
2612                 }
2613                 if (i == j)
2614                         rc->interfaces [j] = extra_class;
2615         } else {
2616                 // Replace the old class. The interface array is the same
2617                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2618                 rc->proxy_class = extra_class;
2619                 rc->interface_count = remote_class->interface_count;
2620                 if (rc->interface_count > 0)
2621                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2622         }
2623         
2624         rc->default_vtable = NULL;
2625         rc->xdomain_vtable = NULL;
2626         rc->proxy_class_name = remote_class->proxy_class_name;
2627
2628         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2629
2630         return rc;
2631 }
2632
2633 gpointer
2634 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2635 {
2636         MONO_REQ_GC_UNSAFE_MODE;
2637
2638         error_init (error);
2639
2640         mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2641         mono_domain_lock (domain);
2642         gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2643         if (target_domain_id != -1) {
2644                 if (remote_class->xdomain_vtable == NULL)
2645                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2646                 mono_domain_unlock (domain);
2647                 mono_loader_unlock ();
2648                 return_val_if_nok (error, NULL);
2649                 return remote_class->xdomain_vtable;
2650         }
2651         if (remote_class->default_vtable == NULL) {
2652                 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2653                 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2654                 
2655                 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2656                 MonoClass *klass = mono_class_from_mono_type (type);
2657 #ifndef DISABLE_COM
2658                 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)))
2659                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2660                 else
2661 #endif
2662                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2663                 /* N.B. both branches of the if modify error */
2664                 if (!is_ok (error)) {
2665                         mono_domain_unlock (domain);
2666                         mono_loader_unlock ();
2667                         return NULL;
2668                 }
2669         }
2670         
2671         mono_domain_unlock (domain);
2672         mono_loader_unlock ();
2673         return remote_class->default_vtable;
2674 }
2675
2676 /**
2677  * mono_upgrade_remote_class:
2678  * \param domain the application domain
2679  * \param tproxy the proxy whose remote class has to be upgraded.
2680  * \param klass class to which the remote class can be casted.
2681  * \param error set on error
2682  * Updates the vtable of the remote class by adding the necessary method slots
2683  * and interface offsets so it can be safely casted to klass. klass can be a
2684  * class or an interface.  On success returns TRUE, on failure returns FALSE and sets \p error.
2685  */
2686 gboolean
2687 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2688 {
2689         MONO_REQ_GC_UNSAFE_MODE;
2690
2691         error_init (error);
2692
2693         MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2694         MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2695         
2696         gboolean redo_vtable;
2697         if (mono_class_is_interface (klass)) {
2698                 int i;
2699                 redo_vtable = TRUE;
2700                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2701                         if (remote_class->interfaces [i] == klass)
2702                                 redo_vtable = FALSE;
2703         }
2704         else {
2705                 redo_vtable = (remote_class->proxy_class != klass);
2706         }
2707
2708         mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2709         mono_domain_lock (domain);
2710         if (redo_vtable) {
2711                 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2712                 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2713                 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2714                 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2715                 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2716                 if (!is_ok (error))
2717                         goto leave;
2718         }
2719         
2720 leave:
2721         mono_domain_unlock (domain);
2722         mono_loader_unlock ();
2723         return is_ok (error);
2724 }
2725 #endif /* DISABLE_REMOTING */
2726
2727
2728 /**
2729  * mono_object_get_virtual_method:
2730  * \param obj object to operate on.
2731  * \param method method 
2732  * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2733  * the instance of a callvirt of \p method.
2734  */
2735 MonoMethod*
2736 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2737 {
2738         MONO_REQ_GC_UNSAFE_MODE;
2739         HANDLE_FUNCTION_ENTER ();
2740         MonoError error;
2741         MONO_HANDLE_DCL (MonoObject, obj);
2742         MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2743         mono_error_assert_ok (&error);
2744         HANDLE_FUNCTION_RETURN_VAL (result);
2745 }
2746
2747 /**
2748  * mono_object_handle_get_virtual_method:
2749  * \param obj object to operate on.
2750  * \param method method 
2751  * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2752  * the instance of a callvirt of \p method.
2753  */
2754 MonoMethod*
2755 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2756 {
2757         error_init (error);
2758
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;
2765         }
2766         return class_get_virtual_method (klass, method, is_proxy, error);
2767 }
2768
2769 static MonoMethod*
2770 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2771 {
2772         error_init (error);
2773
2774
2775         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2776                         return method;
2777
2778         mono_class_setup_vtable (klass);
2779         MonoMethod **vtable = klass->vtable;
2780
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 ();
2789                 }
2790         }
2791
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];
2801                         }
2802                 } else {
2803                         res = vtable [method->slot];
2804                 }
2805     }
2806
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;
2812
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);
2823                 }
2824         } else
2825 #endif
2826         {
2827                 if (method->is_inflated) {
2828                         /* Have to inflate the result */
2829                         res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2830                 }
2831         }
2832
2833         return res;
2834 }
2835
2836 static MonoObject*
2837 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2838 {
2839         MONO_REQ_GC_UNSAFE_MODE;
2840
2841         MonoObject *result = NULL;
2842
2843         g_assert (callbacks.runtime_invoke);
2844
2845         error_init (error);
2846         
2847         MONO_PROFILER_RAISE (method_begin_invoke, (method));
2848
2849         result = callbacks.runtime_invoke (method, obj, params, exc, error);
2850
2851         MONO_PROFILER_RAISE (method_end_invoke, (method));
2852
2853         if (!mono_error_ok (error))
2854                 return NULL;
2855
2856         return result;
2857 }
2858
2859 /**
2860  * mono_runtime_invoke:
2861  * \param method method to invoke
2862  * \param obj object instance
2863  * \param params arguments to the method
2864  * \param exc exception information.
2865  * Invokes the method represented by \p method on the object \p obj.
2866  * \p obj is the \c this pointer, it should be NULL for static
2867  * methods, a \c MonoObject* for object instances and a pointer to
2868  * the value type for value types.
2869  *
2870  * The params array contains the arguments to the method with the
2871  * same convention: \c MonoObject* pointers for object instances and
2872  * pointers to the value type otherwise. 
2873  * 
2874  * From unmanaged code you'll usually use the
2875  * \c mono_runtime_invoke variant.
2876  *
2877  * Note that this function doesn't handle virtual methods for
2878  * you, it will exec the exact method you pass: we still need to
2879  * expose a function to lookup the derived class implementation
2880  * of a virtual method (there are examples of this in the code,
2881  * though).
2882  * 
2883  * You can pass NULL as the \p exc argument if you don't want to
2884  * catch exceptions, otherwise, \c *exc will be set to the exception
2885  * thrown, if any.  if an exception is thrown, you can't use the
2886  * \c MonoObject* result from the function.
2887  * 
2888  * If the method returns a value type, it is boxed in an object
2889  * reference.
2890  */
2891 MonoObject*
2892 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2893 {
2894         MonoError error;
2895         MonoObject *res;
2896         if (exc) {
2897                 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2898                 if (*exc == NULL && !mono_error_ok(&error)) {
2899                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2900                 } else
2901                         mono_error_cleanup (&error);
2902         } else {
2903                 res = mono_runtime_invoke_checked (method, obj, params, &error);
2904                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2905         }
2906         return res;
2907 }
2908
2909 /**
2910  * mono_runtime_try_invoke:
2911  * \param method method to invoke
2912  * \param obj object instance
2913  * \param params arguments to the method
2914  * \param exc exception information.
2915  * \param error set on error
2916  * Invokes the method represented by \p method on the object \p obj.
2917  *
2918  * \p obj is the \c this pointer, it should be NULL for static
2919  * methods, a \c MonoObject* for object instances and a pointer to
2920  * the value type for value types.
2921  *
2922  * The params array contains the arguments to the method with the
2923  * same convention: \c MonoObject* pointers for object instances and
2924  * pointers to the value type otherwise. 
2925  * 
2926  * From unmanaged code you'll usually use the
2927  * mono_runtime_invoke() variant.
2928  *
2929  * Note that this function doesn't handle virtual methods for
2930  * you, it will exec the exact method you pass: we still need to
2931  * expose a function to lookup the derived class implementation
2932  * of a virtual method (there are examples of this in the code,
2933  * though).
2934  * 
2935  * For this function, you must not pass NULL as the \p exc argument if
2936  * you don't want to catch exceptions, use
2937  * mono_runtime_invoke_checked().  If an exception is thrown, you
2938  * can't use the \c MonoObject* result from the function.
2939  * 
2940  * If this method cannot be invoked, \p error will be set and \p exc and
2941  * the return value must not be used.
2942  *
2943  * If the method returns a value type, it is boxed in an object
2944  * reference.
2945  */
2946 MonoObject*
2947 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2948 {
2949         MONO_REQ_GC_UNSAFE_MODE;
2950
2951         g_assert (exc != NULL);
2952
2953         if (mono_runtime_get_no_exec ())
2954                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2955
2956         return do_runtime_invoke (method, obj, params, exc, error);
2957 }
2958
2959 /**
2960  * mono_runtime_invoke_checked:
2961  * \param method method to invoke
2962  * \param obj object instance
2963  * \param params arguments to the method
2964  * \param error set on error
2965  * Invokes the method represented by \p method on the object \p obj.
2966  *
2967  * \p obj is the \c this pointer, it should be NULL for static
2968  * methods, a \c MonoObject* for object instances and a pointer to
2969  * the value type for value types.
2970  *
2971  * The \p params array contains the arguments to the method with the
2972  * same convention: \c MonoObject* pointers for object instances and
2973  * pointers to the value type otherwise. 
2974  * 
2975  * From unmanaged code you'll usually use the
2976  * mono_runtime_invoke() variant.
2977  *
2978  * Note that this function doesn't handle virtual methods for
2979  * you, it will exec the exact method you pass: we still need to
2980  * expose a function to lookup the derived class implementation
2981  * of a virtual method (there are examples of this in the code,
2982  * though).
2983  * 
2984  * If an exception is thrown, you can't use the \c MonoObject* result
2985  * from the function.
2986  * 
2987  * If this method cannot be invoked, \p error will be set.  If the
2988  * method throws an exception (and we're in coop mode) the exception
2989  * will be set in \p error.
2990  *
2991  * If the method returns a value type, it is boxed in an object
2992  * reference.
2993  */
2994 MonoObject*
2995 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2996 {
2997         MONO_REQ_GC_UNSAFE_MODE;
2998
2999         if (mono_runtime_get_no_exec ())
3000                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3001
3002         return do_runtime_invoke (method, obj, params, NULL, error);
3003 }
3004
3005 /**
3006  * mono_method_get_unmanaged_thunk:
3007  * \param method method to generate a thunk for.
3008  *
3009  * Returns an \c unmanaged->managed thunk that can be used to call
3010  * a managed method directly from C.
3011  *
3012  * The thunk's C signature closely matches the managed signature:
3013  *
3014  * C#: <code>public bool Equals (object obj);</code>
3015  *
3016  * C:  <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3017  *
3018  * The 1st (<code>this</code>) parameter must not be used with static methods:
3019  *
3020  * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3021  *
3022  * C:  <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3023  *
3024  * The last argument must be a non-null \c MonoException* pointer.
3025  * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3026  * exception has been thrown in managed code. Otherwise it will point
3027  * to the \c MonoException* caught by the thunk. In this case, the result of
3028  * the thunk is undefined:
3029  *
3030  * <pre>
3031  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3032  *
3033  * MonoException *ex = NULL;
3034  *
3035  * Equals func = mono_method_get_unmanaged_thunk (method);
3036  *
3037  * MonoBoolean res = func (thisObj, objToCompare, &ex);
3038  *
3039  * if (ex) {
3040  *
3041  *    // handle exception
3042  *
3043  * }
3044  * </pre>
3045  *
3046  * The calling convention of the thunk matches the platform's default
3047  * convention. This means that under Windows, C declarations must
3048  * contain the \c __stdcall attribute:
3049  *
3050  * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3051  *
3052  * LIMITATIONS
3053  *
3054  * Value type arguments and return values are treated as they were objects:
3055  *
3056  * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3057  * C:  <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3058  *
3059  * Arguments must be properly boxed upon trunk's invocation, while return
3060  * values must be unboxed.
3061  */
3062 gpointer
3063 mono_method_get_unmanaged_thunk (MonoMethod *method)
3064 {
3065         MONO_REQ_GC_NEUTRAL_MODE;
3066         MONO_REQ_API_ENTRYPOINT;
3067
3068         MonoError error;
3069         gpointer res;
3070
3071         g_assert (!mono_threads_is_coop_enabled ());
3072
3073         MONO_ENTER_GC_UNSAFE;
3074         method = mono_marshal_get_thunk_invoke_wrapper (method);
3075         res = mono_compile_method_checked (method, &error);
3076         mono_error_cleanup (&error);
3077         MONO_EXIT_GC_UNSAFE;
3078
3079         return res;
3080 }
3081
3082 void
3083 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3084 {
3085         MONO_REQ_GC_UNSAFE_MODE;
3086
3087         int t;
3088         if (type->byref) {
3089                 /* object fields cannot be byref, so we don't need a
3090                    wbarrier here */
3091                 gpointer *p = (gpointer*)dest;
3092                 *p = value;
3093                 return;
3094         }
3095         t = type->type;
3096 handle_enum:
3097         switch (t) {
3098         case MONO_TYPE_BOOLEAN:
3099         case MONO_TYPE_I1:
3100         case MONO_TYPE_U1: {
3101                 guint8 *p = (guint8*)dest;
3102                 *p = value ? *(guint8*)value : 0;
3103                 return;
3104         }
3105         case MONO_TYPE_I2:
3106         case MONO_TYPE_U2:
3107         case MONO_TYPE_CHAR: {
3108                 guint16 *p = (guint16*)dest;
3109                 *p = value ? *(guint16*)value : 0;
3110                 return;
3111         }
3112 #if SIZEOF_VOID_P == 4
3113         case MONO_TYPE_I:
3114         case MONO_TYPE_U:
3115 #endif
3116         case MONO_TYPE_I4:
3117         case MONO_TYPE_U4: {
3118                 gint32 *p = (gint32*)dest;
3119                 *p = value ? *(gint32*)value : 0;
3120                 return;
3121         }
3122 #if SIZEOF_VOID_P == 8
3123         case MONO_TYPE_I:
3124         case MONO_TYPE_U:
3125 #endif
3126         case MONO_TYPE_I8:
3127         case MONO_TYPE_U8: {
3128                 gint64 *p = (gint64*)dest;
3129                 *p = value ? *(gint64*)value : 0;
3130                 return;
3131         }
3132         case MONO_TYPE_R4: {
3133                 float *p = (float*)dest;
3134                 *p = value ? *(float*)value : 0;
3135                 return;
3136         }
3137         case MONO_TYPE_R8: {
3138                 double *p = (double*)dest;
3139                 *p = value ? *(double*)value : 0;
3140                 return;
3141         }
3142         case MONO_TYPE_STRING:
3143         case MONO_TYPE_SZARRAY:
3144         case MONO_TYPE_CLASS:
3145         case MONO_TYPE_OBJECT:
3146         case MONO_TYPE_ARRAY:
3147                 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3148                 return;
3149         case MONO_TYPE_FNPTR:
3150         case MONO_TYPE_PTR: {
3151                 gpointer *p = (gpointer*)dest;
3152                 *p = deref_pointer? *(gpointer*)value: value;
3153                 return;
3154         }
3155         case MONO_TYPE_VALUETYPE:
3156                 /* note that 't' and 'type->type' can be different */
3157                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3158                         t = mono_class_enum_basetype (type->data.klass)->type;
3159                         goto handle_enum;
3160                 } else {
3161                         MonoClass *klass = mono_class_from_mono_type (type);
3162                         int size = mono_class_value_size (klass, NULL);
3163                         if (value == NULL)
3164                                 mono_gc_bzero_atomic (dest, size);
3165                         else
3166                                 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3167                 }
3168                 return;
3169         case MONO_TYPE_GENERICINST:
3170                 t = type->data.generic_class->container_class->byval_arg.type;
3171                 goto handle_enum;
3172         default:
3173                 g_error ("got type %x", type->type);
3174         }
3175 }
3176
3177 /**
3178  * mono_field_set_value:
3179  * \param obj Instance object
3180  * \param field \c MonoClassField describing the field to set
3181  * \param value The value to be set
3182  *
3183  * Sets the value of the field described by \p field in the object instance \p obj
3184  * to the value passed in \p value.   This method should only be used for instance
3185  * fields.   For static fields, use \c mono_field_static_set_value.
3186  *
3187  * The value must be in the native format of the field type. 
3188  */
3189 void
3190 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3191 {
3192         MONO_REQ_GC_UNSAFE_MODE;
3193
3194         void *dest;
3195
3196         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3197
3198         dest = (char*)obj + field->offset;
3199         mono_copy_value (field->type, dest, value, FALSE);
3200 }
3201
3202 /**
3203  * mono_field_static_set_value:
3204  * \param field \c MonoClassField describing the field to set
3205  * \param value The value to be set
3206  * Sets the value of the static field described by \p field
3207  * to the value passed in \p value.
3208  * The value must be in the native format of the field type. 
3209  */
3210 void
3211 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3212 {
3213         MONO_REQ_GC_UNSAFE_MODE;
3214
3215         void *dest;
3216
3217         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3218         /* you cant set a constant! */
3219         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3220
3221         if (field->offset == -1) {
3222                 /* Special static */
3223                 gpointer addr;
3224
3225                 mono_domain_lock (vt->domain);
3226                 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3227                 mono_domain_unlock (vt->domain);
3228                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3229         } else {
3230                 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3231         }
3232         mono_copy_value (field->type, dest, value, FALSE);
3233 }
3234
3235 /**
3236  * mono_vtable_get_static_field_data:
3237  *
3238  * Internal use function: return a pointer to the memory holding the static fields
3239  * for a class or NULL if there are no static fields.
3240  * This is exported only for use by the debugger.
3241  */
3242 void *
3243 mono_vtable_get_static_field_data (MonoVTable *vt)
3244 {
3245         MONO_REQ_GC_NEUTRAL_MODE
3246
3247         if (!vt->has_static_fields)
3248                 return NULL;
3249         return vt->vtable [vt->klass->vtable_size];
3250 }
3251
3252 static guint8*
3253 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3254 {
3255         MONO_REQ_GC_UNSAFE_MODE;
3256
3257         guint8 *src;
3258
3259         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3260                 if (field->offset == -1) {
3261                         /* Special static */
3262                         gpointer addr;
3263
3264                         mono_domain_lock (vt->domain);
3265                         addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3266                         mono_domain_unlock (vt->domain);
3267                         src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3268                 } else {
3269                         src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3270                 }
3271         } else {
3272                 src = (guint8*)obj + field->offset;
3273         }
3274
3275         return src;
3276 }
3277
3278 /**
3279  * mono_field_get_value:
3280  * \param obj Object instance
3281  * \param field \c MonoClassField describing the field to fetch information from
3282  * \param value pointer to the location where the value will be stored
3283  * Use this routine to get the value of the field \p field in the object
3284  * passed.
3285  *
3286  * The pointer provided by value must be of the field type, for reference
3287  * types this is a \c MonoObject*, for value types its the actual pointer to
3288  * the value type.
3289  *
3290  * For example:
3291  *
3292  * <pre>
3293  * int i;
3294  *
3295  * mono_field_get_value (obj, int_field, &i);
3296  * </pre>
3297  */
3298 void
3299 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3300 {
3301         MONO_REQ_GC_UNSAFE_MODE;
3302
3303         void *src;
3304
3305         g_assert (obj);
3306
3307         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3308
3309         src = (char*)obj + field->offset;
3310         mono_copy_value (field->type, value, src, TRUE);
3311 }
3312
3313 /**
3314  * mono_field_get_value_object:
3315  * \param domain domain where the object will be created (if boxing)
3316  * \param field \c MonoClassField describing the field to fetch information from
3317  * \param obj The object instance for the field.
3318  * \returns a new \c MonoObject with the value from the given field.  If the
3319  * field represents a value type, the value is boxed.
3320  */
3321 MonoObject *
3322 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3323 {       
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;
3328 }
3329
3330 /**
3331  * mono_field_get_value_object_checked:
3332  * \param domain domain where the object will be created (if boxing)
3333  * \param field \c MonoClassField describing the field to fetch information from
3334  * \param obj The object instance for the field.
3335  * \param error Set on error.
3336  * \returns a new \c MonoObject with the value from the given field.  If the
3337  * field represents a value type, the value is boxed.  On error returns NULL and sets \p error.
3338  */
3339 MonoObject *
3340 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3341 {
3342         MONO_REQ_GC_UNSAFE_MODE;
3343
3344         error_init (error);
3345
3346         MonoObject *o;
3347         MonoClass *klass;
3348         MonoVTable *vtable = NULL;
3349         gchar *v;
3350         gboolean is_static = FALSE;
3351         gboolean is_ref = FALSE;
3352         gboolean is_literal = FALSE;
3353         gboolean is_ptr = FALSE;
3354         MonoType *type = mono_field_get_type_checked (field, error);
3355
3356         return_val_if_nok (error, NULL);
3357
3358         switch (type->type) {
3359         case MONO_TYPE_STRING:
3360         case MONO_TYPE_OBJECT:
3361         case MONO_TYPE_CLASS:
3362         case MONO_TYPE_ARRAY:
3363         case MONO_TYPE_SZARRAY:
3364                 is_ref = TRUE;
3365                 break;
3366         case MONO_TYPE_U1:
3367         case MONO_TYPE_I1:
3368         case MONO_TYPE_BOOLEAN:
3369         case MONO_TYPE_U2:
3370         case MONO_TYPE_I2:
3371         case MONO_TYPE_CHAR:
3372         case MONO_TYPE_U:
3373         case MONO_TYPE_I:
3374         case MONO_TYPE_U4:
3375         case MONO_TYPE_I4:
3376         case MONO_TYPE_R4:
3377         case MONO_TYPE_U8:
3378         case MONO_TYPE_I8:
3379         case MONO_TYPE_R8:
3380         case MONO_TYPE_VALUETYPE:
3381                 is_ref = type->byref;
3382                 break;
3383         case MONO_TYPE_GENERICINST:
3384                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3385                 break;
3386         case MONO_TYPE_PTR:
3387                 is_ptr = TRUE;
3388                 break;
3389         default:
3390                 g_error ("type 0x%x not handled in "
3391                          "mono_field_get_value_object", type->type);
3392                 return NULL;
3393         }
3394
3395         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3396                 is_literal = TRUE;
3397
3398         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3399                 is_static = TRUE;
3400
3401                 if (!is_literal) {
3402                         vtable = mono_class_vtable_full (domain, field->parent, error);
3403                         return_val_if_nok (error, NULL);
3404
3405                         if (!vtable->initialized) {
3406                                 mono_runtime_class_init_full (vtable, error);
3407                                 return_val_if_nok (error, NULL);
3408                         }
3409                 }
3410         } else {
3411                 g_assert (obj);
3412         }
3413         
3414         if (is_ref) {
3415                 if (is_literal) {
3416                         get_default_field_value (domain, field, &o, error);
3417                         return_val_if_nok (error, NULL);
3418                 } else if (is_static) {
3419                         mono_field_static_get_value_checked (vtable, field, &o, error);
3420                         return_val_if_nok (error, NULL);
3421                 } else {
3422                         mono_field_get_value (obj, field, &o);
3423                 }
3424                 return o;
3425         }
3426
3427         if (is_ptr) {
3428                 static MonoMethod *m;
3429                 gpointer args [2];
3430                 gpointer *ptr;
3431                 gpointer v;
3432
3433                 if (!m) {
3434                         MonoClass *ptr_klass = mono_class_get_pointer_class ();
3435                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3436                         g_assert (m);
3437                 }
3438
3439                 v = &ptr;
3440                 if (is_literal) {
3441                         get_default_field_value (domain, field, v, error);
3442                         return_val_if_nok (error, NULL);
3443                 } else if (is_static) {
3444                         mono_field_static_get_value_checked (vtable, field, v, error);
3445                         return_val_if_nok (error, NULL);
3446                 } else {
3447                         mono_field_get_value (obj, field, v);
3448                 }
3449
3450                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3451                 args [0] = ptr ? *ptr : NULL;
3452                 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3453                 return_val_if_nok (error, NULL);
3454
3455                 o = mono_runtime_invoke_checked (m, NULL, args, error);
3456                 return_val_if_nok (error, NULL);
3457
3458                 return o;
3459         }
3460
3461         /* boxed value type */
3462         klass = mono_class_from_mono_type (type);
3463
3464         if (mono_class_is_nullable (klass))
3465                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3466
3467         o = mono_object_new_checked (domain, klass, error);
3468         return_val_if_nok (error, NULL);
3469         v = ((gchar *) o) + sizeof (MonoObject);
3470
3471         if (is_literal) {
3472                 get_default_field_value (domain, field, v, error);
3473                 return_val_if_nok (error, NULL);
3474         } else if (is_static) {
3475                 mono_field_static_get_value_checked (vtable, field, v, error);
3476                 return_val_if_nok (error, NULL);
3477         } else {
3478                 mono_field_get_value (obj, field, v);
3479         }
3480
3481         return o;
3482 }
3483
3484 int
3485 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3486 {
3487         MONO_REQ_GC_UNSAFE_MODE;
3488
3489         error_init (error);
3490         int retval = 0;
3491         const char *p = blob;
3492         mono_metadata_decode_blob_size (p, &p);
3493
3494         switch (type) {
3495         case MONO_TYPE_BOOLEAN:
3496         case MONO_TYPE_U1:
3497         case MONO_TYPE_I1:
3498                 *(guint8 *) value = *p;
3499                 break;
3500         case MONO_TYPE_CHAR:
3501         case MONO_TYPE_U2:
3502         case MONO_TYPE_I2:
3503                 *(guint16*) value = read16 (p);
3504                 break;
3505         case MONO_TYPE_U4:
3506         case MONO_TYPE_I4:
3507                 *(guint32*) value = read32 (p);
3508                 break;
3509         case MONO_TYPE_U8:
3510         case MONO_TYPE_I8:
3511                 *(guint64*) value = read64 (p);
3512                 break;
3513         case MONO_TYPE_R4:
3514                 readr4 (p, (float*) value);
3515                 break;
3516         case MONO_TYPE_R8:
3517                 readr8 (p, (double*) value);
3518                 break;
3519         case MONO_TYPE_STRING:
3520                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3521                 break;
3522         case MONO_TYPE_CLASS:
3523                 *(gpointer*) value = NULL;
3524                 break;
3525         default:
3526                 retval = -1;
3527                 g_warning ("type 0x%02x should not be in constant table", type);
3528         }
3529         return retval;
3530 }
3531
3532 static void
3533 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3534 {
3535         MONO_REQ_GC_NEUTRAL_MODE;
3536
3537         MonoTypeEnum def_type;
3538         const char* data;
3539
3540         error_init (error);
3541         
3542         data = mono_class_get_field_default_value (field, &def_type);
3543         mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3544 }
3545
3546 void
3547 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3548 {
3549         MONO_REQ_GC_UNSAFE_MODE;
3550
3551         void *src;
3552
3553         error_init (error);
3554
3555         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3556         
3557         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3558                 get_default_field_value (vt->domain, field, value, error);
3559                 return;
3560         }
3561
3562         if (field->offset == -1) {
3563                 /* Special static */
3564                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3565                 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3566         } else {
3567                 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3568         }
3569         mono_copy_value (field->type, value, src, TRUE);
3570 }
3571
3572 /**
3573  * mono_field_static_get_value:
3574  * \param vt vtable to the object
3575  * \param field \c MonoClassField describing the field to fetch information from
3576  * \param value where the value is returned
3577  * Use this routine to get the value of the static field \p field value.
3578  *
3579  * The pointer provided by value must be of the field type, for reference
3580  * types this is a \c MonoObject*, for value types its the actual pointer to
3581  * the value type.
3582  *
3583  * For example:
3584  *
3585  * <pre>
3586  *     int i;
3587  *
3588  *     mono_field_static_get_value (vt, int_field, &i);
3589  * </pre>
3590  */
3591 void
3592 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3593 {
3594         MONO_REQ_GC_NEUTRAL_MODE;
3595
3596         MonoError error;
3597         mono_field_static_get_value_checked (vt, field, value, &error);
3598         mono_error_cleanup (&error);
3599 }
3600
3601 /**
3602  * mono_field_static_get_value_checked:
3603  * \param vt vtable to the object
3604  * \param field \c MonoClassField describing the field to fetch information from
3605  * \param value where the value is returned
3606  * \param error set on error
3607  * Use this routine to get the value of the static field \p field value.
3608  *
3609  * The pointer provided by value must be of the field type, for reference
3610  * types this is a \c MonoObject*, for value types its the actual pointer to
3611  * the value type.
3612  *
3613  * For example:
3614  *     int i;
3615  *     mono_field_static_get_value_checked (vt, int_field, &i, error);
3616  *     if (!is_ok (error)) { ... }
3617  *
3618  * On failure sets \p error.
3619  */
3620 void
3621 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3622 {
3623         MONO_REQ_GC_NEUTRAL_MODE;
3624
3625         mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3626 }
3627
3628 /**
3629  * mono_property_set_value:
3630  * \param prop MonoProperty to set
3631  * \param obj instance object on which to act
3632  * \param params parameters to pass to the propery
3633  * \param exc optional exception
3634  * Invokes the property's set method with the given arguments on the
3635  * object instance obj (or NULL for static properties). 
3636  * 
3637  * You can pass NULL as the exc argument if you don't want to
3638  * catch exceptions, otherwise, \c *exc will be set to the exception
3639  * thrown, if any.  if an exception is thrown, you can't use the
3640  * \c MonoObject* result from the function.
3641  */
3642 void
3643 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3644 {
3645         MONO_REQ_GC_UNSAFE_MODE;
3646
3647         MonoError error;
3648         do_runtime_invoke (prop->set, obj, params, exc, &error);
3649         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3650                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3651         } else {
3652                 mono_error_cleanup (&error);
3653         }
3654 }
3655
3656 /**
3657  * mono_property_set_value_checked:
3658  * \param prop \c MonoProperty to set
3659  * \param obj instance object on which to act
3660  * \param params parameters to pass to the propery
3661  * \param error set on error
3662  * Invokes the property's set method with the given arguments on the
3663  * object instance \p obj (or NULL for static properties). 
3664  * \returns TRUE on success.  On failure returns FALSE and sets \p error.
3665  * If an exception is thrown, it will be caught and returned via \p error.
3666  */
3667 gboolean
3668 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3669 {
3670         MONO_REQ_GC_UNSAFE_MODE;
3671
3672         MonoObject *exc;
3673
3674         error_init (error);
3675         do_runtime_invoke (prop->set, obj, params, &exc, error);
3676         if (exc != NULL && is_ok (error))
3677                 mono_error_set_exception_instance (error, (MonoException*)exc);
3678         return is_ok (error);
3679 }
3680
3681 /**
3682  * mono_property_get_value:
3683  * \param prop \c MonoProperty to fetch
3684  * \param obj instance object on which to act
3685  * \param params parameters to pass to the propery
3686  * \param exc optional exception
3687  * Invokes the property's \c get method with the given arguments on the
3688  * object instance \p obj (or NULL for static properties). 
3689  * 
3690  * You can pass NULL as the \p exc argument if you don't want to
3691  * catch exceptions, otherwise, \c *exc will be set to the exception
3692  * thrown, if any.  if an exception is thrown, you can't use the
3693  * \c MonoObject* result from the function.
3694  *
3695  * \returns the value from invoking the \c get method on the property.
3696  */
3697 MonoObject*
3698 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3699 {
3700         MONO_REQ_GC_UNSAFE_MODE;
3701
3702         MonoError error;
3703         MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3704         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3705                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3706         } else {
3707                 mono_error_cleanup (&error); /* FIXME don't raise here */
3708         }
3709
3710         return val;
3711 }
3712
3713 /**
3714  * mono_property_get_value_checked:
3715  * \param prop \c MonoProperty to fetch
3716  * \param obj instance object on which to act
3717  * \param params parameters to pass to the propery
3718  * \param error set on error
3719  * Invokes the property's \c get method with the given arguments on the
3720  * object instance obj (or NULL for static properties). 
3721  * 
3722  * If an exception is thrown, you can't use the
3723  * \c MonoObject* result from the function.  The exception will be propagated via \p error.
3724  *
3725  * \returns the value from invoking the get method on the property. On
3726  * failure returns NULL and sets \p error.
3727  */
3728 MonoObject*
3729 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3730 {
3731         MONO_REQ_GC_UNSAFE_MODE;
3732
3733         MonoObject *exc;
3734         MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3735         if (exc != NULL && !is_ok (error))
3736                 mono_error_set_exception_instance (error, (MonoException*) exc);
3737         if (!is_ok (error))
3738                 val = NULL;
3739         return val;
3740 }
3741
3742
3743 /*
3744  * mono_nullable_init:
3745  * @buf: The nullable structure to initialize.
3746  * @value: the value to initialize from
3747  * @klass: the type for the object
3748  *
3749  * Initialize the nullable structure pointed to by @buf from @value which
3750  * should be a boxed value type.   The size of @buf should be able to hold
3751  * as much data as the @klass->instance_size (which is the number of bytes
3752  * that will be copies).
3753  *
3754  * Since Nullables have variable structure, we can not define a C
3755  * structure for them.
3756  */
3757 void
3758 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3759 {
3760         MONO_REQ_GC_UNSAFE_MODE;
3761
3762         MonoClass *param_class = klass->cast_class;
3763
3764         mono_class_setup_fields (klass);
3765         g_assert (klass->fields_inited);
3766                                 
3767         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3768         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3769
3770         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3771         if (value) {
3772                 if (param_class->has_references)
3773                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3774                 else
3775                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3776         } else {
3777                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3778         }
3779 }
3780
3781 /*
3782  * mono_nullable_init_from_handle:
3783  * @buf: The nullable structure to initialize.
3784  * @value: the value to initialize from
3785  * @klass: the type for the object
3786  *
3787  * Initialize the nullable structure pointed to by @buf from @value which
3788  * should be a boxed value type.   The size of @buf should be able to hold
3789  * as much data as the @klass->instance_size (which is the number of bytes
3790  * that will be copies).
3791  *
3792  * Since Nullables have variable structure, we can not define a C
3793  * structure for them.
3794  */
3795 void
3796 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3797 {
3798         MONO_REQ_GC_UNSAFE_MODE;
3799
3800         MonoClass *param_class = klass->cast_class;
3801
3802         mono_class_setup_fields (klass);
3803         g_assert (klass->fields_inited);
3804
3805         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3806         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3807
3808         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL  (value) ? 0 : 1;
3809         if (!MONO_HANDLE_IS_NULL (value)) {
3810                 uint32_t value_gchandle = 0;
3811                 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3812                 if (param_class->has_references)
3813                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3814                 else
3815                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3816                 mono_gchandle_free (value_gchandle);
3817         } else {
3818                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3819         }
3820 }
3821
3822
3823
3824 /**
3825  * mono_nullable_box:
3826  * \param buf The buffer representing the data to be boxed
3827  * \param klass the type to box it as.
3828  * \param error set on error
3829  *
3830  * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3831  * \p buf.  On failure returns NULL and sets \p error.
3832  */
3833 MonoObject*
3834 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3835 {
3836         MONO_REQ_GC_UNSAFE_MODE;
3837
3838         error_init (error);
3839         MonoClass *param_class = klass->cast_class;
3840
3841         mono_class_setup_fields (klass);
3842         g_assert (klass->fields_inited);
3843
3844         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3845         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3846
3847         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3848                 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3849                 return_val_if_nok (error, NULL);
3850                 if (param_class->has_references)
3851                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3852                 else
3853                         mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3854                 return o;
3855         }
3856         else
3857                 return NULL;
3858 }
3859
3860 /**
3861  * mono_get_delegate_invoke:
3862  * \param klass The delegate class
3863  * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3864  */
3865 MonoMethod *
3866 mono_get_delegate_invoke (MonoClass *klass)
3867 {
3868         MONO_REQ_GC_NEUTRAL_MODE;
3869
3870         MonoMethod *im;
3871
3872         /* This is called at runtime, so avoid the slower search in metadata */
3873         mono_class_setup_methods (klass);
3874         if (mono_class_has_failure (klass))
3875                 return NULL;
3876         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3877         return im;
3878 }
3879
3880 /**
3881  * mono_get_delegate_begin_invoke:
3882  * \param klass The delegate class
3883  * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3884  */
3885 MonoMethod *
3886 mono_get_delegate_begin_invoke (MonoClass *klass)
3887 {
3888         MONO_REQ_GC_NEUTRAL_MODE;
3889
3890         MonoMethod *im;
3891
3892         /* This is called at runtime, so avoid the slower search in metadata */
3893         mono_class_setup_methods (klass);
3894         if (mono_class_has_failure (klass))
3895                 return NULL;
3896         im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3897         return im;
3898 }
3899
3900 /**
3901  * mono_get_delegate_end_invoke:
3902  * \param klass The delegate class
3903  * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3904  */
3905 MonoMethod *
3906 mono_get_delegate_end_invoke (MonoClass *klass)
3907 {
3908         MONO_REQ_GC_NEUTRAL_MODE;
3909
3910         MonoMethod *im;
3911
3912         /* This is called at runtime, so avoid the slower search in metadata */
3913         mono_class_setup_methods (klass);
3914         if (mono_class_has_failure (klass))
3915                 return NULL;
3916         im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3917         return im;
3918 }
3919
3920 /**
3921  * mono_runtime_delegate_invoke:
3922  * \param delegate pointer to a delegate object.
3923  * \param params parameters for the delegate.
3924  * \param exc Pointer to the exception result.
3925  *
3926  * Invokes the delegate method \p delegate with the parameters provided.
3927  *
3928  * You can pass NULL as the \p exc argument if you don't want to
3929  * catch exceptions, otherwise, \c *exc will be set to the exception
3930  * thrown, if any.  if an exception is thrown, you can't use the
3931  * \c MonoObject* result from the function.
3932  */
3933 MonoObject*
3934 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3935 {
3936         MONO_REQ_GC_UNSAFE_MODE;
3937
3938         MonoError error;
3939         if (exc) {
3940                 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3941                 if (*exc) {
3942                         mono_error_cleanup (&error);
3943                         return NULL;
3944                 } else {
3945                         if (!is_ok (&error))
3946                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3947                         return result;
3948                 }
3949         } else {
3950                 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3951                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3952                 return result;
3953         }
3954 }
3955
3956 /**
3957  * mono_runtime_delegate_try_invoke:
3958  * \param delegate pointer to a delegate object.
3959  * \param params parameters for the delegate.
3960  * \param exc Pointer to the exception result.
3961  * \param error set on error
3962  * Invokes the delegate method \p delegate with the parameters provided.
3963  *
3964  * You can pass NULL as the \p exc argument if you don't want to
3965  * catch exceptions, otherwise, \c *exc will be set to the exception
3966  * thrown, if any.  On failure to execute, \p error will be set.
3967  * if an exception is thrown, you can't use the
3968  * \c MonoObject* result from the function.
3969  */
3970 MonoObject*
3971 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3972 {
3973         MONO_REQ_GC_UNSAFE_MODE;
3974
3975         error_init (error);
3976         MonoMethod *im;
3977         MonoClass *klass = delegate->vtable->klass;
3978         MonoObject *o;
3979
3980         im = mono_get_delegate_invoke (klass);
3981         if (!im)
3982                 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3983
3984         if (exc) {
3985                 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3986         } else {
3987                 o = mono_runtime_invoke_checked (im, delegate, params, error);
3988         }
3989
3990         return o;
3991 }
3992
3993 /**
3994  * mono_runtime_delegate_invoke_checked:
3995  * \param delegate pointer to a delegate object.
3996  * \param params parameters for the delegate.
3997  * \param error set on error
3998  * Invokes the delegate method \p delegate with the parameters provided.
3999  * On failure \p error will be set and you can't use the \c MonoObject*
4000  * result from the function.
4001  */
4002 MonoObject*
4003 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4004 {
4005         error_init (error);
4006         return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4007 }
4008
4009 static char **main_args = NULL;
4010 static int num_main_args = 0;
4011
4012 /**
4013  * mono_runtime_get_main_args:
4014  * \returns A \c MonoArray with the arguments passed to the main program
4015  */
4016 MonoArray*
4017 mono_runtime_get_main_args (void)
4018 {
4019         MONO_REQ_GC_UNSAFE_MODE;
4020         MonoError error;
4021         MonoArray *result = mono_runtime_get_main_args_checked (&error);
4022         mono_error_assert_ok (&error);
4023         return result;
4024 }
4025
4026 /**
4027  * mono_runtime_get_main_args_checked:
4028  * \param error set on error
4029  * \returns a \c MonoArray with the arguments passed to the main
4030  * program. On failure returns NULL and sets \p error.
4031  */
4032 MonoArray*
4033 mono_runtime_get_main_args_checked (MonoError *error)
4034 {
4035         MonoArray *res;
4036         int i;
4037         MonoDomain *domain = mono_domain_get ();
4038
4039         error_init (error);
4040
4041         res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4042         return_val_if_nok (error, NULL);
4043
4044         for (i = 0; i < num_main_args; ++i) {
4045                 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
4046                 return_val_if_nok (error, NULL);
4047                 mono_array_setref (res, i, arg);
4048         }
4049
4050         return res;
4051 }
4052
4053 static void
4054 free_main_args (void)
4055 {
4056         MONO_REQ_GC_NEUTRAL_MODE;
4057
4058         int i;
4059
4060         for (i = 0; i < num_main_args; ++i)
4061                 g_free (main_args [i]);
4062         g_free (main_args);
4063         num_main_args = 0;
4064         main_args = NULL;
4065 }
4066
4067 /**
4068  * mono_runtime_set_main_args:
4069  * \param argc number of arguments from the command line
4070  * \param argv array of strings from the command line
4071  * Set the command line arguments from an embedding application that doesn't otherwise call
4072  * \c mono_runtime_run_main.
4073  */
4074 int
4075 mono_runtime_set_main_args (int argc, char* argv[])
4076 {
4077         MONO_REQ_GC_NEUTRAL_MODE;
4078
4079         int i;
4080
4081         free_main_args ();
4082         main_args = g_new0 (char*, argc);
4083         num_main_args = argc;
4084
4085         for (i = 0; i < argc; ++i) {
4086                 gchar *utf8_arg;
4087
4088                 utf8_arg = mono_utf8_from_external (argv[i]);
4089                 if (utf8_arg == NULL) {
4090                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4091                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4092                         exit (-1);
4093                 }
4094
4095                 main_args [i] = utf8_arg;
4096         }
4097
4098         return 0;
4099 }
4100
4101 /*
4102  * Prepare an array of arguments in order to execute a standard Main()
4103  * method (argc/argv contains the executable name). This method also
4104  * sets the command line argument value needed by System.Environment.
4105  * 
4106  */
4107 static MonoArray*
4108 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4109 {
4110         MONO_REQ_GC_UNSAFE_MODE;
4111
4112         MonoError error;
4113         int i;
4114         MonoArray *args = NULL;
4115         MonoDomain *domain = mono_domain_get ();
4116         gchar *utf8_fullpath;
4117         MonoMethodSignature *sig;
4118
4119         g_assert (method != NULL);
4120         
4121         mono_thread_set_main (mono_thread_current ());
4122
4123         main_args = g_new0 (char*, argc);
4124         num_main_args = argc;
4125
4126         if (!g_path_is_absolute (argv [0])) {
4127                 gchar *basename = g_path_get_basename (argv [0]);
4128                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4129                                                     basename,
4130                                                     NULL);
4131
4132                 utf8_fullpath = mono_utf8_from_external (fullpath);
4133                 if(utf8_fullpath == NULL) {
4134                         /* Printing the arg text will cause glib to
4135                          * whinge about "Invalid UTF-8", but at least
4136                          * its relevant, and shows the problem text
4137                          * string.
4138                          */
4139                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4140                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4141                         exit (-1);
4142                 }
4143
4144                 g_free (fullpath);
4145                 g_free (basename);
4146         } else {
4147                 utf8_fullpath = mono_utf8_from_external (argv[0]);
4148                 if(utf8_fullpath == NULL) {
4149                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4150                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4151                         exit (-1);
4152                 }
4153         }
4154
4155         main_args [0] = utf8_fullpath;
4156
4157         for (i = 1; i < argc; ++i) {
4158                 gchar *utf8_arg;
4159
4160                 utf8_arg=mono_utf8_from_external (argv[i]);
4161                 if(utf8_arg==NULL) {
4162                         /* Ditto the comment about Invalid UTF-8 here */
4163                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4164                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4165                         exit (-1);
4166                 }
4167
4168                 main_args [i] = utf8_arg;
4169         }
4170         argc--;
4171         argv++;
4172
4173         sig = mono_method_signature (method);
4174         if (!sig) {
4175                 g_print ("Unable to load Main method.\n");
4176                 exit (-1);
4177         }
4178
4179         if (sig->param_count) {
4180                 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4181                 mono_error_assert_ok (&error);
4182                 for (i = 0; i < argc; ++i) {
4183                         /* The encodings should all work, given that
4184                          * we've checked all these args for the
4185                          * main_args array.
4186                          */
4187                         gchar *str = mono_utf8_from_external (argv [i]);
4188                         MonoString *arg = mono_string_new_checked (domain, str, &error);
4189                         mono_error_assert_ok (&error);
4190                         mono_array_setref (args, i, arg);
4191                         g_free (str);
4192                 }
4193         } else {
4194                 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4195                 mono_error_assert_ok (&error);
4196         }
4197         
4198         mono_assembly_set_main (method->klass->image->assembly);
4199
4200         return args;
4201 }
4202
4203 /**
4204  * mono_runtime_run_main:
4205  * \param method the method to start the application with (usually <code>Main</code>)
4206  * \param argc number of arguments from the command line
4207  * \param argv array of strings from the command line
4208  * \param exc excetption results
4209  * Execute a standard \c Main method (\p argc / \p argv contains the
4210  * executable name). This method also sets the command line argument value
4211  * needed by \c System.Environment.
4212  */
4213 int
4214 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4215                        MonoObject **exc)
4216 {
4217         MONO_REQ_GC_UNSAFE_MODE;
4218
4219         MonoError error;
4220         MonoArray *args = prepare_run_main (method, argc, argv);
4221         int res;
4222         if (exc) {
4223                 res = mono_runtime_try_exec_main (method, args, exc);
4224         } else {
4225                 res = mono_runtime_exec_main_checked (method, args, &error);
4226                 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4227         }
4228         return res;
4229 }
4230
4231 /**
4232  * mono_runtime_run_main_checked:
4233  * \param method the method to start the application with (usually \c Main)
4234  * \param argc number of arguments from the command line
4235  * \param argv array of strings from the command line
4236  * \param error set on error
4237  *
4238  * Execute a standard \c Main method (\p argc / \p argv contains the
4239  * executable name). This method also sets the command line argument value
4240  * needed by \c System.Environment.  On failure sets \p error.
4241  */
4242 int
4243 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4244                                MonoError *error)
4245 {
4246         error_init (error);
4247         MonoArray *args = prepare_run_main (method, argc, argv);
4248         return mono_runtime_exec_main_checked (method, args, error);
4249 }
4250
4251 /**
4252  * mono_runtime_try_run_main:
4253  * \param method the method to start the application with (usually \c Main)
4254  * \param argc number of arguments from the command line
4255  * \param argv array of strings from the command line
4256  * \param exc set if \c Main throws an exception
4257  * \param error set if \c Main can't be executed
4258  * Execute a standard \c Main method (\p argc / \p argv contains the executable
4259  * name). This method also sets the command line argument value needed
4260  * by \c System.Environment.  On failure sets \p error if Main can't be
4261  * executed or \p exc if it threw an exception.
4262  */
4263 int
4264 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4265                            MonoObject **exc)
4266 {
4267         g_assert (exc);
4268         MonoArray *args = prepare_run_main (method, argc, argv);
4269         return mono_runtime_try_exec_main (method, args, exc);
4270 }
4271
4272
4273 static MonoObject*
4274 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4275 {
4276         static MonoMethod *serialize_method;
4277
4278         MonoError error;
4279         void *params [1];
4280         MonoObject *array;
4281
4282         if (!serialize_method) {
4283                 MonoClass *klass = mono_class_get_remoting_services_class ();
4284                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4285         }
4286
4287         if (!serialize_method) {
4288                 *failure = TRUE;
4289                 return NULL;
4290         }
4291
4292         g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4293
4294         params [0] = obj;
4295         *exc = NULL;
4296
4297         array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4298         if (*exc == NULL && !mono_error_ok (&error))
4299                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4300         else
4301                 mono_error_cleanup (&error);
4302
4303         if (*exc)
4304                 *failure = TRUE;
4305
4306         return array;
4307 }
4308
4309 static MonoObject*
4310 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4311 {
4312         MONO_REQ_GC_UNSAFE_MODE;
4313
4314         static MonoMethod *deserialize_method;
4315
4316         MonoError error;
4317         void *params [1];
4318         MonoObject *result;
4319
4320         if (!deserialize_method) {
4321                 MonoClass *klass = mono_class_get_remoting_services_class ();
4322                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4323         }
4324         if (!deserialize_method) {
4325                 *failure = TRUE;
4326                 return NULL;
4327         }
4328
4329         params [0] = obj;
4330         *exc = NULL;
4331
4332         result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4333         if (*exc == NULL && !mono_error_ok (&error))
4334                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4335         else
4336                 mono_error_cleanup (&error);
4337
4338         if (*exc)
4339                 *failure = TRUE;
4340
4341         return result;
4342 }
4343
4344 #ifndef DISABLE_REMOTING
4345 static MonoObject*
4346 make_transparent_proxy (MonoObject *obj, MonoError *error)
4347 {
4348         MONO_REQ_GC_UNSAFE_MODE;
4349
4350         static MonoMethod *get_proxy_method;
4351
4352         MonoDomain *domain = mono_domain_get ();
4353         MonoRealProxy *real_proxy;
4354         MonoReflectionType *reflection_type;
4355         MonoTransparentProxy *transparent_proxy;
4356
4357         error_init (error);
4358
4359         if (!get_proxy_method)
4360                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4361
4362         g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4363
4364         real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4365         return_val_if_nok (error, NULL);
4366         reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4367         return_val_if_nok (error, NULL);
4368
4369         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4370         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4371
4372         MonoObject *exc = NULL;
4373
4374         transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4375         if (exc != NULL && is_ok (error))
4376                 mono_error_set_exception_instance (error, (MonoException*)exc);
4377
4378         return (MonoObject*) transparent_proxy;
4379 }
4380 #endif /* DISABLE_REMOTING */
4381
4382 /**
4383  * mono_object_xdomain_representation
4384  * \param obj an object
4385  * \param target_domain a domain
4386  * \param error set on error.
4387  * Creates a representation of obj in the domain \p target_domain.  This
4388  * is either a copy of \p obj arrived through via serialization and
4389  * deserialization or a proxy, depending on whether the object is
4390  * serializable or marshal by ref.  \p obj must not be in \p target_domain.
4391  * If the object cannot be represented in \p target_domain, NULL is
4392  * returned and \p error is set appropriately.
4393  */
4394 MonoObject*
4395 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4396 {
4397         MONO_REQ_GC_UNSAFE_MODE;
4398
4399         error_init (error);
4400         MonoObject *deserialized = NULL;
4401
4402 #ifndef DISABLE_REMOTING
4403         if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4404                 deserialized = make_transparent_proxy (obj, error);
4405         } 
4406         else
4407 #endif
4408         {
4409                 gboolean failure = FALSE;
4410                 MonoDomain *domain = mono_domain_get ();
4411                 MonoObject *serialized;
4412                 MonoObject *exc = NULL;
4413
4414                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4415                 serialized = serialize_object (obj, &failure, &exc);
4416                 mono_domain_set_internal_with_options (target_domain, FALSE);
4417                 if (!failure)
4418                         deserialized = deserialize_object (serialized, &failure, &exc);
4419                 if (domain != target_domain)
4420                         mono_domain_set_internal_with_options (domain, FALSE);
4421                 if (failure)
4422                         mono_error_set_exception_instance (error, (MonoException*)exc);
4423         }
4424
4425         return deserialized;
4426 }
4427
4428 /* Used in call_unhandled_exception_delegate */
4429 static MonoObject *
4430 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4431 {
4432         MONO_REQ_GC_UNSAFE_MODE;
4433
4434         error_init (error);
4435         MonoClass *klass;
4436         gpointer args [2];
4437         MonoMethod *method = NULL;
4438         MonoBoolean is_terminating = TRUE;
4439         MonoObject *obj;
4440
4441         klass = mono_class_get_unhandled_exception_event_args_class ();
4442         mono_class_init (klass);
4443
4444         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4445         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4446         g_assert (method);
4447
4448         args [0] = exc;
4449         args [1] = &is_terminating;
4450
4451         obj = mono_object_new_checked (mono_domain_get (), klass, error);
4452         return_val_if_nok (error, NULL);
4453
4454         mono_runtime_invoke_checked (method, obj, args, error);
4455         return_val_if_nok (error, NULL);
4456
4457         return obj;
4458 }
4459
4460 /* Used in mono_unhandled_exception */
4461 static void
4462 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4463         MONO_REQ_GC_UNSAFE_MODE;
4464
4465         MonoError error;
4466         MonoObject *e = NULL;
4467         gpointer pa [2];
4468         MonoDomain *current_domain = mono_domain_get ();
4469
4470         if (domain != current_domain)
4471                 mono_domain_set_internal_with_options (domain, FALSE);
4472
4473         g_assert (domain == mono_object_domain (domain->domain));
4474
4475         if (mono_object_domain (exc) != domain) {
4476
4477                 exc = mono_object_xdomain_representation (exc, domain, &error);
4478                 if (!exc) {
4479                         if (!is_ok (&error)) {
4480                                 MonoError inner_error;
4481                                 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4482                                 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4483                                 mono_error_assert_ok (&inner_error);
4484                         } else {
4485                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4486                                                 "System.Runtime.Serialization", "SerializationException",
4487                                                 "Could not serialize unhandled exception.");
4488                         }
4489                 }
4490         }
4491         g_assert (mono_object_domain (exc) == domain);
4492
4493         pa [0] = domain->domain;
4494         pa [1] = create_unhandled_exception_eventargs (exc, &error);
4495         mono_error_assert_ok (&error);
4496         mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4497         if (!is_ok (&error)) {
4498                 if (e == NULL)
4499                         e = (MonoObject*)mono_error_convert_to_exception (&error);
4500                 else
4501                         mono_error_cleanup (&error);
4502         }
4503
4504         if (domain != current_domain)
4505                 mono_domain_set_internal_with_options (current_domain, FALSE);
4506
4507         if (e) {
4508                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4509                 if (!mono_error_ok (&error)) {
4510                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4511                         mono_error_cleanup (&error);
4512                 } else {
4513                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
4514                         g_free (msg);
4515                 }
4516         }
4517 }
4518
4519 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4520
4521 /**
4522  * mono_runtime_unhandled_exception_policy_set:
4523  * \param policy the new policy
4524  * This is a VM internal routine.
4525  * Sets the runtime policy for handling unhandled exceptions.
4526  */
4527 void
4528 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4529         runtime_unhandled_exception_policy = policy;
4530 }
4531
4532 /**
4533  * mono_runtime_unhandled_exception_policy_get:
4534  *
4535  * This is a VM internal routine.
4536  *
4537  * Gets the runtime policy for handling unhandled exceptions.
4538  */
4539 MonoRuntimeUnhandledExceptionPolicy
4540 mono_runtime_unhandled_exception_policy_get (void) {
4541         return runtime_unhandled_exception_policy;
4542 }
4543
4544 /**
4545  * mono_unhandled_exception:
4546  * \param exc exception thrown
4547  * This is a VM internal routine.
4548  *
4549  * We call this function when we detect an unhandled exception
4550  * in the default domain.
4551  *
4552  * It invokes the \c UnhandledException event in \c AppDomain or prints
4553  * a warning to the console 
4554  */
4555 void
4556 mono_unhandled_exception (MonoObject *exc_raw)
4557 {
4558         MonoError error;
4559         HANDLE_FUNCTION_ENTER ();
4560         MONO_HANDLE_DCL (MonoObject, exc);
4561         error_init (&error);
4562         mono_unhandled_exception_checked (exc, &error);
4563         mono_error_assert_ok (&error);
4564         HANDLE_FUNCTION_RETURN ();
4565 }
4566
4567 /**
4568  * mono_unhandled_exception:
4569  * @exc: exception thrown
4570  *
4571  * This is a VM internal routine.
4572  *
4573  * We call this function when we detect an unhandled exception
4574  * in the default domain.
4575  *
4576  * It invokes the * UnhandledException event in AppDomain or prints
4577  * a warning to the console 
4578  */
4579 void
4580 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4581 {
4582         MONO_REQ_GC_UNSAFE_MODE;
4583
4584         error_init (error);
4585         MonoClassField *field;
4586         MonoDomain *current_domain, *root_domain;
4587         MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4588
4589         MonoClass *klass = mono_handle_class (exc);
4590         /*
4591          * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from 
4592          * a thread started in unmanaged world.
4593          * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
4594          */
4595         if (klass == mono_defaults.threadabortexception_class ||
4596                         (klass == mono_class_get_appdomain_unloaded_exception_class () &&
4597                         mono_thread_info_current ()->runtime_thread))
4598                 return;
4599
4600         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4601         g_assert (field);
4602
4603         current_domain = mono_domain_get ();
4604         root_domain = mono_get_root_domain ();
4605
4606         MonoObjectHandle root_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, error)); /* FIXME use handles for mono_field_get_value_object_checked */
4607         return_if_nok (error);
4608         if (current_domain != root_domain) {
4609                 MONO_HANDLE_ASSIGN (current_appdomain_delegate, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, error))); /* FIXME use handles for mono_field_get_value_object_checked */
4610                 return_if_nok (error);
4611         }
4612
4613         if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4614                 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4615         } else {
4616                 /* unhandled exception callbacks must not be aborted */
4617                 mono_threads_begin_abort_protected_block ();
4618                 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4619                         call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4620                 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4621                         call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4622                 mono_threads_end_abort_protected_block ();
4623         }
4624
4625         /* set exitcode only if we will abort the process */
4626         if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4627                  || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4628         {
4629                 mono_environment_exitcode_set (1);
4630         }
4631 }
4632
4633 /**
4634  * mono_runtime_exec_managed_code:
4635  * \param domain Application domain
4636  * \param main_func function to invoke from the execution thread
4637  * \param main_args parameter to the main_func
4638  * Launch a new thread to execute a function
4639  *
4640  * \p main_func is called back from the thread with main_args as the
4641  * parameter.  The callback function is expected to start \c Main
4642  * eventually.  This function then waits for all managed threads to
4643  * finish.
4644  * It is not necessary anymore to execute managed code in a subthread,
4645  * so this function should not be used anymore by default: just
4646  * execute the code and then call mono_thread_manage().
4647  */
4648 void
4649 mono_runtime_exec_managed_code (MonoDomain *domain,
4650                                 MonoMainThreadFunc main_func,
4651                                 gpointer main_args)
4652 {
4653         MonoError error;
4654         mono_thread_create_checked (domain, main_func, main_args, &error);
4655         mono_error_assert_ok (&error);
4656
4657         mono_thread_manage ();
4658 }
4659
4660 static void
4661 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4662 {
4663         MonoInternalThread* thread = mono_thread_internal_current ();
4664         MonoCustomAttrInfo* cinfo;
4665         gboolean has_stathread_attribute;
4666
4667         if (!domain->entry_assembly) {
4668                 gchar *str;
4669                 MonoError error;
4670                 MonoAssembly *assembly;
4671
4672                 assembly = method->klass->image->assembly;
4673                 domain->entry_assembly = assembly;
4674                 /* Domains created from another domain already have application_base and configuration_file set */
4675                 if (domain->setup->application_base == NULL) {
4676                         MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4677                         mono_error_assert_ok (&error);
4678                         MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4679                 }
4680
4681                 if (domain->setup->configuration_file == NULL) {
4682                         str = g_strconcat (assembly->image->name, ".config", NULL);
4683                         MonoString *config_file = mono_string_new_checked (domain, str, &error);
4684                         mono_error_assert_ok (&error);
4685                         MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4686                         g_free (str);
4687                         mono_domain_set_options_from_config (domain);
4688                 }
4689         }
4690
4691         MonoError cattr_error;
4692         cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4693         mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4694         if (cinfo) {
4695                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4696                 if (!cinfo->cached)
4697                         mono_custom_attrs_free (cinfo);
4698         } else {
4699                 has_stathread_attribute = FALSE;
4700         }
4701         if (has_stathread_attribute) {
4702                 thread->apartment_state = ThreadApartmentState_STA;
4703         } else {
4704                 thread->apartment_state = ThreadApartmentState_MTA;
4705         }
4706         mono_thread_init_apartment_state ();
4707
4708 }
4709
4710 static int
4711 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4712 {
4713         MONO_REQ_GC_UNSAFE_MODE;
4714
4715         gpointer pa [1];
4716         int rval;
4717
4718         error_init (error);
4719         g_assert (args);
4720
4721         pa [0] = args;
4722
4723         /* FIXME: check signature of method */
4724         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4725                 MonoObject *res;
4726                 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4727                 if (is_ok (error))
4728                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4729                 else
4730                         rval = -1;
4731                 mono_environment_exitcode_set (rval);
4732         } else {
4733                 mono_runtime_invoke_checked (method, NULL, pa, error);
4734
4735                 if (is_ok (error))
4736                         rval = 0;
4737                 else {
4738                         rval = -1;
4739                 }
4740         }
4741         return rval;
4742 }
4743
4744 static int
4745 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4746 {
4747         MONO_REQ_GC_UNSAFE_MODE;
4748
4749         gpointer pa [1];
4750         int rval;
4751
4752         g_assert (args);
4753         g_assert (exc);
4754
4755         pa [0] = args;
4756
4757         /* FIXME: check signature of method */
4758         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4759                 MonoError inner_error;
4760                 MonoObject *res;
4761                 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4762                 if (*exc == NULL && !mono_error_ok (&inner_error))
4763                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4764                 else
4765                         mono_error_cleanup (&inner_error);
4766
4767                 if (*exc == NULL)
4768                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4769                 else
4770                         rval = -1;
4771
4772                 mono_environment_exitcode_set (rval);
4773         } else {
4774                 MonoError inner_error;
4775                 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4776                 if (*exc == NULL && !mono_error_ok (&inner_error))
4777                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4778                 else
4779                         mono_error_cleanup (&inner_error);
4780
4781                 if (*exc == NULL)
4782                         rval = 0;
4783                 else {
4784                         /* If the return type of Main is void, only
4785                          * set the exitcode if an exception was thrown
4786                          * (we don't want to blow away an
4787                          * explicitly-set exit code)
4788                          */
4789                         rval = -1;
4790                         mono_environment_exitcode_set (rval);
4791                 }
4792         }
4793
4794         return rval;
4795 }
4796
4797 /*
4798  * Execute a standard Main() method (args doesn't contain the
4799  * executable name).
4800  */
4801 int
4802 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4803 {
4804         MonoError error;
4805         prepare_thread_to_exec_main (mono_object_domain (args), method);
4806         if (exc) {
4807                 int rval = do_try_exec_main (method, args, exc);
4808                 return rval;
4809         } else {
4810                 int rval = do_exec_main_checked (method, args, &error);
4811                 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4812                 return rval;
4813         }
4814 }
4815
4816 /*
4817  * Execute a standard Main() method (args doesn't contain the
4818  * executable name).
4819  *
4820  * On failure sets @error
4821  */
4822 int
4823 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4824 {
4825         error_init (error);
4826         prepare_thread_to_exec_main (mono_object_domain (args), method);
4827         return do_exec_main_checked (method, args, error);
4828 }
4829
4830 /*
4831  * Execute a standard Main() method (args doesn't contain the
4832  * executable name).
4833  *
4834  * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4835  */
4836 int
4837 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4838 {
4839         prepare_thread_to_exec_main (mono_object_domain (args), method);
4840         return do_try_exec_main (method, args, exc);
4841 }
4842
4843
4844
4845 /** invoke_array_extract_argument:
4846  * @params: array of arguments to the method.
4847  * @i: the index of the argument to extract.
4848  * @t: ith type from the method signature.
4849  * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4850  * @error: set on error.
4851  *
4852  * Given an array of method arguments, return the ith one using the corresponding type
4853  * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4854  *
4855  * On failure sets @error and returns NULL.
4856  */
4857 static gpointer
4858 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4859 {
4860         MonoType *t_orig = t;
4861         gpointer result = NULL;
4862         error_init (error);
4863                 again:
4864                         switch (t->type) {
4865                         case MONO_TYPE_U1:
4866                         case MONO_TYPE_I1:
4867                         case MONO_TYPE_BOOLEAN:
4868                         case MONO_TYPE_U2:
4869                         case MONO_TYPE_I2:
4870                         case MONO_TYPE_CHAR:
4871                         case MONO_TYPE_U:
4872                         case MONO_TYPE_I:
4873                         case MONO_TYPE_U4:
4874                         case MONO_TYPE_I4:
4875                         case MONO_TYPE_U8:
4876                         case MONO_TYPE_I8:
4877                         case MONO_TYPE_R4:
4878                         case MONO_TYPE_R8:
4879                         case MONO_TYPE_VALUETYPE:
4880                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4881                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4882                                         result = mono_array_get (params, MonoObject*, i);
4883                                         if (t->byref)
4884                                                 *has_byref_nullables = TRUE;
4885                                 } else {
4886                                         /* MS seems to create the objects if a null is passed in */
4887                                         gboolean was_null = FALSE;
4888                                         if (!mono_array_get (params, MonoObject*, i)) {
4889                                                 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4890                                                 return_val_if_nok (error, NULL);
4891                                                 mono_array_setref (params, i, o); 
4892                                                 was_null = TRUE;
4893                                         }
4894
4895                                         if (t->byref) {
4896                                                 /*
4897                                                  * We can't pass the unboxed vtype byref to the callee, since
4898                                                  * that would mean the callee would be able to modify boxed
4899                                                  * primitive types. So we (and MS) make a copy of the boxed
4900                                                  * object, pass that to the callee, and replace the original
4901                                                  * boxed object in the arg array with the copy.
4902                                                  */
4903                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4904                                                 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4905                                                 return_val_if_nok (error, NULL);
4906                                                 mono_array_setref (params, i, copy);
4907                                         }
4908                                                 
4909                                         result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4910                                         if (!t->byref && was_null)
4911                                                 mono_array_setref (params, i, NULL);
4912                                 }
4913                                 break;
4914                         case MONO_TYPE_STRING:
4915                         case MONO_TYPE_OBJECT:
4916                         case MONO_TYPE_CLASS:
4917                         case MONO_TYPE_ARRAY:
4918                         case MONO_TYPE_SZARRAY:
4919                                 if (t->byref)
4920                                         result = mono_array_addr (params, MonoObject*, i);
4921                                         // FIXME: I need to check this code path
4922                                 else
4923                                         result = mono_array_get (params, MonoObject*, i);
4924                                 break;
4925                         case MONO_TYPE_GENERICINST:
4926                                 if (t->byref)
4927                                         t = &t->data.generic_class->container_class->this_arg;
4928                                 else
4929                                         t = &t->data.generic_class->container_class->byval_arg;
4930                                 goto again;
4931                         case MONO_TYPE_PTR: {
4932                                 MonoObject *arg;
4933
4934                                 /* The argument should be an IntPtr */
4935                                 arg = mono_array_get (params, MonoObject*, i);
4936                                 if (arg == NULL) {
4937                                         result = NULL;
4938                                 } else {
4939                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4940                                         result = ((MonoIntPtr*)arg)->m_value;
4941                                 }
4942                                 break;
4943                         }
4944                         default:
4945                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4946                         }
4947         return result;
4948 }
4949 /**
4950  * mono_runtime_invoke_array:
4951  * \param method method to invoke
4952  * \param obj object instance
4953  * \param params arguments to the method
4954  * \param exc exception information.
4955  * Invokes the method represented by \p method on the object \p obj.
4956  *
4957  * \p obj is the \c this pointer, it should be NULL for static
4958  * methods, a \c MonoObject* for object instances and a pointer to
4959  * the value type for value types.
4960  *
4961  * The \p params array contains the arguments to the method with the
4962  * same convention: \c MonoObject* pointers for object instances and
4963  * pointers to the value type otherwise. The \c _invoke_array
4964  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4965  * in this case the value types are boxed inside the
4966  * respective reference representation.
4967  * 
4968  * From unmanaged code you'll usually use the
4969  * mono_runtime_invoke_checked() variant.
4970  *
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).
4976  * 
4977  * You can pass NULL as the \p exc argument if you don't want to
4978  * catch exceptions, otherwise, \c *exc will be set to the exception
4979  * thrown, if any.  if an exception is thrown, you can't use the
4980  * \c MonoObject* result from the function.
4981  * 
4982  * If the method returns a value type, it is boxed in an object
4983  * reference.
4984  */
4985 MonoObject*
4986 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4987                            MonoObject **exc)
4988 {
4989         MonoError error;
4990         if (exc) {
4991                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4992                 if (*exc) {
4993                         mono_error_cleanup (&error);
4994                         return NULL;
4995                 } else {
4996                         if (!is_ok (&error))
4997                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4998                         return result;
4999                 }
5000         } else {
5001                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
5002                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
5003                 return result;
5004         }
5005 }
5006
5007 /**
5008  * mono_runtime_invoke_array_checked:
5009  * \param method method to invoke
5010  * \param obj object instance
5011  * \param params arguments to the method
5012  * \param error set on failure.
5013  * Invokes the method represented by \p method on the object \p obj.
5014  *
5015  * \p obj is the \c this pointer, it should be NULL for static
5016  * methods, a \c MonoObject* for object instances and a pointer to
5017  * the value type for value types.
5018  *
5019  * The \p params array contains the arguments to the method with the
5020  * same convention: \c MonoObject* pointers for object instances and
5021  * pointers to the value type otherwise. The \c _invoke_array
5022  * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5023  * in this case the value types are boxed inside the
5024  * respective reference representation.
5025  *
5026  * From unmanaged code you'll usually use the
5027  * mono_runtime_invoke_checked() variant.
5028  *
5029  * Note that this function doesn't handle virtual methods for
5030  * you, it will exec the exact method you pass: we still need to
5031  * expose a function to lookup the derived class implementation
5032  * of a virtual method (there are examples of this in the code,
5033  * though).
5034  *
5035  * On failure or exception, \p error will be set. In that case, you
5036  * can't use the \c MonoObject* result from the function.
5037  *
5038  * If the method returns a value type, it is boxed in an object
5039  * reference.
5040  */
5041 MonoObject*
5042 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5043                                    MonoError *error)
5044 {
5045         error_init (error);
5046         return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5047 }
5048
5049 /**
5050  * mono_runtime_try_invoke_array:
5051  * \param method method to invoke
5052  * \param obj object instance
5053  * \param params arguments to the method
5054  * \param exc exception information.
5055  * \param error set on failure.
5056  * Invokes the method represented by \p method on the object \p obj.
5057  *
5058  * \p obj is the \c this pointer, it should be NULL for static
5059  * methods, a \c MonoObject* for object instances and a pointer to
5060  * the value type for value types.
5061  *
5062  * The \p params array contains the arguments to the method with the
5063  * same convention: \c MonoObject* pointers for object instances and
5064  * pointers to the value type otherwise. The \c _invoke_array
5065  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5066  * in this case the value types are boxed inside the
5067  * respective reference representation.
5068  *
5069  * From unmanaged code you'll usually use the
5070  * mono_runtime_invoke_checked() variant.
5071  *
5072  * Note that this function doesn't handle virtual methods for
5073  * you, it will exec the exact method you pass: we still need to
5074  * expose a function to lookup the derived class implementation
5075  * of a virtual method (there are examples of this in the code,
5076  * though).
5077  *
5078  * You can pass NULL as the \p exc argument if you don't want to catch
5079  * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5080  * any.  On other failures, \p error will be set. If an exception is
5081  * thrown or there's an error, you can't use the \c MonoObject* result
5082  * from the function.
5083  *
5084  * If the method returns a value type, it is boxed in an object
5085  * reference.
5086  */
5087 MonoObject*
5088 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5089                                MonoObject **exc, MonoError *error)
5090 {
5091         MONO_REQ_GC_UNSAFE_MODE;
5092
5093         error_init (error);
5094
5095         MonoMethodSignature *sig = mono_method_signature (method);
5096         gpointer *pa = NULL;
5097         MonoObject *res;
5098         int i;
5099         gboolean has_byref_nullables = FALSE;
5100
5101         if (NULL != params) {
5102                 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5103                 for (i = 0; i < mono_array_length (params); i++) {
5104                         MonoType *t = sig->params [i];
5105                         pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5106                         return_val_if_nok (error, NULL);
5107                 }
5108         }
5109
5110         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5111                 void *o = obj;
5112
5113                 if (mono_class_is_nullable (method->klass)) {
5114                         /* Need to create a boxed vtype instead */
5115                         g_assert (!obj);
5116
5117                         if (!params)
5118                                 return NULL;
5119                         else {
5120                                 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5121                         }
5122                 }
5123
5124                 if (!obj) {
5125                         obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5126                         mono_error_assert_ok (error);
5127                         g_assert (obj); /*maybe we should raise a TLE instead?*/
5128 #ifndef DISABLE_REMOTING
5129                         if (mono_object_is_transparent_proxy (obj)) {
5130                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5131                         }
5132 #endif
5133                         if (method->klass->valuetype)
5134                                 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5135                         else
5136                                 o = obj;
5137                 } else if (method->klass->valuetype) {
5138                         obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5139                         return_val_if_nok (error, NULL);
5140                 }
5141
5142                 if (exc) {
5143                         mono_runtime_try_invoke (method, o, pa, exc, error);
5144                 } else {
5145                         mono_runtime_invoke_checked (method, o, pa, error);
5146                 }
5147
5148                 return (MonoObject *)obj;
5149         } else {
5150                 if (mono_class_is_nullable (method->klass)) {
5151                         MonoObject *nullable;
5152
5153                         /* Convert the unboxed vtype into a Nullable structure */
5154                         nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5155                         return_val_if_nok (error, NULL);
5156
5157                         MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5158                         return_val_if_nok (error, NULL);
5159                         mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5160                         obj = mono_object_unbox (nullable);
5161                 }
5162
5163                 /* obj must be already unboxed if needed */
5164                 if (exc) {
5165                         res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5166                 } else {
5167                         res = mono_runtime_invoke_checked (method, obj, pa, error);
5168                 }
5169                 return_val_if_nok (error, NULL);
5170
5171                 if (sig->ret->type == MONO_TYPE_PTR) {
5172                         MonoClass *pointer_class;
5173                         static MonoMethod *box_method;
5174                         void *box_args [2];
5175                         MonoObject *box_exc;
5176
5177                         /* 
5178                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
5179                          * convert it to a Pointer object.
5180                          */
5181                         pointer_class = mono_class_get_pointer_class ();
5182                         if (!box_method)
5183                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5184
5185                         g_assert (res->vtable->klass == mono_defaults.int_class);
5186                         box_args [0] = ((MonoIntPtr*)res)->m_value;
5187                         box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5188                         return_val_if_nok (error, NULL);
5189
5190                         res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5191                         g_assert (box_exc == NULL);
5192                         mono_error_assert_ok (error);
5193                 }
5194
5195                 if (has_byref_nullables) {
5196                         /* 
5197                          * The runtime invoke wrapper already converted byref nullables back,
5198                          * and stored them in pa, we just need to copy them back to the
5199                          * managed array.
5200                          */
5201                         for (i = 0; i < mono_array_length (params); i++) {
5202                                 MonoType *t = sig->params [i];
5203
5204                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5205                                         mono_array_setref (params, i, pa [i]);
5206                         }
5207                 }
5208
5209                 return res;
5210         }
5211 }
5212
5213 /**
5214  * mono_object_new:
5215  * \param klass the class of the object that we want to create
5216  * \returns a newly created object whose definition is
5217  * looked up using \p klass.   This will not invoke any constructors, 
5218  * so the consumer of this routine has to invoke any constructors on
5219  * its own to initialize the object.
5220  * 
5221  * It returns NULL on failure.
5222  */
5223 MonoObject *
5224 mono_object_new (MonoDomain *domain, MonoClass *klass)
5225 {
5226         MONO_REQ_GC_UNSAFE_MODE;
5227
5228         MonoError error;
5229
5230         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5231
5232         mono_error_cleanup (&error);
5233         return result;
5234 }
5235
5236 MonoObject *
5237 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5238 {
5239         MONO_REQ_GC_UNSAFE_MODE;
5240
5241         MonoError error;
5242
5243         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5244
5245         mono_error_set_pending_exception (&error);
5246         return result;
5247 }
5248
5249 /**
5250  * mono_object_new_checked:
5251  * \param klass the class of the object that we want to create
5252  * \param error set on error
5253  * \returns a newly created object whose definition is
5254  * looked up using \p klass.   This will not invoke any constructors,
5255  * so the consumer of this routine has to invoke any constructors on
5256  * its own to initialize the object.
5257  *
5258  * It returns NULL on failure and sets \p error.
5259  */
5260 MonoObject *
5261 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5262 {
5263         MONO_REQ_GC_UNSAFE_MODE;
5264
5265         MonoVTable *vtable;
5266
5267         vtable = mono_class_vtable_full (domain, klass, error);
5268         if (!is_ok (error))
5269                 return NULL;
5270
5271         MonoObject *o = mono_object_new_specific_checked (vtable, error);
5272         return o;
5273 }
5274
5275 /**
5276  * mono_object_new_pinned:
5277  *
5278  *   Same as mono_object_new, but the returned object will be pinned.
5279  * For SGEN, these objects will only be freed at appdomain unload.
5280  */
5281 MonoObject *
5282 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5283 {
5284         MONO_REQ_GC_UNSAFE_MODE;
5285
5286         MonoVTable *vtable;
5287
5288         error_init (error);
5289
5290         vtable = mono_class_vtable (domain, klass);
5291         g_assert (vtable); /* FIXME don't swallow the error */
5292
5293         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5294
5295         if (G_UNLIKELY (!o))
5296                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5297         else if (G_UNLIKELY (vtable->klass->has_finalize))
5298                 mono_object_register_finalizer (o);
5299
5300         return o;
5301 }
5302
5303 /**
5304  * mono_object_new_specific:
5305  * \param vtable the vtable of the object that we want to create
5306  * \returns A newly created object with class and domain specified
5307  * by \p vtable
5308  */
5309 MonoObject *
5310 mono_object_new_specific (MonoVTable *vtable)
5311 {
5312         MonoError error;
5313         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5314         mono_error_cleanup (&error);
5315
5316         return o;
5317 }
5318
5319 MonoObject *
5320 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5321 {
5322         MONO_REQ_GC_UNSAFE_MODE;
5323
5324         MonoObject *o;
5325
5326         error_init (error);
5327
5328         /* check for is_com_object for COM Interop */
5329         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5330         {
5331                 gpointer pa [1];
5332                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5333
5334                 if (im == NULL) {
5335                         MonoClass *klass = mono_class_get_activation_services_class ();
5336
5337                         if (!klass->inited)
5338                                 mono_class_init (klass);
5339
5340                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5341                         if (!im) {
5342                                 mono_error_set_not_supported (error, "Linked away.");
5343                                 return NULL;
5344                         }
5345                         vtable->domain->create_proxy_for_type_method = im;
5346                 }
5347         
5348                 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5349                 if (!mono_error_ok (error))
5350                         return NULL;
5351
5352                 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5353                 if (!mono_error_ok (error))
5354                         return NULL;
5355
5356                 if (o != NULL)
5357                         return o;
5358         }
5359
5360         return mono_object_new_alloc_specific_checked (vtable, error);
5361 }
5362
5363 MonoObject *
5364 ves_icall_object_new_specific (MonoVTable *vtable)
5365 {
5366         MonoError error;
5367         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5368         mono_error_set_pending_exception (&error);
5369
5370         return o;
5371 }
5372
5373 /**
5374  * mono_object_new_alloc_specific:
5375  * \param vtable virtual table for the object.
5376  * This function allocates a new \c MonoObject with the type derived
5377  * from the \p vtable information.   If the class of this object has a 
5378  * finalizer, then the object will be tracked for finalization.
5379  *
5380  * This method might raise an exception on errors.  Use the
5381  * \c mono_object_new_fast_checked method if you want to manually raise
5382  * the exception.
5383  *
5384  * \returns the allocated object.   
5385  */
5386 MonoObject *
5387 mono_object_new_alloc_specific (MonoVTable *vtable)
5388 {
5389         MonoError error;
5390         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5391         mono_error_cleanup (&error);
5392
5393         return o;
5394 }
5395
5396 /**
5397  * mono_object_new_alloc_specific_checked:
5398  * \param vtable virtual table for the object.
5399  * \param error holds the error return value.  
5400  *
5401  * This function allocates a new \c MonoObject with the type derived
5402  * from the \p vtable information. If the class of this object has a 
5403  * finalizer, then the object will be tracked for finalization.
5404  *
5405  * If there is not enough memory, the \p error parameter will be set
5406  * and will contain a user-visible message with the amount of bytes
5407  * that were requested.
5408  *
5409  * \returns the allocated object, or NULL if there is not enough memory
5410  */
5411 MonoObject *
5412 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5413 {
5414         MONO_REQ_GC_UNSAFE_MODE;
5415
5416         MonoObject *o;
5417
5418         error_init (error);
5419
5420         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5421
5422         if (G_UNLIKELY (!o))
5423                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5424         else if (G_UNLIKELY (vtable->klass->has_finalize))
5425                 mono_object_register_finalizer (o);
5426
5427         return o;
5428 }
5429
5430 /**
5431  * mono_object_new_fast:
5432  * \param vtable virtual table for the object.
5433  *
5434  * This function allocates a new \c MonoObject with the type derived
5435  * from the \p vtable information.   The returned object is not tracked
5436  * for finalization.   If your object implements a finalizer, you should
5437  * use \c mono_object_new_alloc_specific instead.
5438  *
5439  * This method might raise an exception on errors.  Use the
5440  * \c mono_object_new_fast_checked method if you want to manually raise
5441  * the exception.
5442  *
5443  * \returns the allocated object.   
5444  */
5445 MonoObject*
5446 mono_object_new_fast (MonoVTable *vtable)
5447 {
5448         MonoError error;
5449         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5450         mono_error_cleanup (&error);
5451
5452         return o;
5453 }
5454
5455 /**
5456  * mono_object_new_fast_checked:
5457  * \param vtable virtual table for the object.
5458  * \param error holds the error return value.
5459  *
5460  * This function allocates a new \c MonoObject with the type derived
5461  * from the \p vtable information. The returned object is not tracked
5462  * for finalization.   If your object implements a finalizer, you should
5463  * use \c mono_object_new_alloc_specific_checked instead.
5464  *
5465  * If there is not enough memory, the \p error parameter will be set
5466  * and will contain a user-visible message with the amount of bytes
5467  * that were requested.
5468  *
5469  * \returns the allocated object, or NULL if there is not enough memory
5470  */
5471 MonoObject*
5472 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5473 {
5474         MONO_REQ_GC_UNSAFE_MODE;
5475
5476         MonoObject *o;
5477
5478         error_init (error);
5479
5480         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5481
5482         if (G_UNLIKELY (!o))
5483                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5484
5485         return o;
5486 }
5487
5488 MonoObject*
5489 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5490 {
5491         MONO_REQ_GC_UNSAFE_MODE;
5492
5493         MonoObject *o;
5494
5495         error_init (error);
5496
5497         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5498
5499         if (G_UNLIKELY (!o))
5500                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5501         else if (G_UNLIKELY (vtable->klass->has_finalize))
5502                 mono_object_register_finalizer (o);
5503
5504         return o;
5505 }
5506
5507 /**
5508  * mono_object_new_from_token:
5509  * \param image Context where the type_token is hosted
5510  * \param token a token of the type that we want to create
5511  * \returns A newly created object whose definition is
5512  * looked up using \p token in the \p image image
5513  */
5514 MonoObject *
5515 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
5516 {
5517         MONO_REQ_GC_UNSAFE_MODE;
5518
5519         MonoError error;
5520         MonoObject *result;
5521         MonoClass *klass;
5522
5523         klass = mono_class_get_checked (image, token, &error);
5524         mono_error_assert_ok (&error);
5525         
5526         result = mono_object_new_checked (domain, klass, &error);
5527
5528         mono_error_cleanup (&error);
5529         return result;
5530         
5531 }
5532
5533
5534 /**
5535  * mono_object_clone:
5536  * \param obj the object to clone
5537  * \returns A newly created object who is a shallow copy of \p obj
5538  */
5539 MonoObject *
5540 mono_object_clone (MonoObject *obj)
5541 {
5542         MonoError error;
5543         MonoObject *o = mono_object_clone_checked (obj, &error);
5544         mono_error_cleanup (&error);
5545
5546         return o;
5547 }
5548
5549 MonoObject *
5550 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5551 {
5552         MONO_REQ_GC_UNSAFE_MODE;
5553
5554         MonoObject *o;
5555         int size;
5556
5557         error_init (error);
5558
5559         size = obj->vtable->klass->instance_size;
5560
5561         if (obj->vtable->klass->rank)
5562                 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5563
5564         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5565
5566         if (G_UNLIKELY (!o)) {
5567                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5568                 return NULL;
5569         }
5570
5571         /* If the object doesn't contain references this will do a simple memmove. */
5572         mono_gc_wbarrier_object_copy (o, obj);
5573
5574         if (obj->vtable->klass->has_finalize)
5575                 mono_object_register_finalizer (o);
5576         return o;
5577 }
5578
5579 /**
5580  * mono_array_full_copy:
5581  * \param src source array to copy
5582  * \param dest destination array
5583  * Copies the content of one array to another with exactly the same type and size.
5584  */
5585 void
5586 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5587 {
5588         MONO_REQ_GC_UNSAFE_MODE;
5589
5590         uintptr_t size;
5591         MonoClass *klass = src->obj.vtable->klass;
5592
5593         g_assert (klass == dest->obj.vtable->klass);
5594
5595         size = mono_array_length (src);
5596         g_assert (size == mono_array_length (dest));
5597         size *= mono_array_element_size (klass);
5598
5599         array_full_copy_unchecked_size (src, dest, klass, size);
5600 }
5601
5602 static void
5603 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5604 {
5605         if (mono_gc_is_moving ()) {
5606                 if (klass->element_class->valuetype) {
5607                         if (klass->element_class->has_references)
5608                                 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5609                         else
5610                                 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5611                 } else {
5612                         mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5613                 }
5614         } else {
5615                 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5616         }
5617 }
5618
5619 /**
5620  * mono_array_clone_in_domain:
5621  * \param domain the domain in which the array will be cloned into
5622  * \param array the array to clone
5623  * \param error set on error
5624  * This routine returns a copy of the array that is hosted on the
5625  * specified \c MonoDomain.  On failure returns NULL and sets \p error.
5626  */
5627 MonoArrayHandle
5628 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5629 {
5630         MONO_REQ_GC_UNSAFE_MODE;
5631
5632         MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5633         uintptr_t size = 0;
5634         MonoClass *klass = mono_handle_class (array_handle);
5635
5636         error_init (error);
5637
5638         /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5639         uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5640         
5641         MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5642         MonoArrayHandle o;
5643         if (array_bounds == NULL) {
5644                 size = mono_array_handle_length (array_handle);
5645                 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5646                 if (!is_ok (error))
5647                         goto leave;
5648                 size *= mono_array_element_size (klass);
5649         } else {
5650                 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5651                 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5652                 size = mono_array_element_size (klass);
5653                 for (int i = 0; i < klass->rank; ++i) {
5654                         sizes [i] = array_bounds [i].length;
5655                         size *= array_bounds [i].length;
5656                         lower_bounds [i] = array_bounds [i].lower_bound;
5657                 }
5658                 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5659                 if (!is_ok (error))
5660                         goto leave;
5661         }
5662
5663         uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5664         array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5665         mono_gchandle_free (dst_handle);
5666
5667         MONO_HANDLE_ASSIGN (result, o);
5668
5669 leave:
5670         mono_gchandle_free (src_handle);
5671         return result;
5672 }
5673
5674 /**
5675  * mono_array_clone:
5676  * \param array the array to clone
5677  * \returns A newly created array who is a shallow copy of \p array
5678  */
5679 MonoArray*
5680 mono_array_clone (MonoArray *array)
5681 {
5682         MONO_REQ_GC_UNSAFE_MODE;
5683
5684         MonoError error;
5685         MonoArray *result = mono_array_clone_checked (array, &error);
5686         mono_error_cleanup (&error);
5687         return result;
5688 }
5689
5690 /**
5691  * mono_array_clone_checked:
5692  * \param array the array to clone
5693  * \param error set on error
5694  * \returns A newly created array who is a shallow copy of \p array.  On
5695  * failure returns NULL and sets \p error.
5696  */
5697 MonoArray*
5698 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5699 {
5700         MONO_REQ_GC_UNSAFE_MODE;
5701         HANDLE_FUNCTION_ENTER ();
5702         /* FIXME: callers of mono_array_clone_checked should use handles */
5703         error_init (error);
5704         MONO_HANDLE_DCL (MonoArray, array);
5705         MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5706         HANDLE_FUNCTION_RETURN_OBJ (result);
5707 }
5708
5709 /* helper macros to check for overflow when calculating the size of arrays */
5710 #ifdef MONO_BIG_ARRAYS
5711 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5712 #define MYGUINT_MAX MYGUINT64_MAX
5713 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5714             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5715 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5716             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
5717                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5718 #else
5719 #define MYGUINT32_MAX 4294967295U
5720 #define MYGUINT_MAX MYGUINT32_MAX
5721 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5722             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5723 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5724             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
5725                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5726 #endif
5727
5728 gboolean
5729 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5730 {
5731         MONO_REQ_GC_NEUTRAL_MODE;
5732
5733         uintptr_t byte_len;
5734
5735         byte_len = mono_array_element_size (klass);
5736         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5737                 return FALSE;
5738         byte_len *= len;
5739         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5740                 return FALSE;
5741         byte_len += MONO_SIZEOF_MONO_ARRAY;
5742
5743         *res = byte_len;
5744
5745         return TRUE;
5746 }
5747
5748 /**
5749  * mono_array_new_full:
5750  * \param domain domain where the object is created
5751  * \param array_class array class
5752  * \param lengths lengths for each dimension in the array
5753  * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5754  * This routine creates a new array object with the given dimensions,
5755  * lower bounds and type.
5756  */
5757 MonoArray*
5758 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5759 {
5760         MonoError error;
5761         MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5762         mono_error_cleanup (&error);
5763
5764         return array;
5765 }
5766
5767 MonoArray*
5768 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5769 {
5770         MONO_REQ_GC_UNSAFE_MODE;
5771
5772         uintptr_t byte_len = 0, len, bounds_size;
5773         MonoObject *o;
5774         MonoArray *array;
5775         MonoArrayBounds *bounds;
5776         MonoVTable *vtable;
5777         int i;
5778
5779         error_init (error);
5780
5781         if (!array_class->inited)
5782                 mono_class_init (array_class);
5783
5784         len = 1;
5785
5786         /* A single dimensional array with a 0 lower bound is the same as an szarray */
5787         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5788                 len = lengths [0];
5789                 if (len > MONO_ARRAY_MAX_INDEX) {
5790                         mono_error_set_generic_error (error, "System", "OverflowException", "");
5791                         return NULL;
5792                 }
5793                 bounds_size = 0;
5794         } else {
5795                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5796
5797                 for (i = 0; i < array_class->rank; ++i) {
5798                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5799                                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5800                                 return NULL;
5801                         }
5802                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5803                                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5804                                 return NULL;
5805                         }
5806                         len *= lengths [i];
5807                 }
5808         }
5809
5810         if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5811                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5812                 return NULL;
5813         }
5814
5815         if (bounds_size) {
5816                 /* align */
5817                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5818                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5819                         return NULL;
5820                 }
5821                 byte_len = (byte_len + 3) & ~3;
5822                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5823                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5824                         return NULL;
5825                 }
5826                 byte_len += bounds_size;
5827         }
5828         /* 
5829          * Following three lines almost taken from mono_object_new ():
5830          * they need to be kept in sync.
5831          */
5832         vtable = mono_class_vtable_full (domain, array_class, error);
5833         return_val_if_nok (error, NULL);
5834
5835         if (bounds_size)
5836                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5837         else
5838                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5839
5840         if (G_UNLIKELY (!o)) {
5841                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5842                 return NULL;
5843         }
5844
5845         array = (MonoArray*)o;
5846
5847         bounds = array->bounds;
5848
5849         if (bounds_size) {
5850                 for (i = 0; i < array_class->rank; ++i) {
5851                         bounds [i].length = lengths [i];
5852                         if (lower_bounds)
5853                                 bounds [i].lower_bound = lower_bounds [i];
5854                 }
5855         }
5856
5857         return array;
5858 }
5859
5860 /**
5861  * mono_array_new:
5862  * \param domain domain where the object is created
5863  * \param eclass element class
5864  * \param n number of array elements
5865  * This routine creates a new szarray with \p n elements of type \p eclass.
5866  */
5867 MonoArray *
5868 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5869 {
5870         MONO_REQ_GC_UNSAFE_MODE;
5871
5872         MonoError error;
5873         MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5874         mono_error_cleanup (&error);
5875         return result;
5876 }
5877
5878 /**
5879  * mono_array_new_checked:
5880  * \param domain domain where the object is created
5881  * \param eclass element class
5882  * \param n number of array elements
5883  * \param error set on error
5884  * This routine creates a new szarray with \p n elements of type \p eclass.
5885  * On failure returns NULL and sets \p error.
5886  */
5887 MonoArray *
5888 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5889 {
5890         MonoClass *ac;
5891
5892         error_init (error);
5893
5894         ac = mono_array_class_get (eclass, 1);
5895         g_assert (ac);
5896
5897         MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5898         return_val_if_nok (error, NULL);
5899
5900         return mono_array_new_specific_checked (vtable, n, error);
5901 }
5902
5903 MonoArray*
5904 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5905 {
5906         MonoError error;
5907         MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5908         mono_error_set_pending_exception (&error);
5909
5910         return arr;
5911 }
5912
5913 /**
5914  * mono_array_new_specific:
5915  * \param vtable a vtable in the appropriate domain for an initialized class
5916  * \param n number of array elements
5917  * This routine is a fast alternative to \c mono_array_new for code which
5918  * can be sure about the domain it operates in.
5919  */
5920 MonoArray *
5921 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5922 {
5923         MonoError error;
5924         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5925         mono_error_cleanup (&error);
5926
5927         return arr;
5928 }
5929
5930 MonoArray*
5931 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5932 {
5933         MONO_REQ_GC_UNSAFE_MODE;
5934
5935         MonoObject *o;
5936         uintptr_t byte_len;
5937
5938         error_init (error);
5939
5940         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5941                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5942                 return NULL;
5943         }
5944
5945         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5946                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5947                 return NULL;
5948         }
5949         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5950
5951         if (G_UNLIKELY (!o)) {
5952                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5953                 return NULL;
5954         }
5955
5956         return (MonoArray*)o;
5957 }
5958
5959 MonoArray*
5960 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5961 {
5962         MonoError error;
5963         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5964         mono_error_set_pending_exception (&error);
5965
5966         return arr;
5967 }
5968
5969 /**
5970  * mono_string_empty_wrapper:
5971  *
5972  * Returns: The same empty string instance as the managed string.Empty
5973  */
5974 MonoString*
5975 mono_string_empty_wrapper (void)
5976 {
5977         MonoDomain *domain = mono_domain_get ();
5978         return mono_string_empty (domain);
5979 }
5980
5981 /**
5982  * mono_string_empty:
5983  *
5984  * Returns: The same empty string instance as the managed string.Empty
5985  */
5986 MonoString*
5987 mono_string_empty (MonoDomain *domain)
5988 {
5989         g_assert (domain);
5990         g_assert (domain->empty_string);
5991         return domain->empty_string;
5992 }
5993
5994 /**
5995  * mono_string_new_utf16:
5996  * \param text a pointer to an utf16 string
5997  * \param len the length of the string
5998  * \returns A newly created string object which contains \p text.
5999  */
6000 MonoString *
6001 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6002 {
6003         MONO_REQ_GC_UNSAFE_MODE;
6004
6005         MonoError error;
6006         MonoString *res = NULL;
6007         res = mono_string_new_utf16_checked (domain, text, len, &error);
6008         mono_error_cleanup (&error);
6009
6010         return res;
6011 }
6012
6013 /**
6014  * mono_string_new_utf16_checked:
6015  * \param text a pointer to an utf16 string
6016  * \param len the length of the string
6017  * \param error written on error.
6018  * \returns A newly created string object which contains \p text.
6019  * On error, returns NULL and sets \p error.
6020  */
6021 MonoString *
6022 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6023 {
6024         MONO_REQ_GC_UNSAFE_MODE;
6025
6026         MonoString *s;
6027         
6028         error_init (error);
6029         
6030         s = mono_string_new_size_checked (domain, len, error);
6031         if (s != NULL)
6032                 memcpy (mono_string_chars (s), text, len * 2);
6033
6034         return s;
6035 }
6036
6037 /**
6038  * mono_string_new_utf16_handle:
6039  * \param text a pointer to an utf16 string
6040  * \param len the length of the string
6041  * \param error written on error.
6042  * \returns A newly created string object which contains \p text.
6043  * On error, returns NULL and sets \p error.
6044  */
6045 MonoStringHandle
6046 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6047 {
6048         return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6049 }
6050
6051 /**
6052  * mono_string_new_utf32_checked:
6053  * \param text a pointer to an utf32 string
6054  * \param len the length of the string
6055  * \param error set on failure.
6056  * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6057  */
6058 static MonoString *
6059 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6060 {
6061         MONO_REQ_GC_UNSAFE_MODE;
6062
6063         MonoString *s;
6064         mono_unichar2 *utf16_output = NULL;
6065         gint32 utf16_len = 0;
6066         GError *gerror = NULL;
6067         glong items_written;
6068         
6069         error_init (error);
6070         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6071         
6072         if (gerror)
6073                 g_error_free (gerror);
6074
6075         while (utf16_output [utf16_len]) utf16_len++;
6076         
6077         s = mono_string_new_size_checked (domain, utf16_len, error);
6078         return_val_if_nok (error, NULL);
6079
6080         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6081
6082         g_free (utf16_output);
6083         
6084         return s;
6085 }
6086
6087 /**
6088  * mono_string_new_utf32:
6089  * \param text a pointer to a UTF-32 string
6090  * \param len the length of the string
6091  * \returns A newly created string object which contains \p text.
6092  */
6093 MonoString *
6094 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6095 {
6096         MonoError error;
6097         MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6098         mono_error_cleanup (&error);
6099         return result;
6100 }
6101
6102 /**
6103  * mono_string_new_size:
6104  * \param text a pointer to a UTF-16 string
6105  * \param len the length of the string
6106  * \returns A newly created string object of \p len
6107  */
6108 MonoString *
6109 mono_string_new_size (MonoDomain *domain, gint32 len)
6110 {
6111         MonoError error;
6112         MonoString *str = mono_string_new_size_checked (domain, len, &error);
6113         mono_error_cleanup (&error);
6114
6115         return str;
6116 }
6117
6118 MonoString *
6119 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6120 {
6121         MONO_REQ_GC_UNSAFE_MODE;
6122
6123         MonoString *s;
6124         MonoVTable *vtable;
6125         size_t size;
6126
6127         error_init (error);
6128
6129         /* check for overflow */
6130         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6131                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6132                 return NULL;
6133         }
6134
6135         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6136         g_assert (size > 0);
6137
6138         vtable = mono_class_vtable (domain, mono_defaults.string_class);
6139         g_assert (vtable);
6140
6141         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6142
6143         if (G_UNLIKELY (!s)) {
6144                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6145                 return NULL;
6146         }
6147
6148         return s;
6149 }
6150
6151 /**
6152  * mono_string_new_len:
6153  * \param text a pointer to an utf8 string
6154  * \param length number of bytes in \p text to consider
6155  * \returns A newly created string object which contains \p text.
6156  */
6157 MonoString*
6158 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6159 {
6160         MONO_REQ_GC_UNSAFE_MODE;
6161
6162         MonoError error;
6163         MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6164         mono_error_cleanup (&error);
6165         return result;
6166 }
6167
6168 /**
6169  * mono_string_new_len_checked:
6170  * \param text a pointer to an utf8 string
6171  * \param length number of bytes in \p text to consider
6172  * \param error set on error
6173  * \returns A newly created string object which contains \p text. On
6174  * failure returns NULL and sets \p error.
6175  */
6176 MonoString*
6177 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6178 {
6179         MONO_REQ_GC_UNSAFE_MODE;
6180
6181         error_init (error);
6182
6183         GError *eg_error = NULL;
6184         MonoString *o = NULL;
6185         guint16 *ut = NULL;
6186         glong items_written;
6187
6188         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6189
6190         if (!eg_error)
6191                 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6192         else 
6193                 g_error_free (eg_error);
6194
6195         g_free (ut);
6196
6197         return o;
6198 }
6199
6200 /**
6201  * mono_string_new:
6202  * \param text a pointer to a UTF-8 string
6203  * \deprecated Use \c mono_string_new_checked in new code.
6204  * This function asserts if it cannot allocate a new string.
6205  * \returns A newly created string object which contains \p text.
6206  */
6207 MonoString*
6208 mono_string_new (MonoDomain *domain, const char *text)
6209 {
6210         MonoError error;
6211         MonoString *res = NULL;
6212         res = mono_string_new_checked (domain, text, &error);
6213         mono_error_assert_ok (&error);
6214         return res;
6215 }
6216
6217 /**
6218  * mono_string_new_checked:
6219  * \param text a pointer to an utf8 string
6220  * \param merror set on error
6221  * \returns A newly created string object which contains \p text.
6222  * On error returns NULL and sets \p merror.
6223  */
6224 MonoString*
6225 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6226 {
6227         MONO_REQ_GC_UNSAFE_MODE;
6228
6229         GError *eg_error = NULL;
6230         MonoString *o = NULL;
6231         guint16 *ut;
6232         glong items_written;
6233         int l;
6234
6235         error_init (error);
6236         
6237         l = strlen (text);
6238         
6239         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6240         
6241         if (!eg_error) {
6242                 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6243         } else {
6244                 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6245         }
6246         
6247         g_free (ut);
6248     
6249 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6250 #if 0
6251         gunichar2 *str;
6252         const gchar *end;
6253         int len;
6254         MonoString *o = NULL;
6255
6256         if (!g_utf8_validate (text, -1, &end)) {
6257                 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6258                 goto leave;
6259         }
6260
6261         len = g_utf8_strlen (text, -1);
6262         o = mono_string_new_size_checked (domain, len, error);
6263         if (!o)
6264                 goto leave;
6265         str = mono_string_chars (o);
6266
6267         while (text < end) {
6268                 *str++ = g_utf8_get_char (text);
6269                 text = g_utf8_next_char (text);
6270         }
6271
6272 leave:
6273 #endif
6274         return o;
6275 }
6276
6277 /**
6278  * mono_string_new_wrapper:
6279  * \param text pointer to UTF-8 characters.
6280  * Helper function to create a string object from \p text in the current domain.
6281  */
6282 MonoString*
6283 mono_string_new_wrapper (const char *text)
6284 {
6285         MONO_REQ_GC_UNSAFE_MODE;
6286
6287         MonoDomain *domain = mono_domain_get ();
6288
6289         if (text) {
6290                 MonoError error;
6291                 MonoString *result = mono_string_new_checked (domain, text, &error);
6292                 mono_error_assert_ok (&error);
6293                 return result;
6294         }
6295
6296         return NULL;
6297 }
6298
6299 /**
6300  * mono_value_box:
6301  * \param class the class of the value
6302  * \param value a pointer to the unboxed data
6303  * \returns A newly created object which contains \p value.
6304  */
6305 MonoObject *
6306 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6307 {
6308         MonoError error;
6309         MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6310         mono_error_cleanup (&error);
6311         return result;
6312 }
6313
6314 /**
6315  * mono_value_box_checked:
6316  * \param domain the domain of the new object
6317  * \param class the class of the value
6318  * \param value a pointer to the unboxed data
6319  * \param error set on error
6320  * \returns A newly created object which contains \p value. On failure
6321  * returns NULL and sets \p error.
6322  */
6323 MonoObject *
6324 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6325 {
6326         MONO_REQ_GC_UNSAFE_MODE;
6327         MonoObject *res;
6328         int size;
6329         MonoVTable *vtable;
6330
6331         error_init (error);
6332
6333         g_assert (klass->valuetype);
6334         if (mono_class_is_nullable (klass))
6335                 return mono_nullable_box ((guint8 *)value, klass, error);
6336
6337         vtable = mono_class_vtable (domain, klass);
6338         if (!vtable)
6339                 return NULL;
6340         size = mono_class_instance_size (klass);
6341         res = mono_object_new_alloc_specific_checked (vtable, error);
6342         return_val_if_nok (error, NULL);
6343
6344         size = size - sizeof (MonoObject);
6345
6346         if (mono_gc_is_moving ()) {
6347                 g_assert (size == mono_class_value_size (klass, NULL));
6348                 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6349         } else {
6350 #if NO_UNALIGNED_ACCESS
6351                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6352 #else
6353                 switch (size) {
6354                 case 1:
6355                         *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6356                         break;
6357                 case 2:
6358                         *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6359                         break;
6360                 case 4:
6361                         *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6362                         break;
6363                 case 8:
6364                         *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6365                         break;
6366                 default:
6367                         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6368                 }
6369 #endif
6370         }
6371         if (klass->has_finalize) {
6372                 mono_object_register_finalizer (res);
6373                 return_val_if_nok (error, NULL);
6374         }
6375         return res;
6376 }
6377
6378 /**
6379  * mono_value_copy:
6380  * \param dest destination pointer
6381  * \param src source pointer
6382  * \param klass a valuetype class
6383  * Copy a valuetype from \p src to \p dest. This function must be used
6384  * when \p klass contains reference fields.
6385  */
6386 void
6387 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6388 {
6389         MONO_REQ_GC_UNSAFE_MODE;
6390
6391         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6392 }
6393
6394 /**
6395  * mono_value_copy_array:
6396  * \param dest destination array
6397  * \param dest_idx index in the \p dest array
6398  * \param src source pointer
6399  * \param count number of items
6400  * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx. 
6401  * This function must be used when \p klass contains references fields.
6402  * Overlap is handled.
6403  */
6404 void
6405 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6406 {
6407         MONO_REQ_GC_UNSAFE_MODE;
6408
6409         int size = mono_array_element_size (dest->obj.vtable->klass);
6410         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6411         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6412         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6413 }
6414
6415 /**
6416  * mono_object_get_domain:
6417  * \param obj object to query
6418  * \returns the \c MonoDomain where the object is hosted
6419  */
6420 MonoDomain*
6421 mono_object_get_domain (MonoObject *obj)
6422 {
6423         MONO_REQ_GC_UNSAFE_MODE;
6424
6425         return mono_object_domain (obj);
6426 }
6427
6428 /**
6429  * mono_object_get_class:
6430  * \param obj object to query
6431  * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6432  * \returns the \c MonoClass of the object.
6433  */
6434 MonoClass*
6435 mono_object_get_class (MonoObject *obj)
6436 {
6437         MONO_REQ_GC_UNSAFE_MODE;
6438
6439         return mono_object_class (obj);
6440 }
6441 /**
6442  * mono_object_get_size:
6443  * \param o object to query
6444  * \returns the size, in bytes, of \p o
6445  */
6446 guint
6447 mono_object_get_size (MonoObject* o)
6448 {
6449         MONO_REQ_GC_UNSAFE_MODE;
6450
6451         MonoClass* klass = mono_object_class (o);
6452         if (klass == mono_defaults.string_class) {
6453                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6454         } else if (o->vtable->rank) {
6455                 MonoArray *array = (MonoArray*)o;
6456                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6457                 if (array->bounds) {
6458                         size += 3;
6459                         size &= ~3;
6460                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
6461                 }
6462                 return size;
6463         } else {
6464                 return mono_class_instance_size (klass);
6465         }
6466 }
6467
6468 /**
6469  * mono_object_unbox:
6470  * \param obj object to unbox
6471  * \returns a pointer to the start of the valuetype boxed in this
6472  * object.
6473  *
6474  * This method will assert if the object passed is not a valuetype.
6475  */
6476 gpointer
6477 mono_object_unbox (MonoObject *obj)
6478 {
6479         MONO_REQ_GC_UNSAFE_MODE;
6480
6481         /* add assert for valuetypes? */
6482         g_assert (obj->vtable->klass->valuetype);
6483         return ((char*)obj) + sizeof (MonoObject);
6484 }
6485
6486 /**
6487  * mono_object_isinst:
6488  * \param obj an object
6489  * \param klass a pointer to a class 
6490  * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6491  */
6492 MonoObject *
6493 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6494 {
6495         MONO_REQ_GC_UNSAFE_MODE;
6496
6497         HANDLE_FUNCTION_ENTER ();
6498         MONO_HANDLE_DCL (MonoObject, obj);
6499         MonoError error;
6500         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6501         mono_error_cleanup (&error);
6502         HANDLE_FUNCTION_RETURN_OBJ (result);
6503 }
6504         
6505
6506 /**
6507  * mono_object_isinst_checked:
6508  * \param obj an object
6509  * \param klass a pointer to a class 
6510  * \param error set on error
6511  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6512  * On failure returns NULL and sets \p error.
6513  */
6514 MonoObject *
6515 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6516 {
6517         MONO_REQ_GC_UNSAFE_MODE;
6518
6519         HANDLE_FUNCTION_ENTER ();
6520         error_init (error);
6521         MONO_HANDLE_DCL (MonoObject, obj);
6522         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6523         HANDLE_FUNCTION_RETURN_OBJ (result);
6524 }
6525
6526 /**
6527  * mono_object_handle_isinst:
6528  * \param obj an object
6529  * \param klass a pointer to a class 
6530  * \param error set on error
6531  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6532  * On failure returns NULL and sets \p error.
6533  */
6534 MonoObjectHandle
6535 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6536 {
6537         error_init (error);
6538         
6539         if (!klass->inited)
6540                 mono_class_init (klass);
6541
6542         if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6543                 return mono_object_handle_isinst_mbyref (obj, klass, error);
6544         }
6545
6546         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6547
6548         if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6549                 MONO_HANDLE_ASSIGN (result, obj);
6550         return result;
6551 }
6552
6553 /**
6554  * mono_object_isinst_mbyref:
6555  */
6556 MonoObject *
6557 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6558 {
6559         MONO_REQ_GC_UNSAFE_MODE;
6560
6561         HANDLE_FUNCTION_ENTER ();
6562         MonoError error;
6563         MONO_HANDLE_DCL (MonoObject, obj);
6564         MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6565         mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6566         HANDLE_FUNCTION_RETURN_OBJ (result);
6567 }
6568
6569 MonoObjectHandle
6570 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6571 {
6572         error_init (error);
6573
6574         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6575
6576         if (MONO_HANDLE_IS_NULL (obj))
6577                 goto leave;
6578
6579         MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6580         
6581         if (mono_class_is_interface (klass)) {
6582                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6583                         MONO_HANDLE_ASSIGN (result, obj);
6584                         goto leave;
6585                 }
6586
6587                 /* casting an array one of the invariant interfaces that must act as such */
6588                 if (klass->is_array_special_interface) {
6589                         if (mono_class_is_assignable_from (klass, vt->klass)) {
6590                                 MONO_HANDLE_ASSIGN (result, obj);
6591                                 goto leave;
6592                         }
6593                 }
6594
6595                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6596                 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6597                         MONO_HANDLE_ASSIGN (result, obj);
6598                         goto leave;
6599                 }
6600         } else {
6601                 MonoClass *oklass = vt->klass;
6602                 if (mono_class_is_transparent_proxy (oklass)){
6603                         MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6604                         oklass = remote_class->proxy_class;
6605                 }
6606
6607                 mono_class_setup_supertypes (klass);    
6608                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6609                         MONO_HANDLE_ASSIGN (result, obj);
6610                         goto leave;
6611                 }
6612         }
6613 #ifndef DISABLE_REMOTING
6614         if (mono_class_is_transparent_proxy (vt->klass)) 
6615         {
6616                 MonoBoolean custom_type_info =  MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6617                 if (!custom_type_info)
6618                         goto leave;
6619                 MonoDomain *domain = mono_domain_get ();
6620                 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6621                 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6622                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6623                 MonoMethod *im = NULL;
6624                 gpointer pa [2];
6625
6626                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6627                 if (!im) {
6628                         mono_error_set_not_supported (error, "Linked away.");
6629                         goto leave;
6630                 }
6631                 im = mono_object_handle_get_virtual_method (rp, im, error);
6632                 if (!is_ok (error))
6633                         goto leave;
6634                 g_assert (im);
6635         
6636                 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6637                 if (!is_ok (error))
6638                         goto leave;
6639
6640                 pa [0] = MONO_HANDLE_RAW (reftype);
6641                 pa [1] = MONO_HANDLE_RAW (obj);
6642                 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6643                 if (!is_ok (error))
6644                         goto leave;
6645
6646                 if (*(MonoBoolean *) mono_object_unbox(res)) {
6647                         /* Update the vtable of the remote type, so it can safely cast to this new type */
6648                         mono_upgrade_remote_class (domain, obj, klass, error);
6649                         if (!is_ok (error))
6650                                 goto leave;
6651                         MONO_HANDLE_ASSIGN (result, obj);
6652                 }
6653         }
6654 #endif /* DISABLE_REMOTING */
6655 leave:
6656         return result;
6657 }
6658
6659 /**
6660  * mono_object_castclass_mbyref:
6661  * \param obj an object
6662  * \param klass a pointer to a class 
6663  * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6664  */
6665 MonoObject *
6666 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6667 {
6668         MONO_REQ_GC_UNSAFE_MODE;
6669         HANDLE_FUNCTION_ENTER ();
6670         MonoError error;
6671         MONO_HANDLE_DCL (MonoObject, obj);
6672         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6673         if (MONO_HANDLE_IS_NULL (obj))
6674                 goto leave;
6675         MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6676         mono_error_cleanup (&error);
6677 leave:
6678         HANDLE_FUNCTION_RETURN_OBJ (result);
6679 }
6680
6681 typedef struct {
6682         MonoDomain *orig_domain;
6683         MonoString *ins;
6684         MonoString *res;
6685 } LDStrInfo;
6686
6687 static void
6688 str_lookup (MonoDomain *domain, gpointer user_data)
6689 {
6690         MONO_REQ_GC_UNSAFE_MODE;
6691
6692         LDStrInfo *info = (LDStrInfo *)user_data;
6693         if (info->res || domain == info->orig_domain)
6694                 return;
6695         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6696 }
6697
6698 static MonoString*
6699 mono_string_get_pinned (MonoString *str, MonoError *error)
6700 {
6701         MONO_REQ_GC_UNSAFE_MODE;
6702
6703         error_init (error);
6704
6705         /* We only need to make a pinned version of a string if this is a moving GC */
6706         if (!mono_gc_is_moving ())
6707                 return str;
6708         int size;
6709         MonoString *news;
6710         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6711         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6712         if (news) {
6713                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6714                 news->length = mono_string_length (str);
6715         } else {
6716                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6717         }
6718         return news;
6719 }
6720
6721 static MonoString*
6722 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6723 {
6724         MONO_REQ_GC_UNSAFE_MODE;
6725
6726         MonoGHashTable *ldstr_table;
6727         MonoString *s, *res;
6728         MonoDomain *domain;
6729         
6730         error_init (error);
6731
6732         domain = ((MonoObject *)str)->vtable->domain;
6733         ldstr_table = domain->ldstr_table;
6734         ldstr_lock ();
6735         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6736         if (res) {
6737                 ldstr_unlock ();
6738                 return res;
6739         }
6740         if (insert) {
6741                 /* Allocate outside the lock */
6742                 ldstr_unlock ();
6743                 s = mono_string_get_pinned (str, error);
6744                 return_val_if_nok (error, NULL);
6745                 if (s) {
6746                         ldstr_lock ();
6747                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6748                         if (res) {
6749                                 ldstr_unlock ();
6750                                 return res;
6751                         }
6752                         mono_g_hash_table_insert (ldstr_table, s, s);
6753                         ldstr_unlock ();
6754                 }
6755                 return s;
6756         } else {
6757                 LDStrInfo ldstr_info;
6758                 ldstr_info.orig_domain = domain;
6759                 ldstr_info.ins = str;
6760                 ldstr_info.res = NULL;
6761
6762                 mono_domain_foreach (str_lookup, &ldstr_info);
6763                 if (ldstr_info.res) {
6764                         /* 
6765                          * the string was already interned in some other domain:
6766                          * intern it in the current one as well.
6767                          */
6768                         mono_g_hash_table_insert (ldstr_table, str, str);
6769                         ldstr_unlock ();
6770                         return str;
6771                 }
6772         }
6773         ldstr_unlock ();
6774         return NULL;
6775 }
6776
6777 /**
6778  * mono_string_is_interned:
6779  * \param o String to probe
6780  * \returns Whether the string has been interned.
6781  */
6782 MonoString*
6783 mono_string_is_interned (MonoString *o)
6784 {
6785         MonoError error;
6786         MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6787         /* This function does not fail. */
6788         mono_error_assert_ok (&error);
6789         return result;
6790 }
6791
6792 /**
6793  * mono_string_intern:
6794  * \param o String to intern
6795  * Interns the string passed.  
6796  * \returns The interned string.
6797  */
6798 MonoString*
6799 mono_string_intern (MonoString *str)
6800 {
6801         MonoError error;
6802         MonoString *result = mono_string_intern_checked (str, &error);
6803         mono_error_assert_ok (&error);
6804         return result;
6805 }
6806
6807 /**
6808  * mono_string_intern_checked:
6809  * \param o String to intern
6810  * \param error set on error.
6811  * Interns the string passed.
6812  * \returns The interned string.  On failure returns NULL and sets \p error
6813  */
6814 MonoString*
6815 mono_string_intern_checked (MonoString *str, MonoError *error)
6816 {
6817         MONO_REQ_GC_UNSAFE_MODE;
6818
6819         error_init (error);
6820
6821         return mono_string_is_interned_lookup (str, TRUE, error);
6822 }
6823
6824 /**
6825  * mono_ldstr:
6826  * \param domain the domain where the string will be used.
6827  * \param image a metadata context
6828  * \param idx index into the user string table.
6829  * Implementation for the \c ldstr opcode.
6830  * \returns a loaded string from the \p image / \p idx combination.
6831  */
6832 MonoString*
6833 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6834 {
6835         MonoError error;
6836         MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6837         mono_error_cleanup (&error);
6838         return result;
6839 }
6840
6841 /**
6842  * mono_ldstr_checked:
6843  * \param domain the domain where the string will be used.
6844  * \param image a metadata context
6845  * \param idx index into the user string table.
6846  * \param error set on error.
6847  * Implementation for the \c ldstr opcode.
6848  * \returns A loaded string from the \p image / \p idx combination.
6849  * On failure returns NULL and sets \p error.
6850  */
6851 MonoString*
6852 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6853 {
6854         MONO_REQ_GC_UNSAFE_MODE;
6855         error_init (error);
6856
6857         if (image->dynamic) {
6858                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6859                 return str;
6860         } else {
6861                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6862                         return NULL; /*FIXME we should probably be raising an exception here*/
6863                 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6864                 return str;
6865         }
6866 }
6867
6868 /**
6869  * mono_ldstr_metadata_sig
6870  * \param domain the domain for the string
6871  * \param sig the signature of a metadata string
6872  * \param error set on error
6873  * \returns a \c MonoString for a string stored in the metadata. On
6874  * failure returns NULL and sets \p error.
6875  */
6876 static MonoString*
6877 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6878 {
6879         MONO_REQ_GC_UNSAFE_MODE;
6880
6881         error_init (error);
6882         const char *str = sig;
6883         MonoString *o, *interned;
6884         size_t len2;
6885
6886         len2 = mono_metadata_decode_blob_size (str, &str);
6887         len2 >>= 1;
6888
6889         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6890         return_val_if_nok (error, NULL);
6891 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6892         {
6893                 int i;
6894                 guint16 *p2 = (guint16*)mono_string_chars (o);
6895                 for (i = 0; i < len2; ++i) {
6896                         *p2 = GUINT16_FROM_LE (*p2);
6897                         ++p2;
6898                 }
6899         }
6900 #endif
6901         ldstr_lock ();
6902         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6903         ldstr_unlock ();
6904         if (interned)
6905                 return interned; /* o will get garbage collected */
6906
6907         o = mono_string_get_pinned (o, error);
6908         if (o) {
6909                 ldstr_lock ();
6910                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6911                 if (!interned) {
6912                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6913                         interned = o;
6914                 }
6915                 ldstr_unlock ();
6916         }
6917
6918         return interned;
6919 }
6920
6921 /*
6922  * mono_ldstr_utf8:
6923  *
6924  *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
6925  * of an object.
6926  */
6927 char*
6928 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6929 {
6930         const char *str;
6931         size_t len2;
6932         long written = 0;
6933         char *as;
6934         GError *gerror = NULL;
6935
6936         error_init (error);
6937
6938         if (!mono_verifier_verify_string_signature (image, idx, NULL))
6939                 return NULL; /*FIXME we should probably be raising an exception here*/
6940         str = mono_metadata_user_string (image, idx);
6941
6942         len2 = mono_metadata_decode_blob_size (str, &str);
6943         len2 >>= 1;
6944
6945         as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6946         if (gerror) {
6947                 mono_error_set_argument (error, "string", "%s", gerror->message);
6948                 g_error_free (gerror);
6949                 return NULL;
6950         }
6951         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6952         if (len2 > written) {
6953                 /* allocate the total length and copy the part of the string that has been converted */
6954                 char *as2 = (char *)g_malloc0 (len2);
6955                 memcpy (as2, as, written);
6956                 g_free (as);
6957                 as = as2;
6958         }
6959
6960         return as;
6961 }
6962
6963 /**
6964  * mono_string_to_utf8:
6965  * \param s a \c System.String
6966  * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6967  * \returns the UTF-8 representation for \p s.
6968  * The resulting buffer needs to be freed with \c mono_free().
6969  */
6970 char *
6971 mono_string_to_utf8 (MonoString *s)
6972 {
6973         MONO_REQ_GC_UNSAFE_MODE;
6974
6975         MonoError error;
6976         char *result = mono_string_to_utf8_checked (s, &error);
6977         
6978         if (!is_ok (&error)) {
6979                 mono_error_cleanup (&error);
6980                 return NULL;
6981         }
6982         return result;
6983 }
6984
6985 /**
6986  * mono_string_to_utf8_checked:
6987  * \param s a \c System.String
6988  * \param error a \c MonoError.
6989  * Converts a \c MonoString to its UTF-8 representation. May fail; check 
6990  * \p error to determine whether the conversion was successful.
6991  * The resulting buffer should be freed with \c mono_free().
6992  */
6993 char *
6994 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6995 {
6996         MONO_REQ_GC_UNSAFE_MODE;
6997
6998         long written = 0;
6999         char *as;
7000         GError *gerror = NULL;
7001
7002         error_init (error);
7003
7004         if (s == NULL)
7005                 return NULL;
7006
7007         if (!s->length)
7008                 return g_strdup ("");
7009
7010         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7011         if (gerror) {
7012                 mono_error_set_argument (error, "string", "%s", gerror->message);
7013                 g_error_free (gerror);
7014                 return NULL;
7015         }
7016         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7017         if (s->length > written) {
7018                 /* allocate the total length and copy the part of the string that has been converted */
7019                 char *as2 = (char *)g_malloc0 (s->length);
7020                 memcpy (as2, as, written);
7021                 g_free (as);
7022                 as = as2;
7023         }
7024
7025         return as;
7026 }
7027
7028 char *
7029 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7030 {
7031         return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7032 }
7033
7034 /**
7035  * mono_string_to_utf8_ignore:
7036  * \param s a MonoString
7037  * Converts a \c MonoString to its UTF-8 representation. Will ignore
7038  * invalid surrogate pairs.
7039  * The resulting buffer should be freed with \c mono_free().
7040  */
7041 char *
7042 mono_string_to_utf8_ignore (MonoString *s)
7043 {
7044         MONO_REQ_GC_UNSAFE_MODE;
7045
7046         long written = 0;
7047         char *as;
7048
7049         if (s == NULL)
7050                 return NULL;
7051
7052         if (!s->length)
7053                 return g_strdup ("");
7054
7055         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7056
7057         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7058         if (s->length > written) {
7059                 /* allocate the total length and copy the part of the string that has been converted */
7060                 char *as2 = (char *)g_malloc0 (s->length);
7061                 memcpy (as2, as, written);
7062                 g_free (as);
7063                 as = as2;
7064         }
7065
7066         return as;
7067 }
7068
7069 /**
7070  * mono_string_to_utf8_image_ignore:
7071  * \param s a \c System.String
7072  * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7073  */
7074 char *
7075 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7076 {
7077         MONO_REQ_GC_UNSAFE_MODE;
7078
7079         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7080 }
7081
7082 /**
7083  * mono_string_to_utf8_mp_ignore:
7084  * \param s a \c System.String
7085  * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7086  */
7087 char *
7088 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7089 {
7090         MONO_REQ_GC_UNSAFE_MODE;
7091
7092         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7093 }
7094
7095
7096 /**
7097  * mono_string_to_utf16:
7098  * \param s a \c MonoString
7099  * \returns a null-terminated array of the UTF-16 chars
7100  * contained in \p s. The result must be freed with \c g_free().
7101  * This is a temporary helper until our string implementation
7102  * is reworked to always include the null-terminating char.
7103  */
7104 mono_unichar2*
7105 mono_string_to_utf16 (MonoString *s)
7106 {
7107         MONO_REQ_GC_UNSAFE_MODE;
7108
7109         char *as;
7110
7111         if (s == NULL)
7112                 return NULL;
7113
7114         as = (char *)g_malloc ((s->length * 2) + 2);
7115         as [(s->length * 2)] = '\0';
7116         as [(s->length * 2) + 1] = '\0';
7117
7118         if (!s->length) {
7119                 return (gunichar2 *)(as);
7120         }
7121         
7122         memcpy (as, mono_string_chars(s), s->length * 2);
7123         return (gunichar2 *)(as);
7124 }
7125
7126 /**
7127  * mono_string_to_utf32:
7128  * \param s a \c MonoString
7129  * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7130  * contained in \p s. The result must be freed with \c g_free().
7131  */
7132 mono_unichar4*
7133 mono_string_to_utf32 (MonoString *s)
7134 {
7135         MONO_REQ_GC_UNSAFE_MODE;
7136
7137         mono_unichar4 *utf32_output = NULL; 
7138         GError *error = NULL;
7139         glong items_written;
7140         
7141         if (s == NULL)
7142                 return NULL;
7143                 
7144         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7145         
7146         if (error)
7147                 g_error_free (error);
7148
7149         return utf32_output;
7150 }
7151
7152 /**
7153  * mono_string_from_utf16:
7154  * \param data the UTF-16 string (LPWSTR) to convert
7155  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7156  * \returns a \c MonoString.
7157  */
7158 MonoString *
7159 mono_string_from_utf16 (gunichar2 *data)
7160 {
7161         MonoError error;
7162         MonoString *result = mono_string_from_utf16_checked (data, &error);
7163         mono_error_cleanup (&error);
7164         return result;
7165 }
7166
7167 /**
7168  * mono_string_from_utf16_checked:
7169  * \param data the UTF-16 string (LPWSTR) to convert
7170  * \param error set on error
7171  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7172  * \returns a \c MonoString. On failure sets \p error and returns NULL.
7173  */
7174 MonoString *
7175 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7176 {
7177
7178         MONO_REQ_GC_UNSAFE_MODE;
7179
7180         error_init (error);
7181         MonoDomain *domain = mono_domain_get ();
7182         int len = 0;
7183
7184         if (!data)
7185                 return NULL;
7186
7187         while (data [len]) len++;
7188
7189         return mono_string_new_utf16_checked (domain, data, len, error);
7190 }
7191
7192 /**
7193  * mono_string_from_utf32:
7194  * \param data the UTF-32 string (LPWSTR) to convert
7195  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7196  * \returns a \c MonoString.
7197  */
7198 MonoString *
7199 mono_string_from_utf32 (mono_unichar4 *data)
7200 {
7201         MonoError error;
7202         MonoString *result = mono_string_from_utf32_checked (data, &error);
7203         mono_error_cleanup (&error);
7204         return result;
7205 }
7206
7207 /**
7208  * mono_string_from_utf32_checked:
7209  * \param data the UTF-32 string (LPWSTR) to convert
7210  * \param error set on error
7211  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7212  * \returns a \c MonoString. On failure returns NULL and sets \p error.
7213  */
7214 MonoString *
7215 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7216 {
7217         MONO_REQ_GC_UNSAFE_MODE;
7218
7219         error_init (error);
7220         MonoString* result = NULL;
7221         mono_unichar2 *utf16_output = NULL;
7222         GError *gerror = NULL;
7223         glong items_written;
7224         int len = 0;
7225
7226         if (!data)
7227                 return NULL;
7228
7229         while (data [len]) len++;
7230
7231         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7232
7233         if (gerror)
7234                 g_error_free (gerror);
7235
7236         result = mono_string_from_utf16_checked (utf16_output, error);
7237         g_free (utf16_output);
7238         return result;
7239 }
7240
7241 static char *
7242 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7243 {
7244         MONO_REQ_GC_UNSAFE_MODE;
7245
7246         char *r;
7247         char *mp_s;
7248         int len;
7249
7250         if (ignore_error) {
7251                 r = mono_string_to_utf8_ignore (s);
7252         } else {
7253                 r = mono_string_to_utf8_checked (s, error);
7254                 if (!mono_error_ok (error))
7255                         return NULL;
7256         }
7257
7258         if (!mp && !image)
7259                 return r;
7260
7261         len = strlen (r) + 1;
7262         if (mp)
7263                 mp_s = (char *)mono_mempool_alloc (mp, len);
7264         else
7265                 mp_s = (char *)mono_image_alloc (image, len);
7266
7267         memcpy (mp_s, r, len);
7268
7269         g_free (r);
7270
7271         return mp_s;
7272 }
7273
7274 /**
7275  * mono_string_to_utf8_image:
7276  * \param s a \c System.String
7277  * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7278  */
7279 char *
7280 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7281 {
7282         MONO_REQ_GC_UNSAFE_MODE;
7283
7284         return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7285 }
7286
7287 /**
7288  * mono_string_to_utf8_mp:
7289  * \param s a \c System.String
7290  * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7291  */
7292 char *
7293 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7294 {
7295         MONO_REQ_GC_UNSAFE_MODE;
7296
7297         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7298 }
7299
7300
7301 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7302
7303 void
7304 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7305 {
7306         eh_callbacks = *cbs;
7307 }
7308
7309 MonoRuntimeExceptionHandlingCallbacks *
7310 mono_get_eh_callbacks (void)
7311 {
7312         return &eh_callbacks;
7313 }
7314
7315 /**
7316  * mono_raise_exception:
7317  * \param ex exception object
7318  * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7319  */
7320 void
7321 mono_raise_exception (MonoException *ex) 
7322 {
7323         MONO_REQ_GC_UNSAFE_MODE;
7324
7325         /*
7326          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7327          * that will cause gcc to omit the function epilog, causing problems when
7328          * the JIT tries to walk the stack, since the return address on the stack
7329          * will point into the next function in the executable, not this one.
7330          */     
7331         eh_callbacks.mono_raise_exception (ex);
7332 }
7333
7334 /**
7335  * mono_raise_exception:
7336  * \param ex exception object
7337  * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7338  */
7339 void
7340 mono_reraise_exception (MonoException *ex)
7341 {
7342         MONO_REQ_GC_UNSAFE_MODE;
7343
7344         /*
7345          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7346          * that will cause gcc to omit the function epilog, causing problems when
7347          * the JIT tries to walk the stack, since the return address on the stack
7348          * will point into the next function in the executable, not this one.
7349          */
7350         eh_callbacks.mono_reraise_exception (ex);
7351 }
7352
7353 void
7354 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
7355 {
7356         MONO_REQ_GC_UNSAFE_MODE;
7357
7358         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7359 }
7360
7361 /**
7362  * mono_wait_handle_new:
7363  * \param domain Domain where the object will be created
7364  * \param handle Handle for the wait handle
7365  * \param error set on error.
7366  * \returns A new \c MonoWaitHandle created in the given domain for the
7367  * given handle.  On failure returns NULL and sets \p error.
7368  */
7369 MonoWaitHandle *
7370 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7371 {
7372         MONO_REQ_GC_UNSAFE_MODE;
7373
7374         MonoWaitHandle *res;
7375         gpointer params [1];
7376         static MonoMethod *handle_set;
7377
7378         error_init (error);
7379         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7380         return_val_if_nok (error, NULL);
7381
7382         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
7383         if (!handle_set)
7384                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7385
7386         params [0] = &handle;
7387
7388         mono_runtime_invoke_checked (handle_set, res, params, error);
7389         return res;
7390 }
7391
7392 HANDLE
7393 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7394 {
7395         MONO_REQ_GC_UNSAFE_MODE;
7396
7397         static MonoClassField *f_safe_handle = NULL;
7398         MonoSafeHandle *sh;
7399
7400         if (!f_safe_handle) {
7401                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7402                 g_assert (f_safe_handle);
7403         }
7404
7405         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7406         return sh->handle;
7407 }
7408
7409
7410 static MonoObject*
7411 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7412 {
7413 #ifdef HOST_WASM
7414         return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
7415 #else
7416         MONO_REQ_GC_UNSAFE_MODE;
7417
7418         RuntimeInvokeFunction runtime_invoke;
7419
7420         error_init (error);
7421
7422         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7423                 MonoMethod *method = mono_get_context_capture_method ();
7424                 MonoMethod *wrapper;
7425                 if (!method)
7426                         return NULL;
7427                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7428                 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7429                 return_val_if_nok (error, NULL);
7430                 domain->capture_context_method = mono_compile_method_checked (method, error);
7431                 return_val_if_nok (error, NULL);
7432         }
7433
7434         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7435
7436         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7437 #endif
7438 }
7439 /**
7440  * mono_async_result_new:
7441  * \param domain domain where the object will be created.
7442  * \param handle wait handle.
7443  * \param state state to pass to AsyncResult
7444  * \param data C closure data.
7445  * \param error set on error.
7446  * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7447  * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7448  * On failure returns NULL and sets \p error.
7449  */
7450 MonoAsyncResult *
7451 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7452 {
7453         MONO_REQ_GC_UNSAFE_MODE;
7454
7455         error_init (error);
7456         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7457         return_val_if_nok (error, NULL);
7458         MonoObject *context = mono_runtime_capture_context (domain, error);
7459         return_val_if_nok (error, NULL);
7460         /* we must capture the execution context from the original thread */
7461         if (context) {
7462                 MONO_OBJECT_SETREF (res, execution_context, context);
7463                 /* note: result may be null if the flow is suppressed */
7464         }
7465
7466         res->data = (void **)data;
7467         MONO_OBJECT_SETREF (res, object_data, object_data);
7468         MONO_OBJECT_SETREF (res, async_state, state);
7469         MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7470         return_val_if_nok (error, NULL);
7471         if (handle != NULL)
7472                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7473
7474         res->sync_completed = FALSE;
7475         res->completed = FALSE;
7476
7477         return res;
7478 }
7479
7480 MonoObject *
7481 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7482 {
7483         MONO_REQ_GC_UNSAFE_MODE;
7484
7485         MonoError error;
7486         MonoAsyncCall *ac;
7487         MonoObject *res;
7488
7489         g_assert (ares);
7490         g_assert (ares->async_delegate);
7491
7492         ac = (MonoAsyncCall*) ares->object_data;
7493         if (!ac) {
7494                 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7495                 if (mono_error_set_pending_exception (&error))
7496                         return NULL;
7497         } else {
7498                 gpointer wait_event = NULL;
7499
7500                 ac->msg->exc = NULL;
7501
7502                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7503
7504                 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7505                 mono_threads_begin_abort_protected_block ();
7506
7507                 if (!ac->msg->exc) {
7508                         MonoException *ex = mono_error_convert_to_exception (&error);
7509                         ac->msg->exc = (MonoObject *)ex;
7510                 } else {
7511                         mono_error_cleanup (&error);
7512                 }
7513
7514                 MONO_OBJECT_SETREF (ac, res, res);
7515
7516                 mono_monitor_enter ((MonoObject*) ares);
7517                 ares->completed = 1;
7518                 if (ares->handle)
7519                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7520                 mono_monitor_exit ((MonoObject*) ares);
7521
7522                 if (wait_event != NULL)
7523                         mono_w32event_set (wait_event);
7524
7525                 error_init (&error); //the else branch would leave it in an undefined state
7526                 if (ac->cb_method)
7527                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7528
7529                 mono_threads_end_abort_protected_block ();
7530
7531                 if (mono_error_set_pending_exception (&error))
7532                         return NULL;
7533         }
7534
7535         return res;
7536 }
7537
7538 gboolean
7539 mono_message_init (MonoDomain *domain,
7540                    MonoMethodMessage *this_obj, 
7541                    MonoReflectionMethod *method,
7542                    MonoArray *out_args,
7543                    MonoError *error)
7544 {
7545         MONO_REQ_GC_UNSAFE_MODE;
7546
7547         static MonoMethod *init_message_method = NULL;
7548
7549         if (!init_message_method) {
7550                 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7551                 g_assert (init_message_method != NULL);
7552         }
7553
7554         error_init (error);
7555         /* FIXME set domain instead? */
7556         g_assert (domain == mono_domain_get ());
7557         
7558         gpointer args[2];
7559
7560         args[0] = method;
7561         args[1] = out_args;
7562
7563         mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7564         return is_ok (error);
7565 }
7566
7567 #ifndef DISABLE_REMOTING
7568 /**
7569  * mono_remoting_invoke:
7570  * \param real_proxy pointer to a \c RealProxy object
7571  * \param msg The \c MonoMethodMessage to execute
7572  * \param exc used to store exceptions
7573  * \param out_args used to store output arguments
7574  * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7575  * \c IMessage interface and it is not trivial to extract results from there. So
7576  * we call an helper method \c PrivateInvoke instead of calling
7577  * \c RealProxy::Invoke() directly.
7578  * \returns the result object.
7579  */
7580 MonoObject *
7581 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7582 {
7583         MONO_REQ_GC_UNSAFE_MODE;
7584
7585         MonoObject *o;
7586         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7587         gpointer pa [4];
7588
7589         g_assert (exc);
7590
7591         error_init (error);
7592
7593         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7594
7595         if (!im) {
7596                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7597                 if (!im) {
7598                         mono_error_set_not_supported (error, "Linked away.");
7599                         return NULL;
7600                 }
7601                 real_proxy->vtable->domain->private_invoke_method = im;
7602         }
7603
7604         pa [0] = real_proxy;
7605         pa [1] = msg;
7606         pa [2] = exc;
7607         pa [3] = out_args;
7608
7609         o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7610         return_val_if_nok (error, NULL);
7611
7612         return o;
7613 }
7614 #endif
7615
7616 MonoObject *
7617 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
7618                      MonoObject **exc, MonoArray **out_args, MonoError *error) 
7619 {
7620         MONO_REQ_GC_UNSAFE_MODE;
7621
7622         static MonoClass *object_array_klass;
7623         error_init (error);
7624
7625         MonoDomain *domain; 
7626         MonoMethod *method;
7627         MonoMethodSignature *sig;
7628         MonoArray *arr;
7629         int i, j, outarg_count = 0;
7630
7631 #ifndef DISABLE_REMOTING
7632         if (target && mono_object_is_transparent_proxy (target)) {
7633                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7634                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7635                         target = tp->rp->unwrapped_server;
7636                 } else {
7637                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7638                 }
7639         }
7640 #endif
7641
7642         domain = mono_domain_get (); 
7643         method = msg->method->method;
7644         sig = mono_method_signature (method);
7645
7646         for (i = 0; i < sig->param_count; i++) {
7647                 if (sig->params [i]->byref) 
7648                         outarg_count++;
7649         }
7650
7651         if (!object_array_klass) {
7652                 MonoClass *klass;
7653
7654                 klass = mono_array_class_get (mono_defaults.object_class, 1);
7655                 g_assert (klass);
7656
7657                 mono_memory_barrier ();
7658                 object_array_klass = klass;
7659         }
7660
7661         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7662         return_val_if_nok (error, NULL);
7663
7664         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7665         *exc = NULL;
7666
7667         MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7668         return_val_if_nok (error, NULL);
7669
7670         for (i = 0, j = 0; i < sig->param_count; i++) {
7671                 if (sig->params [i]->byref) {
7672                         MonoObject* arg;
7673                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7674                         mono_array_setref (*out_args, j, arg);
7675                         j++;
7676                 }
7677         }
7678
7679         return ret;
7680 }
7681
7682 /**
7683  * prepare_to_string_method:
7684  * @obj: The object
7685  * @target: Set to @obj or unboxed value if a valuetype
7686  *
7687  * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7688  */
7689 static MonoMethod *
7690 prepare_to_string_method (MonoObject *obj, void **target)
7691 {
7692         MONO_REQ_GC_UNSAFE_MODE;
7693
7694         static MonoMethod *to_string = NULL;
7695         MonoMethod *method;
7696         g_assert (target);
7697         g_assert (obj);
7698
7699         *target = obj;
7700
7701         if (!to_string)
7702                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7703
7704         method = mono_object_get_virtual_method (obj, to_string);
7705
7706         // Unbox value type if needed
7707         if (mono_class_is_valuetype (mono_method_get_class (method))) {
7708                 *target = mono_object_unbox (obj);
7709         }
7710         return method;
7711 }
7712
7713 /**
7714  * mono_object_to_string:
7715  * \param obj The object
7716  * \param exc Any exception thrown by \c ToString. May be NULL.
7717  * \returns the result of calling \c ToString on an object.
7718  */
7719 MonoString *
7720 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7721 {
7722         MonoError error;
7723         MonoString *s = NULL;
7724         void *target;
7725         MonoMethod *method = prepare_to_string_method (obj, &target);
7726         if (exc) {
7727                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7728                 if (*exc == NULL && !mono_error_ok (&error))
7729                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7730                 else
7731                         mono_error_cleanup (&error);
7732         } else {
7733                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7734                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7735         }
7736
7737         return s;
7738 }
7739
7740 /**
7741  * mono_object_to_string_checked:
7742  * \param obj The object
7743  * \param error Set on error.
7744  * \returns the result of calling \c ToString() on an object. If the
7745  * method cannot be invoked or if it raises an exception, sets \p error
7746  * and returns NULL.
7747  */
7748 MonoString *
7749 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7750 {
7751         error_init (error);
7752         void *target;
7753         MonoMethod *method = prepare_to_string_method (obj, &target);
7754         return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7755 }
7756
7757 /**
7758  * mono_object_try_to_string:
7759  * \param obj The object
7760  * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7761  * \param error Set if method cannot be invoked.
7762  * \returns the result of calling \c ToString() on an object. If the
7763  * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7764  * and returns NULL.
7765  */
7766 MonoString *
7767 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7768 {
7769         g_assert (exc);
7770         error_init (error);
7771         void *target;
7772         MonoMethod *method = prepare_to_string_method (obj, &target);
7773         return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7774 }
7775
7776
7777
7778 static char *
7779 get_native_backtrace (MonoException *exc_raw)
7780 {
7781         HANDLE_FUNCTION_ENTER ();
7782         MONO_HANDLE_DCL(MonoException, exc);
7783         char * trace = mono_exception_handle_get_native_backtrace (exc);
7784         HANDLE_FUNCTION_RETURN_VAL (trace);
7785 }
7786
7787 /**
7788  * mono_print_unhandled_exception:
7789  * \param exc The exception
7790  * Prints the unhandled exception.
7791  */
7792 void
7793 mono_print_unhandled_exception (MonoObject *exc)
7794 {
7795         MONO_REQ_GC_UNSAFE_MODE;
7796
7797         MonoString * str;
7798         char *message = (char*)"";
7799         gboolean free_message = FALSE;
7800         MonoError error;
7801
7802         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7803                 message = g_strdup ("OutOfMemoryException");
7804                 free_message = TRUE;
7805         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7806                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7807                 free_message = TRUE;
7808         } else {
7809                 
7810                 if (((MonoException*)exc)->native_trace_ips) {
7811                         message = get_native_backtrace ((MonoException*)exc);
7812                         free_message = TRUE;
7813                 } else {
7814                         MonoObject *other_exc = NULL;
7815                         str = mono_object_try_to_string (exc, &other_exc, &error);
7816                         if (other_exc == NULL && !is_ok (&error))
7817                                 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7818                         else
7819                                 mono_error_cleanup (&error);
7820                         if (other_exc) {
7821                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7822                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7823                                 
7824                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7825                                         original_backtrace, nested_backtrace);
7826
7827                                 g_free (original_backtrace);
7828                                 g_free (nested_backtrace);
7829                                 free_message = TRUE;
7830                         } else if (str) {
7831                                 message = mono_string_to_utf8_checked (str, &error);
7832                                 if (!mono_error_ok (&error)) {
7833                                         mono_error_cleanup (&error);
7834                                         message = (char *) "";
7835                                 } else {
7836                                         free_message = TRUE;
7837                                 }
7838                         }
7839                 }
7840         }
7841
7842         /*
7843          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7844          *         exc->vtable->klass->name, message);
7845          */
7846         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7847         
7848         if (free_message)
7849                 g_free (message);
7850 }
7851
7852 /**
7853  * mono_delegate_ctor_with_method:
7854  * \param this pointer to an uninitialized delegate object
7855  * \param target target object
7856  * \param addr pointer to native code
7857  * \param method method
7858  * \param error set on error.
7859  * Initialize a delegate and sets a specific method, not the one
7860  * associated with \p addr.  This is useful when sharing generic code.
7861  * In that case \p addr will most probably not be associated with the
7862  * correct instantiation of the method.
7863  * On failure returns FALSE and sets \p error.
7864  */
7865 gboolean
7866 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7867 {
7868         MONO_REQ_GC_UNSAFE_MODE;
7869
7870         error_init (error);
7871         MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7872
7873         g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7874         g_assert (addr);
7875
7876         MonoClass *klass = mono_handle_class (this_obj);
7877         g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7878
7879         if (method)
7880                 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7881
7882         UnlockedIncrement (&mono_stats.delegate_creations);
7883
7884 #ifndef DISABLE_REMOTING
7885         if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7886                 g_assert (method);
7887                 method = mono_marshal_get_remoting_invoke (method);
7888 #ifdef ENABLE_INTERPRETER
7889                 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7890 #endif
7891                 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7892                 return_val_if_nok (error, FALSE);
7893                 MONO_HANDLE_SET (delegate, target, target);
7894         } else
7895 #endif
7896         {
7897                 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7898                 MONO_HANDLE_SET (delegate, target, target);
7899         }
7900
7901         MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7902         if (callbacks.init_delegate)
7903                 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7904         return TRUE;
7905 }
7906
7907 /**
7908  * mono_delegate_ctor:
7909  * \param this pointer to an uninitialized delegate object
7910  * \param target target object
7911  * \param addr pointer to native code
7912  * \param error set on error.
7913  * This is used to initialize a delegate.
7914  * On failure returns FALSE and sets \p error.
7915  */
7916 gboolean
7917 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7918 {
7919         MONO_REQ_GC_UNSAFE_MODE;
7920
7921         error_init (error);
7922         MonoDomain *domain = mono_domain_get ();
7923         MonoJitInfo *ji;
7924         MonoMethod *method = NULL;
7925
7926         g_assert (addr);
7927
7928         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7929         /* Shared code */
7930         if (!ji && domain != mono_get_root_domain ())
7931                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7932         if (ji) {
7933                 method = mono_jit_info_get_method (ji);
7934                 g_assert (!mono_class_is_gtd (method->klass));
7935         }
7936
7937         return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7938 }
7939
7940 /**
7941  * mono_method_call_message_new:
7942  * \param method method to encapsulate
7943  * \param params parameters to the method
7944  * \param invoke optional, delegate invoke.
7945  * \param cb async callback delegate.
7946  * \param state state passed to the async callback.
7947  * \param error set on error.
7948   * Translates arguments pointers into a \c MonoMethodMessage.
7949  * On failure returns NULL and sets \p error.
7950  */
7951 MonoMethodMessage *
7952 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7953                               MonoDelegate **cb, MonoObject **state, MonoError *error)
7954 {
7955         MONO_REQ_GC_UNSAFE_MODE;
7956
7957         error_init (error);
7958
7959         MonoDomain *domain = mono_domain_get ();
7960         MonoMethodSignature *sig = mono_method_signature (method);
7961         MonoMethodMessage *msg;
7962         int i, count;
7963
7964         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error); 
7965         return_val_if_nok  (error, NULL);
7966
7967         if (invoke) {
7968                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7969                 return_val_if_nok (error, NULL);
7970                 mono_message_init (domain, msg, rm, NULL, error);
7971                 return_val_if_nok (error, NULL);
7972                 count =  sig->param_count - 2;
7973         } else {
7974                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7975                 return_val_if_nok (error, NULL);
7976                 mono_message_init (domain, msg, rm, NULL, error);
7977                 return_val_if_nok (error, NULL);
7978                 count =  sig->param_count;
7979         }
7980
7981         for (i = 0; i < count; i++) {
7982                 gpointer vpos;
7983                 MonoClass *klass;
7984                 MonoObject *arg;
7985
7986                 if (sig->params [i]->byref)
7987                         vpos = *((gpointer *)params [i]);
7988                 else 
7989                         vpos = params [i];
7990
7991                 klass = mono_class_from_mono_type (sig->params [i]);
7992
7993                 if (klass->valuetype) {
7994                         arg = mono_value_box_checked (domain, klass, vpos, error);
7995                         return_val_if_nok (error, NULL);
7996                 } else 
7997                         arg = *((MonoObject **)vpos);
7998                       
7999                 mono_array_setref (msg->args, i, arg);
8000         }
8001
8002         if (cb != NULL && state != NULL) {
8003                 *cb = *((MonoDelegate **)params [i]);
8004                 i++;
8005                 *state = *((MonoObject **)params [i]);
8006         }
8007
8008         return msg;
8009 }
8010
8011 /**
8012  * mono_method_return_message_restore:
8013  *
8014  * Restore results from message based processing back to arguments pointers
8015  */
8016 void
8017 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8018 {
8019         MONO_REQ_GC_UNSAFE_MODE;
8020
8021         error_init (error);
8022
8023         MonoMethodSignature *sig = mono_method_signature (method);
8024         int i, j, type, size, out_len;
8025         
8026         if (out_args == NULL)
8027                 return;
8028         out_len = mono_array_length (out_args);
8029         if (out_len == 0)
8030                 return;
8031
8032         for (i = 0, j = 0; i < sig->param_count; i++) {
8033                 MonoType *pt = sig->params [i];
8034
8035                 if (pt->byref) {
8036                         char *arg;
8037                         if (j >= out_len) {
8038                                 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8039                                 return;
8040                         }
8041
8042                         arg = (char *)mono_array_get (out_args, gpointer, j);
8043                         type = pt->type;
8044
8045                         g_assert (type != MONO_TYPE_VOID);
8046
8047                         if (MONO_TYPE_IS_REFERENCE (pt)) {
8048                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8049                         } else {
8050                                 if (arg) {
8051                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8052                                         size = mono_class_value_size (klass, NULL);
8053                                         if (klass->has_references)
8054                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8055                                         else
8056                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8057                                 } else {
8058                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8059                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8060                                 }
8061                         }
8062
8063                         j++;
8064                 }
8065         }
8066 }
8067
8068 #ifndef DISABLE_REMOTING
8069
8070 /**
8071  * mono_load_remote_field:
8072  * \param this pointer to an object
8073  * \param klass klass of the object containing \p field
8074  * \param field the field to load
8075  * \param res a storage to store the result
8076  * This method is called by the runtime on attempts to load fields of
8077  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8078  * the object containing \p field. \p res is a storage location which can be
8079  * used to store the result.
8080  * \returns an address pointing to the value of field.
8081  */
8082 gpointer
8083 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8084 {
8085         MonoError error;
8086         gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8087         mono_error_cleanup (&error);
8088         return result;
8089 }
8090
8091 /**
8092  * mono_load_remote_field_checked:
8093  * \param this pointer to an object
8094  * \param klass klass of the object containing \p field
8095  * \param field the field to load
8096  * \param res a storage to store the result
8097  * \param error set on error
8098  * This method is called by the runtime on attempts to load fields of
8099  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8100  * the object containing \p field. \p res is a storage location which can be
8101  * used to store the result.
8102  * \returns an address pointing to the value of field.  On failure returns NULL and sets \p error.
8103  */
8104 gpointer
8105 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8106 {
8107         MONO_REQ_GC_UNSAFE_MODE;
8108
8109         static MonoMethod *getter = NULL;
8110
8111         error_init (error);
8112
8113         MonoDomain *domain = mono_domain_get ();
8114         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8115         MonoClass *field_class;
8116         MonoMethodMessage *msg;
8117         MonoArray *out_args;
8118         MonoObject *exc;
8119         char* full_name;
8120
8121         g_assert (mono_object_is_transparent_proxy (this_obj));
8122         g_assert (res != NULL);
8123
8124         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8125                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8126                 return res;
8127         }
8128         
8129         if (!getter) {
8130                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8131                 if (!getter) {
8132                         mono_error_set_not_supported (error, "Linked away.");
8133                         return NULL;
8134                 }
8135         }
8136         
8137         field_class = mono_class_from_mono_type (field->type);
8138
8139         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8140         return_val_if_nok (error, NULL);
8141         out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8142         return_val_if_nok (error, NULL);
8143         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8144         return_val_if_nok (error, NULL);
8145         mono_message_init (domain, msg, rm, out_args, error);
8146         return_val_if_nok (error, NULL);
8147
8148         full_name = mono_type_get_full_name (klass);
8149         MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8150         g_free (full_name);
8151         return_val_if_nok (error, NULL);
8152         mono_array_setref (msg->args, 0, full_name_str);
8153         MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8154         return_val_if_nok (error, NULL);
8155         mono_array_setref (msg->args, 1, field_name);
8156
8157         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8158         return_val_if_nok (error, NULL);
8159
8160         if (exc) {
8161                 mono_error_set_exception_instance (error, (MonoException *)exc);
8162                 return NULL;
8163         }
8164
8165         if (mono_array_length (out_args) == 0)
8166                 return NULL;
8167
8168         mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8169
8170         if (field_class->valuetype) {
8171                 return ((char *)*res) + sizeof (MonoObject);
8172         } else
8173                 return res;
8174 }
8175
8176 /**
8177  * mono_load_remote_field_new:
8178  * \param this
8179  * \param klass
8180  * \param field
8181  * Missing documentation.
8182  */
8183 MonoObject *
8184 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8185 {
8186         MonoError error;
8187
8188         MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8189         mono_error_cleanup (&error);
8190         return result;
8191 }
8192
8193 /**
8194  * mono_load_remote_field_new_checked:
8195  * \param this pointer to an object
8196  * \param klass klass of the object containing \p field
8197  * \param field the field to load
8198  * \param error set on error.
8199  * This method is called by the runtime on attempts to load fields of
8200  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8201  * the object containing \p field.
8202  * \returns a freshly allocated object containing the value of the field.  On failure returns NULL and sets \p error.
8203  */
8204 MonoObject *
8205 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8206 {
8207         MONO_REQ_GC_UNSAFE_MODE;
8208
8209         error_init (error);
8210
8211         static MonoMethod *tp_load = NULL;
8212
8213         g_assert (mono_object_is_transparent_proxy (this_obj));
8214
8215         if (!tp_load) {
8216                 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8217                 if (!tp_load) {
8218                         mono_error_set_not_supported (error, "Linked away.");
8219                         return NULL;
8220                 }
8221         }
8222         
8223         /* MonoType *type = mono_class_get_type (klass); */
8224
8225         gpointer args[2];
8226         args [0] = &klass;
8227         args [1] = &field;
8228
8229         return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8230 }
8231
8232 /**
8233  * mono_store_remote_field:
8234  * \param this_obj pointer to an object
8235  * \param klass klass of the object containing \p field
8236  * \param field the field to load
8237  * \param val the value/object to store
8238  * This method is called by the runtime on attempts to store fields of
8239  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8240  * the object containing \p field. \p val is the new value to store in \p field.
8241  */
8242 void
8243 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8244 {
8245         MonoError error;
8246         (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8247         mono_error_cleanup (&error);
8248 }
8249
8250 /**
8251  * mono_store_remote_field_checked:
8252  * \param this_obj pointer to an object
8253  * \param klass klass of the object containing \p field
8254  * \param field the field to load
8255  * \param val the value/object to store
8256  * \param error set on error
8257  * This method is called by the runtime on attempts to store fields of
8258  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8259  * the object containing \p field. \p val is the new value to store in \p field.
8260  * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8261  */
8262 gboolean
8263 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8264 {
8265         
8266         MONO_REQ_GC_UNSAFE_MODE;
8267
8268         error_init (error);
8269
8270         MonoDomain *domain = mono_domain_get ();
8271         MonoClass *field_class;
8272         MonoObject *arg;
8273
8274         g_assert (mono_object_is_transparent_proxy (this_obj));
8275
8276         field_class = mono_class_from_mono_type (field->type);
8277
8278         if (field_class->valuetype) {
8279                 arg = mono_value_box_checked (domain, field_class, val, error);
8280                 return_val_if_nok (error, FALSE);
8281         } else {
8282                 arg = *((MonoObject**)val);
8283         }
8284
8285         return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8286 }
8287
8288 /**
8289  * mono_store_remote_field_new:
8290  * \param this_obj
8291  * \param klass
8292  * \param field
8293  * \param arg
8294  * Missing documentation
8295  */
8296 void
8297 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8298 {
8299         MonoError error;
8300         (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8301         mono_error_cleanup (&error);
8302 }
8303
8304 /**
8305  * mono_store_remote_field_new_checked:
8306  * \param this_obj
8307  * \param klass
8308  * \param field
8309  * \param arg
8310  * \param error
8311  * Missing documentation
8312  */
8313 gboolean
8314 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8315 {
8316         MONO_REQ_GC_UNSAFE_MODE;
8317
8318         static MonoMethod *tp_store = NULL;
8319
8320         error_init (error);
8321
8322         g_assert (mono_object_is_transparent_proxy (this_obj));
8323
8324         if (!tp_store) {
8325                 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8326                 if (!tp_store) {
8327                         mono_error_set_not_supported (error, "Linked away.");
8328                         return FALSE;
8329                 }
8330         }
8331
8332         gpointer args[3];
8333         args [0] = &klass;
8334         args [1] = &field;
8335         args [2] = arg;
8336
8337         mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8338         return is_ok (error);
8339 }
8340 #endif
8341
8342 /**
8343  * mono_create_ftnptr:
8344  *
8345  * Given a function address, create a function descriptor for it.
8346  * This is only needed on some platforms.
8347  */
8348 gpointer
8349 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8350 {
8351         return callbacks.create_ftnptr (domain, addr);
8352 }
8353
8354 /*
8355  * mono_get_addr_from_ftnptr:
8356  *
8357  *   Given a pointer to a function descriptor, return the function address.
8358  * This is only needed on some platforms.
8359  */
8360 gpointer
8361 mono_get_addr_from_ftnptr (gpointer descr)
8362 {
8363         return callbacks.get_addr_from_ftnptr (descr);
8364 }       
8365
8366 /**
8367  * mono_string_chars:
8368  * \param s a \c MonoString
8369  * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8370  */
8371 gunichar2 *
8372 mono_string_chars (MonoString *s)
8373 {
8374         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8375
8376         return s->chars;
8377 }
8378
8379 /**
8380  * mono_string_length:
8381  * \param s MonoString
8382  * \returns the length in characters of the string
8383  */
8384 int
8385 mono_string_length (MonoString *s)
8386 {
8387         MONO_REQ_GC_UNSAFE_MODE;
8388
8389         return s->length;
8390 }
8391
8392 /**
8393  * mono_string_handle_length:
8394  * \param s \c MonoString
8395  * \returns the length in characters of the string
8396  */
8397 int
8398 mono_string_handle_length (MonoStringHandle s)
8399 {
8400         MONO_REQ_GC_UNSAFE_MODE;
8401
8402         return MONO_HANDLE_GETVAL (s, length);
8403 }
8404
8405
8406 /**
8407  * mono_array_length:
8408  * \param array a \c MonoArray*
8409  * \returns the total number of elements in the array. This works for
8410  * both vectors and multidimensional arrays.
8411  */
8412 uintptr_t
8413 mono_array_length (MonoArray *array)
8414 {
8415         MONO_REQ_GC_UNSAFE_MODE;
8416
8417         return array->max_length;
8418 }
8419
8420 /**
8421  * mono_array_addr_with_size:
8422  * \param array a \c MonoArray*
8423  * \param size size of the array elements
8424  * \param idx index into the array
8425  * Use this function to obtain the address for the \p idx item on the
8426  * \p array containing elements of size \p size.
8427  *
8428  * This method performs no bounds checking or type checking.
8429  * \returns the address of the \p idx element in the array.
8430  */
8431 char*
8432 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8433 {
8434         MONO_REQ_GC_UNSAFE_MODE;
8435
8436         return ((char*)(array)->vector) + size * idx;
8437 }
8438
8439
8440 MonoArray *
8441 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error) 
8442 {
8443         MonoDomain *domain = mono_domain_get ();
8444         MonoArray *res;
8445         int len, i;
8446
8447         error_init (error);
8448         if (!list)
8449                 return NULL;
8450
8451         len = g_list_length (list);
8452         res = mono_array_new_checked (domain, eclass, len, error);
8453         return_val_if_nok (error, NULL);
8454
8455         for (i = 0; list; list = list->next, i++)
8456                 mono_array_set (res, gpointer, i, list->data);
8457
8458         return res;
8459 }
8460
8461 #if NEVER_DEFINED
8462 /*
8463  * The following section is purely to declare prototypes and
8464  * document the API, as these C files are processed by our
8465  * tool
8466  */
8467
8468 /**
8469  * mono_array_set:
8470  * \param array array to alter
8471  * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8472  * \param index index into the array
8473  * \param value value to set
8474  * Value Type version: This sets the \p index's element of the \p array
8475  * with elements of size sizeof(type) to the provided \p value.
8476  *
8477  * This macro does not attempt to perform type checking or bounds checking.
8478  *
8479  * Use this to set value types in a \c MonoArray.
8480  */
8481 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8482 {
8483 }
8484
8485 /**
8486  * mono_array_setref:
8487  * \param array array to alter
8488  * \param index index into the array
8489  * \param value value to set
8490  * Reference Type version. This sets the \p index's element of the
8491  * \p array with elements of size sizeof(type) to the provided \p value.
8492  *
8493  * This macro does not attempt to perform type checking or bounds checking.
8494  *
8495  * Use this to reference types in a \c MonoArray.
8496  */
8497 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8498 {
8499 }
8500
8501 /**
8502  * mono_array_get:
8503  * \param array array on which to operate on
8504  * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8505  * \param index index into the array
8506  *
8507  * Use this macro to retrieve the \p index element of an \p array and
8508  * extract the value assuming that the elements of the array match
8509  * the provided type value.
8510  *
8511  * This method can be used with both arrays holding value types and
8512  * reference types.   For reference types, the \p type parameter should
8513  * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8514  *
8515  * This macro does not attempt to perform type checking or bounds checking.
8516  *
8517  * \returns The element at the \p index position in the \p array.
8518  */
8519 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8520 {
8521 }
8522 #endif
8523