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