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