Merge pull request #4570 from lateralusX/jlorenss/visual_studio_msbuild_fix
[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)
4491 {
4492         MONO_REQ_GC_UNSAFE_MODE;
4493
4494         MonoError error;
4495         MonoClassField *field;
4496         MonoDomain *current_domain, *root_domain;
4497         MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4498
4499         if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4500                 return;
4501
4502         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4503         g_assert (field);
4504
4505         current_domain = mono_domain_get ();
4506         root_domain = mono_get_root_domain ();
4507
4508         root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4509         mono_error_assert_ok (&error);
4510         if (current_domain != root_domain) {
4511                 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4512                 mono_error_assert_ok (&error);
4513         }
4514
4515         if (!current_appdomain_delegate && !root_appdomain_delegate) {
4516                 mono_print_unhandled_exception (exc);
4517         } else {
4518                 /* unhandled exception callbacks must not be aborted */
4519                 mono_threads_begin_abort_protected_block ();
4520                 if (root_appdomain_delegate)
4521                         call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4522                 if (current_appdomain_delegate)
4523                         call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4524                 mono_threads_end_abort_protected_block ();
4525         }
4526
4527         /* set exitcode only if we will abort the process */
4528         if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4529                  || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4530         {
4531                 mono_environment_exitcode_set (1);
4532         }
4533 }
4534
4535 /**
4536  * mono_runtime_exec_managed_code:
4537  * \param domain Application domain
4538  * \param main_func function to invoke from the execution thread
4539  * \param main_args parameter to the main_func
4540  * Launch a new thread to execute a function
4541  *
4542  * \p main_func is called back from the thread with main_args as the
4543  * parameter.  The callback function is expected to start \c Main
4544  * eventually.  This function then waits for all managed threads to
4545  * finish.
4546  * It is not necessary anymore to execute managed code in a subthread,
4547  * so this function should not be used anymore by default: just
4548  * execute the code and then call mono_thread_manage().
4549  */
4550 void
4551 mono_runtime_exec_managed_code (MonoDomain *domain,
4552                                 MonoMainThreadFunc main_func,
4553                                 gpointer main_args)
4554 {
4555         MonoError error;
4556         mono_thread_create_checked (domain, main_func, main_args, &error);
4557         mono_error_assert_ok (&error);
4558
4559         mono_thread_manage ();
4560 }
4561
4562 static void
4563 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4564 {
4565         MonoInternalThread* thread = mono_thread_internal_current ();
4566         MonoCustomAttrInfo* cinfo;
4567         gboolean has_stathread_attribute;
4568
4569         if (!domain->entry_assembly) {
4570                 gchar *str;
4571                 MonoAssembly *assembly;
4572
4573                 assembly = method->klass->image->assembly;
4574                 domain->entry_assembly = assembly;
4575                 /* Domains created from another domain already have application_base and configuration_file set */
4576                 if (domain->setup->application_base == NULL) {
4577                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4578                 }
4579
4580                 if (domain->setup->configuration_file == NULL) {
4581                         str = g_strconcat (assembly->image->name, ".config", NULL);
4582                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4583                         g_free (str);
4584                         mono_domain_set_options_from_config (domain);
4585                 }
4586         }
4587
4588         MonoError cattr_error;
4589         cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4590         mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4591         if (cinfo) {
4592                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4593                 if (!cinfo->cached)
4594                         mono_custom_attrs_free (cinfo);
4595         } else {
4596                 has_stathread_attribute = FALSE;
4597         }
4598         if (has_stathread_attribute) {
4599                 thread->apartment_state = ThreadApartmentState_STA;
4600         } else {
4601                 thread->apartment_state = ThreadApartmentState_MTA;
4602         }
4603         mono_thread_init_apartment_state ();
4604
4605 }
4606
4607 static int
4608 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4609 {
4610         MONO_REQ_GC_UNSAFE_MODE;
4611
4612         gpointer pa [1];
4613         int rval;
4614
4615         error_init (error);
4616         g_assert (args);
4617
4618         pa [0] = args;
4619
4620         /* FIXME: check signature of method */
4621         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4622                 MonoObject *res;
4623                 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4624                 if (is_ok (error))
4625                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4626                 else
4627                         rval = -1;
4628                 mono_environment_exitcode_set (rval);
4629         } else {
4630                 mono_runtime_invoke_checked (method, NULL, pa, error);
4631
4632                 if (is_ok (error))
4633                         rval = 0;
4634                 else {
4635                         rval = -1;
4636                 }
4637         }
4638         return rval;
4639 }
4640
4641 static int
4642 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4643 {
4644         MONO_REQ_GC_UNSAFE_MODE;
4645
4646         gpointer pa [1];
4647         int rval;
4648
4649         g_assert (args);
4650         g_assert (exc);
4651
4652         pa [0] = args;
4653
4654         /* FIXME: check signature of method */
4655         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4656                 MonoError inner_error;
4657                 MonoObject *res;
4658                 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4659                 if (*exc == NULL && !mono_error_ok (&inner_error))
4660                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4661                 else
4662                         mono_error_cleanup (&inner_error);
4663
4664                 if (*exc == NULL)
4665                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4666                 else
4667                         rval = -1;
4668
4669                 mono_environment_exitcode_set (rval);
4670         } else {
4671                 MonoError inner_error;
4672                 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4673                 if (*exc == NULL && !mono_error_ok (&inner_error))
4674                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4675                 else
4676                         mono_error_cleanup (&inner_error);
4677
4678                 if (*exc == NULL)
4679                         rval = 0;
4680                 else {
4681                         /* If the return type of Main is void, only
4682                          * set the exitcode if an exception was thrown
4683                          * (we don't want to blow away an
4684                          * explicitly-set exit code)
4685                          */
4686                         rval = -1;
4687                         mono_environment_exitcode_set (rval);
4688                 }
4689         }
4690
4691         return rval;
4692 }
4693
4694 /*
4695  * Execute a standard Main() method (args doesn't contain the
4696  * executable name).
4697  */
4698 int
4699 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4700 {
4701         MonoError error;
4702         prepare_thread_to_exec_main (mono_object_domain (args), method);
4703         if (exc) {
4704                 int rval = do_try_exec_main (method, args, exc);
4705                 return rval;
4706         } else {
4707                 int rval = do_exec_main_checked (method, args, &error);
4708                 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4709                 return rval;
4710         }
4711 }
4712
4713 /*
4714  * Execute a standard Main() method (args doesn't contain the
4715  * executable name).
4716  *
4717  * On failure sets @error
4718  */
4719 int
4720 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4721 {
4722         error_init (error);
4723         prepare_thread_to_exec_main (mono_object_domain (args), method);
4724         return do_exec_main_checked (method, args, error);
4725 }
4726
4727 /*
4728  * Execute a standard Main() method (args doesn't contain the
4729  * executable name).
4730  *
4731  * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4732  */
4733 int
4734 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4735 {
4736         prepare_thread_to_exec_main (mono_object_domain (args), method);
4737         return do_try_exec_main (method, args, exc);
4738 }
4739
4740
4741
4742 /** invoke_array_extract_argument:
4743  * @params: array of arguments to the method.
4744  * @i: the index of the argument to extract.
4745  * @t: ith type from the method signature.
4746  * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4747  * @error: set on error.
4748  *
4749  * Given an array of method arguments, return the ith one using the corresponding type
4750  * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4751  *
4752  * On failure sets @error and returns NULL.
4753  */
4754 static gpointer
4755 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4756 {
4757         MonoType *t_orig = t;
4758         gpointer result = NULL;
4759         error_init (error);
4760                 again:
4761                         switch (t->type) {
4762                         case MONO_TYPE_U1:
4763                         case MONO_TYPE_I1:
4764                         case MONO_TYPE_BOOLEAN:
4765                         case MONO_TYPE_U2:
4766                         case MONO_TYPE_I2:
4767                         case MONO_TYPE_CHAR:
4768                         case MONO_TYPE_U:
4769                         case MONO_TYPE_I:
4770                         case MONO_TYPE_U4:
4771                         case MONO_TYPE_I4:
4772                         case MONO_TYPE_U8:
4773                         case MONO_TYPE_I8:
4774                         case MONO_TYPE_R4:
4775                         case MONO_TYPE_R8:
4776                         case MONO_TYPE_VALUETYPE:
4777                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4778                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4779                                         result = mono_array_get (params, MonoObject*, i);
4780                                         if (t->byref)
4781                                                 *has_byref_nullables = TRUE;
4782                                 } else {
4783                                         /* MS seems to create the objects if a null is passed in */
4784                                         gboolean was_null = FALSE;
4785                                         if (!mono_array_get (params, MonoObject*, i)) {
4786                                                 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4787                                                 return_val_if_nok (error, NULL);
4788                                                 mono_array_setref (params, i, o); 
4789                                                 was_null = TRUE;
4790                                         }
4791
4792                                         if (t->byref) {
4793                                                 /*
4794                                                  * We can't pass the unboxed vtype byref to the callee, since
4795                                                  * that would mean the callee would be able to modify boxed
4796                                                  * primitive types. So we (and MS) make a copy of the boxed
4797                                                  * object, pass that to the callee, and replace the original
4798                                                  * boxed object in the arg array with the copy.
4799                                                  */
4800                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4801                                                 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4802                                                 return_val_if_nok (error, NULL);
4803                                                 mono_array_setref (params, i, copy);
4804                                         }
4805                                                 
4806                                         result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4807                                         if (!t->byref && was_null)
4808                                                 mono_array_setref (params, i, NULL);
4809                                 }
4810                                 break;
4811                         case MONO_TYPE_STRING:
4812                         case MONO_TYPE_OBJECT:
4813                         case MONO_TYPE_CLASS:
4814                         case MONO_TYPE_ARRAY:
4815                         case MONO_TYPE_SZARRAY:
4816                                 if (t->byref)
4817                                         result = mono_array_addr (params, MonoObject*, i);
4818                                         // FIXME: I need to check this code path
4819                                 else
4820                                         result = mono_array_get (params, MonoObject*, i);
4821                                 break;
4822                         case MONO_TYPE_GENERICINST:
4823                                 if (t->byref)
4824                                         t = &t->data.generic_class->container_class->this_arg;
4825                                 else
4826                                         t = &t->data.generic_class->container_class->byval_arg;
4827                                 goto again;
4828                         case MONO_TYPE_PTR: {
4829                                 MonoObject *arg;
4830
4831                                 /* The argument should be an IntPtr */
4832                                 arg = mono_array_get (params, MonoObject*, i);
4833                                 if (arg == NULL) {
4834                                         result = NULL;
4835                                 } else {
4836                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4837                                         result = ((MonoIntPtr*)arg)->m_value;
4838                                 }
4839                                 break;
4840                         }
4841                         default:
4842                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4843                         }
4844         return result;
4845 }
4846 /**
4847  * mono_runtime_invoke_array:
4848  * \param method method to invoke
4849  * \param obj object instance
4850  * \param params arguments to the method
4851  * \param exc exception information.
4852  * Invokes the method represented by \p method on the object \p obj.
4853  *
4854  * \p obj is the \c this pointer, it should be NULL for static
4855  * methods, a \c MonoObject* for object instances and a pointer to
4856  * the value type for value types.
4857  *
4858  * The \p params array contains the arguments to the method with the
4859  * same convention: \c MonoObject* pointers for object instances and
4860  * pointers to the value type otherwise. The \c _invoke_array
4861  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4862  * in this case the value types are boxed inside the
4863  * respective reference representation.
4864  * 
4865  * From unmanaged code you'll usually use the
4866  * mono_runtime_invoke_checked() variant.
4867  *
4868  * Note that this function doesn't handle virtual methods for
4869  * you, it will exec the exact method you pass: we still need to
4870  * expose a function to lookup the derived class implementation
4871  * of a virtual method (there are examples of this in the code,
4872  * though).
4873  * 
4874  * You can pass NULL as the \p exc argument if you don't want to
4875  * catch exceptions, otherwise, \c *exc will be set to the exception
4876  * thrown, if any.  if an exception is thrown, you can't use the
4877  * \c MonoObject* result from the function.
4878  * 
4879  * If the method returns a value type, it is boxed in an object
4880  * reference.
4881  */
4882 MonoObject*
4883 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4884                            MonoObject **exc)
4885 {
4886         MonoError error;
4887         if (exc) {
4888                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4889                 if (*exc) {
4890                         mono_error_cleanup (&error);
4891                         return NULL;
4892                 } else {
4893                         if (!is_ok (&error))
4894                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4895                         return result;
4896                 }
4897         } else {
4898                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4899                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4900                 return result;
4901         }
4902 }
4903
4904 /**
4905  * mono_runtime_invoke_array_checked:
4906  * \param method method to invoke
4907  * \param obj object instance
4908  * \param params arguments to the method
4909  * \param error set on failure.
4910  * Invokes the method represented by \p method on the object \p obj.
4911  *
4912  * \p obj is the \c this pointer, it should be NULL for static
4913  * methods, a \c MonoObject* for object instances and a pointer to
4914  * the value type for value types.
4915  *
4916  * The \p params array contains the arguments to the method with the
4917  * same convention: \c MonoObject* pointers for object instances and
4918  * pointers to the value type otherwise. The \c _invoke_array
4919  * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4920  * in this case the value types are boxed inside the
4921  * respective reference representation.
4922  *
4923  * From unmanaged code you'll usually use the
4924  * mono_runtime_invoke_checked() variant.
4925  *
4926  * Note that this function doesn't handle virtual methods for
4927  * you, it will exec the exact method you pass: we still need to
4928  * expose a function to lookup the derived class implementation
4929  * of a virtual method (there are examples of this in the code,
4930  * though).
4931  *
4932  * On failure or exception, \p error will be set. In that case, you
4933  * can't use the \c MonoObject* result from the function.
4934  *
4935  * If the method returns a value type, it is boxed in an object
4936  * reference.
4937  */
4938 MonoObject*
4939 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4940                                    MonoError *error)
4941 {
4942         error_init (error);
4943         return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4944 }
4945
4946 /**
4947  * mono_runtime_try_invoke_array:
4948  * \param method method to invoke
4949  * \param obj object instance
4950  * \param params arguments to the method
4951  * \param exc exception information.
4952  * \param error set on failure.
4953  * Invokes the method represented by \p method on the object \p obj.
4954  *
4955  * \p obj is the \c this pointer, it should be NULL for static
4956  * methods, a \c MonoObject* for object instances and a pointer to
4957  * the value type for value types.
4958  *
4959  * The \p params array contains the arguments to the method with the
4960  * same convention: \c MonoObject* pointers for object instances and
4961  * pointers to the value type otherwise. The \c _invoke_array
4962  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4963  * in this case the value types are boxed inside the
4964  * respective reference representation.
4965  *
4966  * From unmanaged code you'll usually use the
4967  * mono_runtime_invoke_checked() variant.
4968  *
4969  * Note that this function doesn't handle virtual methods for
4970  * you, it will exec the exact method you pass: we still need to
4971  * expose a function to lookup the derived class implementation
4972  * of a virtual method (there are examples of this in the code,
4973  * though).
4974  *
4975  * You can pass NULL as the \p exc argument if you don't want to catch
4976  * exceptions, otherwise, \c *exc will be set to the exception thrown, if
4977  * any.  On other failures, \p error will be set. If an exception is
4978  * thrown or there's an error, you can't use the \c MonoObject* result
4979  * from the function.
4980  *
4981  * If the method returns a value type, it is boxed in an object
4982  * reference.
4983  */
4984 MonoObject*
4985 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4986                                MonoObject **exc, MonoError *error)
4987 {
4988         MONO_REQ_GC_UNSAFE_MODE;
4989
4990         error_init (error);
4991
4992         MonoMethodSignature *sig = mono_method_signature (method);
4993         gpointer *pa = NULL;
4994         MonoObject *res;
4995         int i;
4996         gboolean has_byref_nullables = FALSE;
4997
4998         if (NULL != params) {
4999                 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5000                 for (i = 0; i < mono_array_length (params); i++) {
5001                         MonoType *t = sig->params [i];
5002                         pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5003                         return_val_if_nok (error, NULL);
5004                 }
5005         }
5006
5007         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5008                 void *o = obj;
5009
5010                 if (mono_class_is_nullable (method->klass)) {
5011                         /* Need to create a boxed vtype instead */
5012                         g_assert (!obj);
5013
5014                         if (!params)
5015                                 return NULL;
5016                         else {
5017                                 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5018                         }
5019                 }
5020
5021                 if (!obj) {
5022                         obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5023                         mono_error_assert_ok (error);
5024                         g_assert (obj); /*maybe we should raise a TLE instead?*/
5025 #ifndef DISABLE_REMOTING
5026                         if (mono_object_is_transparent_proxy (obj)) {
5027                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5028                         }
5029 #endif
5030                         if (method->klass->valuetype)
5031                                 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5032                         else
5033                                 o = obj;
5034                 } else if (method->klass->valuetype) {
5035                         obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5036                         return_val_if_nok (error, NULL);
5037                 }
5038
5039                 if (exc) {
5040                         mono_runtime_try_invoke (method, o, pa, exc, error);
5041                 } else {
5042                         mono_runtime_invoke_checked (method, o, pa, error);
5043                 }
5044
5045                 return (MonoObject *)obj;
5046         } else {
5047                 if (mono_class_is_nullable (method->klass)) {
5048                         MonoObject *nullable;
5049
5050                         /* Convert the unboxed vtype into a Nullable structure */
5051                         nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5052                         return_val_if_nok (error, NULL);
5053
5054                         MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5055                         return_val_if_nok (error, NULL);
5056                         mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5057                         obj = mono_object_unbox (nullable);
5058                 }
5059
5060                 /* obj must be already unboxed if needed */
5061                 if (exc) {
5062                         res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5063                 } else {
5064                         res = mono_runtime_invoke_checked (method, obj, pa, error);
5065                 }
5066                 return_val_if_nok (error, NULL);
5067
5068                 if (sig->ret->type == MONO_TYPE_PTR) {
5069                         MonoClass *pointer_class;
5070                         static MonoMethod *box_method;
5071                         void *box_args [2];
5072                         MonoObject *box_exc;
5073
5074                         /* 
5075                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
5076                          * convert it to a Pointer object.
5077                          */
5078                         pointer_class = mono_class_get_pointer_class ();
5079                         if (!box_method)
5080                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5081
5082                         g_assert (res->vtable->klass == mono_defaults.int_class);
5083                         box_args [0] = ((MonoIntPtr*)res)->m_value;
5084                         box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5085                         return_val_if_nok (error, NULL);
5086
5087                         res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5088                         g_assert (box_exc == NULL);
5089                         mono_error_assert_ok (error);
5090                 }
5091
5092                 if (has_byref_nullables) {
5093                         /* 
5094                          * The runtime invoke wrapper already converted byref nullables back,
5095                          * and stored them in pa, we just need to copy them back to the
5096                          * managed array.
5097                          */
5098                         for (i = 0; i < mono_array_length (params); i++) {
5099                                 MonoType *t = sig->params [i];
5100
5101                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5102                                         mono_array_setref (params, i, pa [i]);
5103                         }
5104                 }
5105
5106                 return res;
5107         }
5108 }
5109
5110 /**
5111  * mono_object_new:
5112  * \param klass the class of the object that we want to create
5113  * \returns a newly created object whose definition is
5114  * looked up using \p klass.   This will not invoke any constructors, 
5115  * so the consumer of this routine has to invoke any constructors on
5116  * its own to initialize the object.
5117  * 
5118  * It returns NULL on failure.
5119  */
5120 MonoObject *
5121 mono_object_new (MonoDomain *domain, MonoClass *klass)
5122 {
5123         MONO_REQ_GC_UNSAFE_MODE;
5124
5125         MonoError error;
5126
5127         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5128
5129         mono_error_cleanup (&error);
5130         return result;
5131 }
5132
5133 MonoObject *
5134 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5135 {
5136         MONO_REQ_GC_UNSAFE_MODE;
5137
5138         MonoError error;
5139
5140         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5141
5142         mono_error_set_pending_exception (&error);
5143         return result;
5144 }
5145
5146 /**
5147  * mono_object_new_checked:
5148  * \param klass the class of the object that we want to create
5149  * \param error set on error
5150  * \returns a newly created object whose definition is
5151  * looked up using \p klass.   This will not invoke any constructors,
5152  * so the consumer of this routine has to invoke any constructors on
5153  * its own to initialize the object.
5154  *
5155  * It returns NULL on failure and sets \p error.
5156  */
5157 MonoObject *
5158 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5159 {
5160         MONO_REQ_GC_UNSAFE_MODE;
5161
5162         MonoVTable *vtable;
5163
5164         vtable = mono_class_vtable (domain, klass);
5165         g_assert (vtable); /* FIXME don't swallow the error */
5166
5167         MonoObject *o = mono_object_new_specific_checked (vtable, error);
5168         return o;
5169 }
5170
5171 /**
5172  * mono_object_new_pinned:
5173  *
5174  *   Same as mono_object_new, but the returned object will be pinned.
5175  * For SGEN, these objects will only be freed at appdomain unload.
5176  */
5177 MonoObject *
5178 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5179 {
5180         MONO_REQ_GC_UNSAFE_MODE;
5181
5182         MonoVTable *vtable;
5183
5184         error_init (error);
5185
5186         vtable = mono_class_vtable (domain, klass);
5187         g_assert (vtable); /* FIXME don't swallow the error */
5188
5189         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5190
5191         if (G_UNLIKELY (!o))
5192                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5193         else if (G_UNLIKELY (vtable->klass->has_finalize))
5194                 mono_object_register_finalizer (o);
5195
5196         return o;
5197 }
5198
5199 /**
5200  * mono_object_new_specific:
5201  * \param vtable the vtable of the object that we want to create
5202  * \returns A newly created object with class and domain specified
5203  * by \p vtable
5204  */
5205 MonoObject *
5206 mono_object_new_specific (MonoVTable *vtable)
5207 {
5208         MonoError error;
5209         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5210         mono_error_cleanup (&error);
5211
5212         return o;
5213 }
5214
5215 MonoObject *
5216 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5217 {
5218         MONO_REQ_GC_UNSAFE_MODE;
5219
5220         MonoObject *o;
5221
5222         error_init (error);
5223
5224         /* check for is_com_object for COM Interop */
5225         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5226         {
5227                 gpointer pa [1];
5228                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5229
5230                 if (im == NULL) {
5231                         MonoClass *klass = mono_class_get_activation_services_class ();
5232
5233                         if (!klass->inited)
5234                                 mono_class_init (klass);
5235
5236                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5237                         if (!im) {
5238                                 mono_error_set_not_supported (error, "Linked away.");
5239                                 return NULL;
5240                         }
5241                         vtable->domain->create_proxy_for_type_method = im;
5242                 }
5243         
5244                 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5245                 if (!mono_error_ok (error))
5246                         return NULL;
5247
5248                 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5249                 if (!mono_error_ok (error))
5250                         return NULL;
5251
5252                 if (o != NULL)
5253                         return o;
5254         }
5255
5256         return mono_object_new_alloc_specific_checked (vtable, error);
5257 }
5258
5259 MonoObject *
5260 ves_icall_object_new_specific (MonoVTable *vtable)
5261 {
5262         MonoError error;
5263         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5264         mono_error_set_pending_exception (&error);
5265
5266         return o;
5267 }
5268
5269 /**
5270  * mono_object_new_alloc_specific:
5271  * \param vtable virtual table for the object.
5272  * This function allocates a new \c MonoObject with the type derived
5273  * from the \p vtable information.   If the class of this object has a 
5274  * finalizer, then the object will be tracked for finalization.
5275  *
5276  * This method might raise an exception on errors.  Use the
5277  * \c mono_object_new_fast_checked method if you want to manually raise
5278  * the exception.
5279  *
5280  * \returns the allocated object.   
5281  */
5282 MonoObject *
5283 mono_object_new_alloc_specific (MonoVTable *vtable)
5284 {
5285         MonoError error;
5286         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5287         mono_error_cleanup (&error);
5288
5289         return o;
5290 }
5291
5292 /**
5293  * mono_object_new_alloc_specific_checked:
5294  * \param vtable virtual table for the object.
5295  * \param error holds the error return value.  
5296  *
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  * If there is not enough memory, the \p error parameter will be set
5302  * and will contain a user-visible message with the amount of bytes
5303  * that were requested.
5304  *
5305  * \returns the allocated object, or NULL if there is not enough memory
5306  */
5307 MonoObject *
5308 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5309 {
5310         MONO_REQ_GC_UNSAFE_MODE;
5311
5312         MonoObject *o;
5313
5314         error_init (error);
5315
5316         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5317
5318         if (G_UNLIKELY (!o))
5319                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5320         else if (G_UNLIKELY (vtable->klass->has_finalize))
5321                 mono_object_register_finalizer (o);
5322
5323         return o;
5324 }
5325
5326 /**
5327  * mono_object_new_fast:
5328  * \param vtable virtual table for the object.
5329  *
5330  * This function allocates a new \c MonoObject with the type derived
5331  * from the \p vtable information.   The returned object is not tracked
5332  * for finalization.   If your object implements a finalizer, you should
5333  * use \c mono_object_new_alloc_specific instead.
5334  *
5335  * This method might raise an exception on errors.  Use the
5336  * \c mono_object_new_fast_checked method if you want to manually raise
5337  * the exception.
5338  *
5339  * \returns the allocated object.   
5340  */
5341 MonoObject*
5342 mono_object_new_fast (MonoVTable *vtable)
5343 {
5344         MonoError error;
5345         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5346         mono_error_cleanup (&error);
5347
5348         return o;
5349 }
5350
5351 /**
5352  * mono_object_new_fast_checked:
5353  * \param vtable virtual table for the object.
5354  * \param error holds the error return value.
5355  *
5356  * This function allocates a new \c MonoObject with the type derived
5357  * from the \p vtable information. The returned object is not tracked
5358  * for finalization.   If your object implements a finalizer, you should
5359  * use \c mono_object_new_alloc_specific_checked instead.
5360  *
5361  * If there is not enough memory, the \p error parameter will be set
5362  * and will contain a user-visible message with the amount of bytes
5363  * that were requested.
5364  *
5365  * \returns the allocated object, or NULL if there is not enough memory
5366  */
5367 MonoObject*
5368 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5369 {
5370         MONO_REQ_GC_UNSAFE_MODE;
5371
5372         MonoObject *o;
5373
5374         error_init (error);
5375
5376         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5377
5378         if (G_UNLIKELY (!o))
5379                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5380
5381         return o;
5382 }
5383
5384 MonoObject *
5385 ves_icall_object_new_fast (MonoVTable *vtable)
5386 {
5387         MonoError error;
5388         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5389         mono_error_set_pending_exception (&error);
5390
5391         return o;
5392 }
5393
5394 MonoObject*
5395 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5396 {
5397         MONO_REQ_GC_UNSAFE_MODE;
5398
5399         MonoObject *o;
5400
5401         error_init (error);
5402
5403         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5404
5405         if (G_UNLIKELY (!o))
5406                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5407         else if (G_UNLIKELY (vtable->klass->has_finalize))
5408                 mono_object_register_finalizer (o);
5409
5410         return o;
5411 }
5412
5413 /**
5414  * mono_class_get_allocation_ftn:
5415  * \param vtable vtable
5416  * \param for_box the object will be used for boxing
5417  * \param pass_size_in_words Unused
5418  * \returns the allocation function appropriate for the given class.
5419  */
5420 void*
5421 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5422 {
5423         MONO_REQ_GC_NEUTRAL_MODE;
5424
5425         *pass_size_in_words = FALSE;
5426
5427         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5428                 return ves_icall_object_new_specific;
5429
5430         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5431
5432                 return ves_icall_object_new_fast;
5433
5434                 /* 
5435                  * FIXME: This is actually slower than ves_icall_object_new_fast, because
5436                  * of the overhead of parameter passing.
5437                  */
5438                 /*
5439                 *pass_size_in_words = TRUE;
5440 #ifdef GC_REDIRECT_TO_LOCAL
5441                 return GC_local_gcj_fast_malloc;
5442 #else
5443                 return GC_gcj_fast_malloc;
5444 #endif
5445                 */
5446         }
5447
5448         return ves_icall_object_new_specific;
5449 }
5450
5451 /**
5452  * mono_object_new_from_token:
5453  * \param image Context where the type_token is hosted
5454  * \param token a token of the type that we want to create
5455  * \returns A newly created object whose definition is
5456  * looked up using \p token in the \p image image
5457  */
5458 MonoObject *
5459 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
5460 {
5461         MONO_REQ_GC_UNSAFE_MODE;
5462
5463         MonoError error;
5464         MonoObject *result;
5465         MonoClass *klass;
5466
5467         klass = mono_class_get_checked (image, token, &error);
5468         mono_error_assert_ok (&error);
5469         
5470         result = mono_object_new_checked (domain, klass, &error);
5471
5472         mono_error_cleanup (&error);
5473         return result;
5474         
5475 }
5476
5477
5478 /**
5479  * mono_object_clone:
5480  * \param obj the object to clone
5481  * \returns A newly created object who is a shallow copy of \p obj
5482  */
5483 MonoObject *
5484 mono_object_clone (MonoObject *obj)
5485 {
5486         MonoError error;
5487         MonoObject *o = mono_object_clone_checked (obj, &error);
5488         mono_error_cleanup (&error);
5489
5490         return o;
5491 }
5492
5493 MonoObject *
5494 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5495 {
5496         MONO_REQ_GC_UNSAFE_MODE;
5497
5498         MonoObject *o;
5499         int size;
5500
5501         error_init (error);
5502
5503         size = obj->vtable->klass->instance_size;
5504
5505         if (obj->vtable->klass->rank)
5506                 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5507
5508         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5509
5510         if (G_UNLIKELY (!o)) {
5511                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5512                 return NULL;
5513         }
5514
5515         /* If the object doesn't contain references this will do a simple memmove. */
5516         mono_gc_wbarrier_object_copy (o, obj);
5517
5518         if (obj->vtable->klass->has_finalize)
5519                 mono_object_register_finalizer (o);
5520         return o;
5521 }
5522
5523 /**
5524  * mono_array_full_copy:
5525  * \param src source array to copy
5526  * \param dest destination array
5527  * Copies the content of one array to another with exactly the same type and size.
5528  */
5529 void
5530 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5531 {
5532         MONO_REQ_GC_UNSAFE_MODE;
5533
5534         uintptr_t size;
5535         MonoClass *klass = src->obj.vtable->klass;
5536
5537         g_assert (klass == dest->obj.vtable->klass);
5538
5539         size = mono_array_length (src);
5540         g_assert (size == mono_array_length (dest));
5541         size *= mono_array_element_size (klass);
5542
5543         array_full_copy_unchecked_size (src, dest, klass, size);
5544 }
5545
5546 static void
5547 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5548 {
5549 #ifdef HAVE_SGEN_GC
5550         if (klass->element_class->valuetype) {
5551                 if (klass->element_class->has_references)
5552                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5553                 else
5554                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5555         } else {
5556                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5557         }
5558 #else
5559         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5560 #endif
5561 }
5562
5563 /**
5564  * mono_array_clone_in_domain:
5565  * \param domain the domain in which the array will be cloned into
5566  * \param array the array to clone
5567  * \param error set on error
5568  * This routine returns a copy of the array that is hosted on the
5569  * specified \c MonoDomain.  On failure returns NULL and sets \p error.
5570  */
5571 MonoArrayHandle
5572 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5573 {
5574         MONO_REQ_GC_UNSAFE_MODE;
5575
5576         MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5577         uintptr_t size = 0;
5578         MonoClass *klass = mono_handle_class (array_handle);
5579
5580         error_init (error);
5581
5582         /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5583         uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5584         
5585         MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5586         MonoArrayHandle o;
5587         if (array_bounds == NULL) {
5588                 size = mono_array_handle_length (array_handle);
5589                 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5590                 if (!is_ok (error))
5591                         goto leave;
5592                 size *= mono_array_element_size (klass);
5593         } else {
5594                 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5595                 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5596                 size = mono_array_element_size (klass);
5597                 for (int i = 0; i < klass->rank; ++i) {
5598                         sizes [i] = array_bounds [i].length;
5599                         size *= array_bounds [i].length;
5600                         lower_bounds [i] = array_bounds [i].lower_bound;
5601                 }
5602                 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5603                 if (!is_ok (error))
5604                         goto leave;
5605         }
5606
5607         uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5608         array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5609         mono_gchandle_free (dst_handle);
5610
5611         MONO_HANDLE_ASSIGN (result, o);
5612
5613 leave:
5614         mono_gchandle_free (src_handle);
5615         return result;
5616 }
5617
5618 /**
5619  * mono_array_clone:
5620  * \param array the array to clone
5621  * \returns A newly created array who is a shallow copy of \p array
5622  */
5623 MonoArray*
5624 mono_array_clone (MonoArray *array)
5625 {
5626         MONO_REQ_GC_UNSAFE_MODE;
5627
5628         MonoError error;
5629         MonoArray *result = mono_array_clone_checked (array, &error);
5630         mono_error_cleanup (&error);
5631         return result;
5632 }
5633
5634 /**
5635  * mono_array_clone_checked:
5636  * \param array the array to clone
5637  * \param error set on error
5638  * \returns A newly created array who is a shallow copy of \p array.  On
5639  * failure returns NULL and sets \p error.
5640  */
5641 MonoArray*
5642 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5643 {
5644         MONO_REQ_GC_UNSAFE_MODE;
5645         HANDLE_FUNCTION_ENTER ();
5646         /* FIXME: callers of mono_array_clone_checked should use handles */
5647         error_init (error);
5648         MONO_HANDLE_DCL (MonoArray, array);
5649         MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5650         HANDLE_FUNCTION_RETURN_OBJ (result);
5651 }
5652
5653 /* helper macros to check for overflow when calculating the size of arrays */
5654 #ifdef MONO_BIG_ARRAYS
5655 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5656 #define MYGUINT_MAX MYGUINT64_MAX
5657 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5658             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5659 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5660             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
5661                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5662 #else
5663 #define MYGUINT32_MAX 4294967295U
5664 #define MYGUINT_MAX MYGUINT32_MAX
5665 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5666             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5667 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5668             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
5669                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5670 #endif
5671
5672 gboolean
5673 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5674 {
5675         MONO_REQ_GC_NEUTRAL_MODE;
5676
5677         uintptr_t byte_len;
5678
5679         byte_len = mono_array_element_size (klass);
5680         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5681                 return FALSE;
5682         byte_len *= len;
5683         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5684                 return FALSE;
5685         byte_len += MONO_SIZEOF_MONO_ARRAY;
5686
5687         *res = byte_len;
5688
5689         return TRUE;
5690 }
5691
5692 /**
5693  * mono_array_new_full:
5694  * \param domain domain where the object is created
5695  * \param array_class array class
5696  * \param lengths lengths for each dimension in the array
5697  * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5698  * This routine creates a new array object with the given dimensions,
5699  * lower bounds and type.
5700  */
5701 MonoArray*
5702 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5703 {
5704         MonoError error;
5705         MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5706         mono_error_cleanup (&error);
5707
5708         return array;
5709 }
5710
5711 MonoArray*
5712 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5713 {
5714         MONO_REQ_GC_UNSAFE_MODE;
5715
5716         uintptr_t byte_len = 0, len, bounds_size;
5717         MonoObject *o;
5718         MonoArray *array;
5719         MonoArrayBounds *bounds;
5720         MonoVTable *vtable;
5721         int i;
5722
5723         error_init (error);
5724
5725         if (!array_class->inited)
5726                 mono_class_init (array_class);
5727
5728         len = 1;
5729
5730         /* A single dimensional array with a 0 lower bound is the same as an szarray */
5731         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5732                 len = lengths [0];
5733                 if (len > MONO_ARRAY_MAX_INDEX) {
5734                         mono_error_set_generic_error (error, "System", "OverflowException", "");
5735                         return NULL;
5736                 }
5737                 bounds_size = 0;
5738         } else {
5739                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5740
5741                 for (i = 0; i < array_class->rank; ++i) {
5742                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5743                                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5744                                 return NULL;
5745                         }
5746                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5747                                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5748                                 return NULL;
5749                         }
5750                         len *= lengths [i];
5751                 }
5752         }
5753
5754         if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5755                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5756                 return NULL;
5757         }
5758
5759         if (bounds_size) {
5760                 /* align */
5761                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5762                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5763                         return NULL;
5764                 }
5765                 byte_len = (byte_len + 3) & ~3;
5766                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5767                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5768                         return NULL;
5769                 }
5770                 byte_len += bounds_size;
5771         }
5772         /* 
5773          * Following three lines almost taken from mono_object_new ():
5774          * they need to be kept in sync.
5775          */
5776         vtable = mono_class_vtable_full (domain, array_class, error);
5777         return_val_if_nok (error, NULL);
5778
5779         if (bounds_size)
5780                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5781         else
5782                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5783
5784         if (G_UNLIKELY (!o)) {
5785                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5786                 return NULL;
5787         }
5788
5789         array = (MonoArray*)o;
5790
5791         bounds = array->bounds;
5792
5793         if (bounds_size) {
5794                 for (i = 0; i < array_class->rank; ++i) {
5795                         bounds [i].length = lengths [i];
5796                         if (lower_bounds)
5797                                 bounds [i].lower_bound = lower_bounds [i];
5798                 }
5799         }
5800
5801         return array;
5802 }
5803
5804 /**
5805  * mono_array_new:
5806  * \param domain domain where the object is created
5807  * \param eclass element class
5808  * \param n number of array elements
5809  * This routine creates a new szarray with \p n elements of type \p eclass.
5810  */
5811 MonoArray *
5812 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5813 {
5814         MONO_REQ_GC_UNSAFE_MODE;
5815
5816         MonoError error;
5817         MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5818         mono_error_cleanup (&error);
5819         return result;
5820 }
5821
5822 /**
5823  * mono_array_new_checked:
5824  * \param domain domain where the object is created
5825  * \param eclass element class
5826  * \param n number of array elements
5827  * \param error set on error
5828  * This routine creates a new szarray with \p n elements of type \p eclass.
5829  * On failure returns NULL and sets \p error.
5830  */
5831 MonoArray *
5832 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5833 {
5834         MonoClass *ac;
5835
5836         error_init (error);
5837
5838         ac = mono_array_class_get (eclass, 1);
5839         g_assert (ac);
5840
5841         MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5842         return_val_if_nok (error, NULL);
5843
5844         return mono_array_new_specific_checked (vtable, n, error);
5845 }
5846
5847 MonoArray*
5848 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5849 {
5850         MonoError error;
5851         MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5852         mono_error_set_pending_exception (&error);
5853
5854         return arr;
5855 }
5856
5857 /**
5858  * mono_array_new_specific:
5859  * \param vtable a vtable in the appropriate domain for an initialized class
5860  * \param n number of array elements
5861  * This routine is a fast alternative to \c mono_array_new for code which
5862  * can be sure about the domain it operates in.
5863  */
5864 MonoArray *
5865 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5866 {
5867         MonoError error;
5868         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5869         mono_error_cleanup (&error);
5870
5871         return arr;
5872 }
5873
5874 MonoArray*
5875 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5876 {
5877         MONO_REQ_GC_UNSAFE_MODE;
5878
5879         MonoObject *o;
5880         uintptr_t byte_len;
5881
5882         error_init (error);
5883
5884         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5885                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5886                 return NULL;
5887         }
5888
5889         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5890                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5891                 return NULL;
5892         }
5893         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5894
5895         if (G_UNLIKELY (!o)) {
5896                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5897                 return NULL;
5898         }
5899
5900         return (MonoArray*)o;
5901 }
5902
5903 MonoArray*
5904 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5905 {
5906         MonoError error;
5907         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5908         mono_error_set_pending_exception (&error);
5909
5910         return arr;
5911 }
5912
5913 /**
5914  * mono_string_empty_wrapper:
5915  *
5916  * Returns: The same empty string instance as the managed string.Empty
5917  */
5918 MonoString*
5919 mono_string_empty_wrapper (void)
5920 {
5921         MonoDomain *domain = mono_domain_get ();
5922         return mono_string_empty (domain);
5923 }
5924
5925 /**
5926  * mono_string_empty:
5927  *
5928  * Returns: The same empty string instance as the managed string.Empty
5929  */
5930 MonoString*
5931 mono_string_empty (MonoDomain *domain)
5932 {
5933         g_assert (domain);
5934         g_assert (domain->empty_string);
5935         return domain->empty_string;
5936 }
5937
5938 /**
5939  * mono_string_new_utf16:
5940  * \param text a pointer to an utf16 string
5941  * \param len the length of the string
5942  * \returns A newly created string object which contains \p text.
5943  */
5944 MonoString *
5945 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5946 {
5947         MONO_REQ_GC_UNSAFE_MODE;
5948
5949         MonoError error;
5950         MonoString *res = NULL;
5951         res = mono_string_new_utf16_checked (domain, text, len, &error);
5952         mono_error_cleanup (&error);
5953
5954         return res;
5955 }
5956
5957 /**
5958  * mono_string_new_utf16_checked:
5959  * \param text a pointer to an utf16 string
5960  * \param len the length of the string
5961  * \param error written on error.
5962  * \returns A newly created string object which contains \p text.
5963  * On error, returns NULL and sets \p error.
5964  */
5965 MonoString *
5966 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5967 {
5968         MONO_REQ_GC_UNSAFE_MODE;
5969
5970         MonoString *s;
5971         
5972         error_init (error);
5973         
5974         s = mono_string_new_size_checked (domain, len, error);
5975         if (s != NULL)
5976                 memcpy (mono_string_chars (s), text, len * 2);
5977
5978         return s;
5979 }
5980
5981 /**
5982  * mono_string_new_utf16_handle:
5983  * \param text a pointer to an utf16 string
5984  * \param len the length of the string
5985  * \param error written on error.
5986  * \returns A newly created string object which contains \p text.
5987  * On error, returns NULL and sets \p error.
5988  */
5989 MonoStringHandle
5990 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5991 {
5992         return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
5993 }
5994
5995 /**
5996  * mono_string_new_utf32_checked:
5997  * \param text a pointer to an utf32 string
5998  * \param len the length of the string
5999  * \param error set on failure.
6000  * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6001  */
6002 static MonoString *
6003 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6004 {
6005         MONO_REQ_GC_UNSAFE_MODE;
6006
6007         MonoString *s;
6008         mono_unichar2 *utf16_output = NULL;
6009         gint32 utf16_len = 0;
6010         GError *gerror = NULL;
6011         glong items_written;
6012         
6013         error_init (error);
6014         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6015         
6016         if (gerror)
6017                 g_error_free (gerror);
6018
6019         while (utf16_output [utf16_len]) utf16_len++;
6020         
6021         s = mono_string_new_size_checked (domain, utf16_len, error);
6022         return_val_if_nok (error, NULL);
6023
6024         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6025
6026         g_free (utf16_output);
6027         
6028         return s;
6029 }
6030
6031 /**
6032  * mono_string_new_utf32:
6033  * \param text a pointer to a UTF-32 string
6034  * \param len the length of the string
6035  * \returns A newly created string object which contains \p text.
6036  */
6037 MonoString *
6038 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6039 {
6040         MonoError error;
6041         MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6042         mono_error_cleanup (&error);
6043         return result;
6044 }
6045
6046 /**
6047  * mono_string_new_size:
6048  * \param text a pointer to a UTF-16 string
6049  * \param len the length of the string
6050  * \returns A newly created string object of \p len
6051  */
6052 MonoString *
6053 mono_string_new_size (MonoDomain *domain, gint32 len)
6054 {
6055         MonoError error;
6056         MonoString *str = mono_string_new_size_checked (domain, len, &error);
6057         mono_error_cleanup (&error);
6058
6059         return str;
6060 }
6061
6062 MonoString *
6063 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6064 {
6065         MONO_REQ_GC_UNSAFE_MODE;
6066
6067         MonoString *s;
6068         MonoVTable *vtable;
6069         size_t size;
6070
6071         error_init (error);
6072
6073         /* check for overflow */
6074         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6075                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6076                 return NULL;
6077         }
6078
6079         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6080         g_assert (size > 0);
6081
6082         vtable = mono_class_vtable (domain, mono_defaults.string_class);
6083         g_assert (vtable);
6084
6085         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6086
6087         if (G_UNLIKELY (!s)) {
6088                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6089                 return NULL;
6090         }
6091
6092         return s;
6093 }
6094
6095 /**
6096  * mono_string_new_len:
6097  * \param text a pointer to an utf8 string
6098  * \param length number of bytes in \p text to consider
6099  * \returns A newly created string object which contains \p text.
6100  */
6101 MonoString*
6102 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6103 {
6104         MONO_REQ_GC_UNSAFE_MODE;
6105
6106         MonoError error;
6107         MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6108         mono_error_cleanup (&error);
6109         return result;
6110 }
6111
6112 /**
6113  * mono_string_new_len_checked:
6114  * \param text a pointer to an utf8 string
6115  * \param length number of bytes in \p text to consider
6116  * \param error set on error
6117  * \returns A newly created string object which contains \p text. On
6118  * failure returns NULL and sets \p error.
6119  */
6120 MonoString*
6121 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6122 {
6123         MONO_REQ_GC_UNSAFE_MODE;
6124
6125         error_init (error);
6126
6127         GError *eg_error = NULL;
6128         MonoString *o = NULL;
6129         guint16 *ut = NULL;
6130         glong items_written;
6131
6132         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6133
6134         if (!eg_error)
6135                 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6136         else 
6137                 g_error_free (eg_error);
6138
6139         g_free (ut);
6140
6141         return o;
6142 }
6143
6144 /**
6145  * mono_string_new:
6146  * \param text a pointer to a UTF-8 string
6147  * \deprecated Use \c mono_string_new_checked in new code.
6148  * This function asserts if it cannot allocate a new string.
6149  * \returns A newly created string object which contains \p text.
6150  */
6151 MonoString*
6152 mono_string_new (MonoDomain *domain, const char *text)
6153 {
6154         MonoError error;
6155         MonoString *res = NULL;
6156         res = mono_string_new_checked (domain, text, &error);
6157         mono_error_assert_ok (&error);
6158         return res;
6159 }
6160
6161 /**
6162  * mono_string_new_checked:
6163  * \param text a pointer to an utf8 string
6164  * \param merror set on error
6165  * \returns A newly created string object which contains \p text.
6166  * On error returns NULL and sets \p merror.
6167  */
6168 MonoString*
6169 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6170 {
6171         MONO_REQ_GC_UNSAFE_MODE;
6172
6173     GError *eg_error = NULL;
6174     MonoString *o = NULL;
6175     guint16 *ut;
6176     glong items_written;
6177     int l;
6178
6179     error_init (error);
6180
6181     l = strlen (text);
6182    
6183     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6184
6185     if (!eg_error)
6186             o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6187     else
6188         g_error_free (eg_error);
6189
6190     g_free (ut);
6191     
6192 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6193 #if 0
6194         gunichar2 *str;
6195         const gchar *end;
6196         int len;
6197         MonoString *o = NULL;
6198
6199         if (!g_utf8_validate (text, -1, &end)) {
6200                 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6201                 goto leave;
6202         }
6203
6204         len = g_utf8_strlen (text, -1);
6205         o = mono_string_new_size_checked (domain, len, error);
6206         if (!o)
6207                 goto leave;
6208         str = mono_string_chars (o);
6209
6210         while (text < end) {
6211                 *str++ = g_utf8_get_char (text);
6212                 text = g_utf8_next_char (text);
6213         }
6214
6215 leave:
6216 #endif
6217         return o;
6218 }
6219
6220 /**
6221  * mono_string_new_wrapper:
6222  * \param text pointer to UTF-8 characters.
6223  * Helper function to create a string object from \p text in the current domain.
6224  */
6225 MonoString*
6226 mono_string_new_wrapper (const char *text)
6227 {
6228         MONO_REQ_GC_UNSAFE_MODE;
6229
6230         MonoDomain *domain = mono_domain_get ();
6231
6232         if (text)
6233                 return mono_string_new (domain, text);
6234
6235         return NULL;
6236 }
6237
6238 /**
6239  * mono_value_box:
6240  * \param class the class of the value
6241  * \param value a pointer to the unboxed data
6242  * \returns A newly created object which contains \p value.
6243  */
6244 MonoObject *
6245 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6246 {
6247         MonoError error;
6248         MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6249         mono_error_cleanup (&error);
6250         return result;
6251 }
6252
6253 /**
6254  * mono_value_box_checked:
6255  * \param domain the domain of the new object
6256  * \param class the class of the value
6257  * \param value a pointer to the unboxed data
6258  * \param error set on error
6259  * \returns A newly created object which contains \p value. On failure
6260  * returns NULL and sets \p error.
6261  */
6262 MonoObject *
6263 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6264 {
6265         MONO_REQ_GC_UNSAFE_MODE;
6266         MonoObject *res;
6267         int size;
6268         MonoVTable *vtable;
6269
6270         error_init (error);
6271
6272         g_assert (klass->valuetype);
6273         if (mono_class_is_nullable (klass))
6274                 return mono_nullable_box ((guint8 *)value, klass, error);
6275
6276         vtable = mono_class_vtable (domain, klass);
6277         if (!vtable)
6278                 return NULL;
6279         size = mono_class_instance_size (klass);
6280         res = mono_object_new_alloc_specific_checked (vtable, error);
6281         return_val_if_nok (error, NULL);
6282
6283         size = size - sizeof (MonoObject);
6284
6285 #ifdef HAVE_SGEN_GC
6286         g_assert (size == mono_class_value_size (klass, NULL));
6287         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6288 #else
6289 #if NO_UNALIGNED_ACCESS
6290         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6291 #else
6292         switch (size) {
6293         case 1:
6294                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6295                 break;
6296         case 2:
6297                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6298                 break;
6299         case 4:
6300                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6301                 break;
6302         case 8:
6303                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6304                 break;
6305         default:
6306                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6307         }
6308 #endif
6309 #endif
6310         if (klass->has_finalize) {
6311                 mono_object_register_finalizer (res);
6312                 return_val_if_nok (error, NULL);
6313         }
6314         return res;
6315 }
6316
6317 /**
6318  * mono_value_copy:
6319  * \param dest destination pointer
6320  * \param src source pointer
6321  * \param klass a valuetype class
6322  * Copy a valuetype from \p src to \p dest. This function must be used
6323  * when \p klass contains reference fields.
6324  */
6325 void
6326 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6327 {
6328         MONO_REQ_GC_UNSAFE_MODE;
6329
6330         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6331 }
6332
6333 /**
6334  * mono_value_copy_array:
6335  * \param dest destination array
6336  * \param dest_idx index in the \p dest array
6337  * \param src source pointer
6338  * \param count number of items
6339  * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx. 
6340  * This function must be used when \p klass contains references fields.
6341  * Overlap is handled.
6342  */
6343 void
6344 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6345 {
6346         MONO_REQ_GC_UNSAFE_MODE;
6347
6348         int size = mono_array_element_size (dest->obj.vtable->klass);
6349         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6350         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6351         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6352 }
6353
6354 /**
6355  * mono_object_get_domain:
6356  * \param obj object to query
6357  * \returns the \c MonoDomain where the object is hosted
6358  */
6359 MonoDomain*
6360 mono_object_get_domain (MonoObject *obj)
6361 {
6362         MONO_REQ_GC_UNSAFE_MODE;
6363
6364         return mono_object_domain (obj);
6365 }
6366
6367 /**
6368  * mono_object_get_class:
6369  * \param obj object to query
6370  * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6371  * \returns the \c MonoClass of the object.
6372  */
6373 MonoClass*
6374 mono_object_get_class (MonoObject *obj)
6375 {
6376         MONO_REQ_GC_UNSAFE_MODE;
6377
6378         return mono_object_class (obj);
6379 }
6380 /**
6381  * mono_object_get_size:
6382  * \param o object to query
6383  * \returns the size, in bytes, of \p o
6384  */
6385 guint
6386 mono_object_get_size (MonoObject* o)
6387 {
6388         MONO_REQ_GC_UNSAFE_MODE;
6389
6390         MonoClass* klass = mono_object_class (o);
6391         if (klass == mono_defaults.string_class) {
6392                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6393         } else if (o->vtable->rank) {
6394                 MonoArray *array = (MonoArray*)o;
6395                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6396                 if (array->bounds) {
6397                         size += 3;
6398                         size &= ~3;
6399                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
6400                 }
6401                 return size;
6402         } else {
6403                 return mono_class_instance_size (klass);
6404         }
6405 }
6406
6407 /**
6408  * mono_object_unbox:
6409  * \param obj object to unbox
6410  * \returns a pointer to the start of the valuetype boxed in this
6411  * object.
6412  *
6413  * This method will assert if the object passed is not a valuetype.
6414  */
6415 gpointer
6416 mono_object_unbox (MonoObject *obj)
6417 {
6418         MONO_REQ_GC_UNSAFE_MODE;
6419
6420         /* add assert for valuetypes? */
6421         g_assert (obj->vtable->klass->valuetype);
6422         return ((char*)obj) + sizeof (MonoObject);
6423 }
6424
6425 /**
6426  * mono_object_isinst:
6427  * \param obj an object
6428  * \param klass a pointer to a class 
6429  * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6430  */
6431 MonoObject *
6432 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6433 {
6434         MONO_REQ_GC_UNSAFE_MODE;
6435
6436         HANDLE_FUNCTION_ENTER ();
6437         MONO_HANDLE_DCL (MonoObject, obj);
6438         MonoError error;
6439         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6440         mono_error_cleanup (&error);
6441         HANDLE_FUNCTION_RETURN_OBJ (result);
6442 }
6443         
6444
6445 /**
6446  * mono_object_isinst_checked:
6447  * \param obj an object
6448  * \param klass a pointer to a class 
6449  * \param error set on error
6450  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6451  * On failure returns NULL and sets \p error.
6452  */
6453 MonoObject *
6454 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6455 {
6456         MONO_REQ_GC_UNSAFE_MODE;
6457
6458         HANDLE_FUNCTION_ENTER ();
6459         error_init (error);
6460         MONO_HANDLE_DCL (MonoObject, obj);
6461         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6462         HANDLE_FUNCTION_RETURN_OBJ (result);
6463 }
6464
6465 /**
6466  * mono_object_handle_isinst:
6467  * \param obj an object
6468  * \param klass a pointer to a class 
6469  * \param error set on error
6470  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6471  * On failure returns NULL and sets \p error.
6472  */
6473 MonoObjectHandle
6474 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6475 {
6476         error_init (error);
6477         
6478         if (!klass->inited)
6479                 mono_class_init (klass);
6480
6481         if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6482                 return mono_object_handle_isinst_mbyref (obj, klass, error);
6483         }
6484
6485         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6486
6487         if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6488                 MONO_HANDLE_ASSIGN (result, obj);
6489         return result;
6490 }
6491
6492 /**
6493  * mono_object_isinst_mbyref:
6494  */
6495 MonoObject *
6496 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6497 {
6498         MONO_REQ_GC_UNSAFE_MODE;
6499
6500         HANDLE_FUNCTION_ENTER ();
6501         MonoError error;
6502         MONO_HANDLE_DCL (MonoObject, obj);
6503         MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6504         mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6505         HANDLE_FUNCTION_RETURN_OBJ (result);
6506 }
6507
6508 MonoObjectHandle
6509 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6510 {
6511         error_init (error);
6512
6513         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6514
6515         if (MONO_HANDLE_IS_NULL (obj))
6516                 goto leave;
6517
6518         MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6519         
6520         if (mono_class_is_interface (klass)) {
6521                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6522                         MONO_HANDLE_ASSIGN (result, obj);
6523                         goto leave;
6524                 }
6525
6526                 /* casting an array one of the invariant interfaces that must act as such */
6527                 if (klass->is_array_special_interface) {
6528                         if (mono_class_is_assignable_from (klass, vt->klass)) {
6529                                 MONO_HANDLE_ASSIGN (result, obj);
6530                                 goto leave;
6531                         }
6532                 }
6533
6534                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6535                 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6536                         MONO_HANDLE_ASSIGN (result, obj);
6537                         goto leave;
6538                 }
6539         } else {
6540                 MonoClass *oklass = vt->klass;
6541                 if (mono_class_is_transparent_proxy (oklass)){
6542                         MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6543                         oklass = remote_class->proxy_class;
6544                 }
6545
6546                 mono_class_setup_supertypes (klass);    
6547                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6548                         MONO_HANDLE_ASSIGN (result, obj);
6549                         goto leave;
6550                 }
6551         }
6552 #ifndef DISABLE_REMOTING
6553         if (mono_class_is_transparent_proxy (vt->klass)) 
6554         {
6555                 MonoBoolean custom_type_info =  MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6556                 if (!custom_type_info)
6557                         goto leave;
6558                 MonoDomain *domain = mono_domain_get ();
6559                 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6560                 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6561                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6562                 MonoMethod *im = NULL;
6563                 gpointer pa [2];
6564
6565                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6566                 if (!im) {
6567                         mono_error_set_not_supported (error, "Linked away.");
6568                         goto leave;
6569                 }
6570                 im = mono_object_handle_get_virtual_method (rp, im, error);
6571                 if (!is_ok (error))
6572                         goto leave;
6573                 g_assert (im);
6574         
6575                 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6576                 if (!is_ok (error))
6577                         goto leave;
6578
6579                 pa [0] = MONO_HANDLE_RAW (reftype);
6580                 pa [1] = MONO_HANDLE_RAW (obj);
6581                 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6582                 if (!is_ok (error))
6583                         goto leave;
6584
6585                 if (*(MonoBoolean *) mono_object_unbox(res)) {
6586                         /* Update the vtable of the remote type, so it can safely cast to this new type */
6587                         mono_upgrade_remote_class (domain, obj, klass, error);
6588                         if (!is_ok (error))
6589                                 goto leave;
6590                         MONO_HANDLE_ASSIGN (result, obj);
6591                 }
6592         }
6593 #endif /* DISABLE_REMOTING */
6594 leave:
6595         return result;
6596 }
6597
6598 /**
6599  * mono_object_castclass_mbyref:
6600  * \param obj an object
6601  * \param klass a pointer to a class 
6602  * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6603  */
6604 MonoObject *
6605 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6606 {
6607         MONO_REQ_GC_UNSAFE_MODE;
6608         HANDLE_FUNCTION_ENTER ();
6609         MonoError error;
6610         MONO_HANDLE_DCL (MonoObject, obj);
6611         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6612         if (MONO_HANDLE_IS_NULL (obj))
6613                 goto leave;
6614         MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6615         mono_error_cleanup (&error);
6616 leave:
6617         HANDLE_FUNCTION_RETURN_OBJ (result);
6618 }
6619
6620 typedef struct {
6621         MonoDomain *orig_domain;
6622         MonoString *ins;
6623         MonoString *res;
6624 } LDStrInfo;
6625
6626 static void
6627 str_lookup (MonoDomain *domain, gpointer user_data)
6628 {
6629         MONO_REQ_GC_UNSAFE_MODE;
6630
6631         LDStrInfo *info = (LDStrInfo *)user_data;
6632         if (info->res || domain == info->orig_domain)
6633                 return;
6634         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6635 }
6636
6637 static MonoString*
6638 mono_string_get_pinned (MonoString *str, MonoError *error)
6639 {
6640         MONO_REQ_GC_UNSAFE_MODE;
6641
6642         error_init (error);
6643
6644         /* We only need to make a pinned version of a string if this is a moving GC */
6645         if (!mono_gc_is_moving ())
6646                 return str;
6647         int size;
6648         MonoString *news;
6649         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6650         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6651         if (news) {
6652                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6653                 news->length = mono_string_length (str);
6654         } else {
6655                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6656         }
6657         return news;
6658 }
6659
6660 static MonoString*
6661 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6662 {
6663         MONO_REQ_GC_UNSAFE_MODE;
6664
6665         MonoGHashTable *ldstr_table;
6666         MonoString *s, *res;
6667         MonoDomain *domain;
6668         
6669         error_init (error);
6670
6671         domain = ((MonoObject *)str)->vtable->domain;
6672         ldstr_table = domain->ldstr_table;
6673         ldstr_lock ();
6674         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6675         if (res) {
6676                 ldstr_unlock ();
6677                 return res;
6678         }
6679         if (insert) {
6680                 /* Allocate outside the lock */
6681                 ldstr_unlock ();
6682                 s = mono_string_get_pinned (str, error);
6683                 return_val_if_nok (error, NULL);
6684                 if (s) {
6685                         ldstr_lock ();
6686                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6687                         if (res) {
6688                                 ldstr_unlock ();
6689                                 return res;
6690                         }
6691                         mono_g_hash_table_insert (ldstr_table, s, s);
6692                         ldstr_unlock ();
6693                 }
6694                 return s;
6695         } else {
6696                 LDStrInfo ldstr_info;
6697                 ldstr_info.orig_domain = domain;
6698                 ldstr_info.ins = str;
6699                 ldstr_info.res = NULL;
6700
6701                 mono_domain_foreach (str_lookup, &ldstr_info);
6702                 if (ldstr_info.res) {
6703                         /* 
6704                          * the string was already interned in some other domain:
6705                          * intern it in the current one as well.
6706                          */
6707                         mono_g_hash_table_insert (ldstr_table, str, str);
6708                         ldstr_unlock ();
6709                         return str;
6710                 }
6711         }
6712         ldstr_unlock ();
6713         return NULL;
6714 }
6715
6716 /**
6717  * mono_string_is_interned:
6718  * \param o String to probe
6719  * \returns Whether the string has been interned.
6720  */
6721 MonoString*
6722 mono_string_is_interned (MonoString *o)
6723 {
6724         MonoError error;
6725         MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6726         /* This function does not fail. */
6727         mono_error_assert_ok (&error);
6728         return result;
6729 }
6730
6731 /**
6732  * mono_string_intern:
6733  * \param o String to intern
6734  * Interns the string passed.  
6735  * \returns The interned string.
6736  */
6737 MonoString*
6738 mono_string_intern (MonoString *str)
6739 {
6740         MonoError error;
6741         MonoString *result = mono_string_intern_checked (str, &error);
6742         mono_error_assert_ok (&error);
6743         return result;
6744 }
6745
6746 /**
6747  * mono_string_intern_checked:
6748  * \param o String to intern
6749  * \param error set on error.
6750  * Interns the string passed.
6751  * \returns The interned string.  On failure returns NULL and sets \p error
6752  */
6753 MonoString*
6754 mono_string_intern_checked (MonoString *str, MonoError *error)
6755 {
6756         MONO_REQ_GC_UNSAFE_MODE;
6757
6758         error_init (error);
6759
6760         return mono_string_is_interned_lookup (str, TRUE, error);
6761 }
6762
6763 /**
6764  * mono_ldstr:
6765  * \param domain the domain where the string will be used.
6766  * \param image a metadata context
6767  * \param idx index into the user string table.
6768  * Implementation for the \c ldstr opcode.
6769  * \returns a loaded string from the \p image / \p idx combination.
6770  */
6771 MonoString*
6772 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6773 {
6774         MonoError error;
6775         MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6776         mono_error_cleanup (&error);
6777         return result;
6778 }
6779
6780 /**
6781  * mono_ldstr_checked:
6782  * \param domain the domain where the string will be used.
6783  * \param image a metadata context
6784  * \param idx index into the user string table.
6785  * \param error set on error.
6786  * Implementation for the \c ldstr opcode.
6787  * \returns A loaded string from the \p image / \p idx combination.
6788  * On failure returns NULL and sets \p error.
6789  */
6790 MonoString*
6791 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6792 {
6793         MONO_REQ_GC_UNSAFE_MODE;
6794         error_init (error);
6795
6796         if (image->dynamic) {
6797                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6798                 return str;
6799         } else {
6800                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6801                         return NULL; /*FIXME we should probably be raising an exception here*/
6802                 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6803                 return str;
6804         }
6805 }
6806
6807 /**
6808  * mono_ldstr_metadata_sig
6809  * \param domain the domain for the string
6810  * \param sig the signature of a metadata string
6811  * \param error set on error
6812  * \returns a \c MonoString for a string stored in the metadata. On
6813  * failure returns NULL and sets \p error.
6814  */
6815 static MonoString*
6816 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6817 {
6818         MONO_REQ_GC_UNSAFE_MODE;
6819
6820         error_init (error);
6821         const char *str = sig;
6822         MonoString *o, *interned;
6823         size_t len2;
6824
6825         len2 = mono_metadata_decode_blob_size (str, &str);
6826         len2 >>= 1;
6827
6828         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6829         return_val_if_nok (error, NULL);
6830 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6831         {
6832                 int i;
6833                 guint16 *p2 = (guint16*)mono_string_chars (o);
6834                 for (i = 0; i < len2; ++i) {
6835                         *p2 = GUINT16_FROM_LE (*p2);
6836                         ++p2;
6837                 }
6838         }
6839 #endif
6840         ldstr_lock ();
6841         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6842         ldstr_unlock ();
6843         if (interned)
6844                 return interned; /* o will get garbage collected */
6845
6846         o = mono_string_get_pinned (o, error);
6847         if (o) {
6848                 ldstr_lock ();
6849                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6850                 if (!interned) {
6851                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6852                         interned = o;
6853                 }
6854                 ldstr_unlock ();
6855         }
6856
6857         return interned;
6858 }
6859
6860 /*
6861  * mono_ldstr_utf8:
6862  *
6863  *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
6864  * of an object.
6865  */
6866 char*
6867 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6868 {
6869         const char *str;
6870         size_t len2;
6871         long written = 0;
6872         char *as;
6873         GError *gerror = NULL;
6874
6875         error_init (error);
6876
6877         if (!mono_verifier_verify_string_signature (image, idx, NULL))
6878                 return NULL; /*FIXME we should probably be raising an exception here*/
6879         str = mono_metadata_user_string (image, idx);
6880
6881         len2 = mono_metadata_decode_blob_size (str, &str);
6882         len2 >>= 1;
6883
6884         as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6885         if (gerror) {
6886                 mono_error_set_argument (error, "string", "%s", gerror->message);
6887                 g_error_free (gerror);
6888                 return NULL;
6889         }
6890         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6891         if (len2 > written) {
6892                 /* allocate the total length and copy the part of the string that has been converted */
6893                 char *as2 = (char *)g_malloc0 (len2);
6894                 memcpy (as2, as, written);
6895                 g_free (as);
6896                 as = as2;
6897         }
6898
6899         return as;
6900 }
6901
6902 /**
6903  * mono_string_to_utf8:
6904  * \param s a \c System.String
6905  * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6906  * \returns the UTF-8 representation for \p s.
6907  * The resulting buffer needs to be freed with \c mono_free().
6908  */
6909 char *
6910 mono_string_to_utf8 (MonoString *s)
6911 {
6912         MONO_REQ_GC_UNSAFE_MODE;
6913
6914         MonoError error;
6915         char *result = mono_string_to_utf8_checked (s, &error);
6916         
6917         if (!is_ok (&error)) {
6918                 mono_error_cleanup (&error);
6919                 return NULL;
6920         }
6921         return result;
6922 }
6923
6924 /**
6925  * mono_string_to_utf8_checked:
6926  * \param s a \c System.String
6927  * \param error a \c MonoError.
6928  * Converts a \c MonoString to its UTF-8 representation. May fail; check 
6929  * \p error to determine whether the conversion was successful.
6930  * The resulting buffer should be freed with \c mono_free().
6931  */
6932 char *
6933 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6934 {
6935         MONO_REQ_GC_UNSAFE_MODE;
6936
6937         long written = 0;
6938         char *as;
6939         GError *gerror = NULL;
6940
6941         error_init (error);
6942
6943         if (s == NULL)
6944                 return NULL;
6945
6946         if (!s->length)
6947                 return g_strdup ("");
6948
6949         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6950         if (gerror) {
6951                 mono_error_set_argument (error, "string", "%s", gerror->message);
6952                 g_error_free (gerror);
6953                 return NULL;
6954         }
6955         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6956         if (s->length > written) {
6957                 /* allocate the total length and copy the part of the string that has been converted */
6958                 char *as2 = (char *)g_malloc0 (s->length);
6959                 memcpy (as2, as, written);
6960                 g_free (as);
6961                 as = as2;
6962         }
6963
6964         return as;
6965 }
6966
6967 char *
6968 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6969 {
6970         return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6971 }
6972
6973 /**
6974  * mono_string_to_utf8_ignore:
6975  * \param s a MonoString
6976  * Converts a \c MonoString to its UTF-8 representation. Will ignore
6977  * invalid surrogate pairs.
6978  * The resulting buffer should be freed with \c mono_free().
6979  */
6980 char *
6981 mono_string_to_utf8_ignore (MonoString *s)
6982 {
6983         MONO_REQ_GC_UNSAFE_MODE;
6984
6985         long written = 0;
6986         char *as;
6987
6988         if (s == NULL)
6989                 return NULL;
6990
6991         if (!s->length)
6992                 return g_strdup ("");
6993
6994         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6995
6996         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6997         if (s->length > written) {
6998                 /* allocate the total length and copy the part of the string that has been converted */
6999                 char *as2 = (char *)g_malloc0 (s->length);
7000                 memcpy (as2, as, written);
7001                 g_free (as);
7002                 as = as2;
7003         }
7004
7005         return as;
7006 }
7007
7008 /**
7009  * mono_string_to_utf8_image_ignore:
7010  * \param s a \c System.String
7011  * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7012  */
7013 char *
7014 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7015 {
7016         MONO_REQ_GC_UNSAFE_MODE;
7017
7018         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7019 }
7020
7021 /**
7022  * mono_string_to_utf8_mp_ignore:
7023  * \param s a \c System.String
7024  * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7025  */
7026 char *
7027 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7028 {
7029         MONO_REQ_GC_UNSAFE_MODE;
7030
7031         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7032 }
7033
7034
7035 /**
7036  * mono_string_to_utf16:
7037  * \param s a \c MonoString
7038  * \returns a null-terminated array of the UTF-16 chars
7039  * contained in \p s. The result must be freed with \c g_free().
7040  * This is a temporary helper until our string implementation
7041  * is reworked to always include the null-terminating char.
7042  */
7043 mono_unichar2*
7044 mono_string_to_utf16 (MonoString *s)
7045 {
7046         MONO_REQ_GC_UNSAFE_MODE;
7047
7048         char *as;
7049
7050         if (s == NULL)
7051                 return NULL;
7052
7053         as = (char *)g_malloc ((s->length * 2) + 2);
7054         as [(s->length * 2)] = '\0';
7055         as [(s->length * 2) + 1] = '\0';
7056
7057         if (!s->length) {
7058                 return (gunichar2 *)(as);
7059         }
7060         
7061         memcpy (as, mono_string_chars(s), s->length * 2);
7062         return (gunichar2 *)(as);
7063 }
7064
7065 /**
7066  * mono_string_to_utf32:
7067  * \param s a \c MonoString
7068  * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7069  * contained in \p s. The result must be freed with \c g_free().
7070  */
7071 mono_unichar4*
7072 mono_string_to_utf32 (MonoString *s)
7073 {
7074         MONO_REQ_GC_UNSAFE_MODE;
7075
7076         mono_unichar4 *utf32_output = NULL; 
7077         GError *error = NULL;
7078         glong items_written;
7079         
7080         if (s == NULL)
7081                 return NULL;
7082                 
7083         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7084         
7085         if (error)
7086                 g_error_free (error);
7087
7088         return utf32_output;
7089 }
7090
7091 /**
7092  * mono_string_from_utf16:
7093  * \param data the UTF-16 string (LPWSTR) to convert
7094  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7095  * \returns a \c MonoString.
7096  */
7097 MonoString *
7098 mono_string_from_utf16 (gunichar2 *data)
7099 {
7100         MonoError error;
7101         MonoString *result = mono_string_from_utf16_checked (data, &error);
7102         mono_error_cleanup (&error);
7103         return result;
7104 }
7105
7106 /**
7107  * mono_string_from_utf16_checked:
7108  * \param data the UTF-16 string (LPWSTR) to convert
7109  * \param error set on error
7110  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7111  * \returns a \c MonoString. On failure sets \p error and returns NULL.
7112  */
7113 MonoString *
7114 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7115 {
7116
7117         MONO_REQ_GC_UNSAFE_MODE;
7118
7119         error_init (error);
7120         MonoDomain *domain = mono_domain_get ();
7121         int len = 0;
7122
7123         if (!data)
7124                 return NULL;
7125
7126         while (data [len]) len++;
7127
7128         return mono_string_new_utf16_checked (domain, data, len, error);
7129 }
7130
7131 /**
7132  * mono_string_from_utf32:
7133  * \param data the UTF-32 string (LPWSTR) to convert
7134  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7135  * \returns a \c MonoString.
7136  */
7137 MonoString *
7138 mono_string_from_utf32 (mono_unichar4 *data)
7139 {
7140         MonoError error;
7141         MonoString *result = mono_string_from_utf32_checked (data, &error);
7142         mono_error_cleanup (&error);
7143         return result;
7144 }
7145
7146 /**
7147  * mono_string_from_utf32_checked:
7148  * \param data the UTF-32 string (LPWSTR) to convert
7149  * \param error set on error
7150  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7151  * \returns a \c MonoString. On failure returns NULL and sets \p error.
7152  */
7153 MonoString *
7154 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7155 {
7156         MONO_REQ_GC_UNSAFE_MODE;
7157
7158         error_init (error);
7159         MonoString* result = NULL;
7160         mono_unichar2 *utf16_output = NULL;
7161         GError *gerror = NULL;
7162         glong items_written;
7163         int len = 0;
7164
7165         if (!data)
7166                 return NULL;
7167
7168         while (data [len]) len++;
7169
7170         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7171
7172         if (gerror)
7173                 g_error_free (gerror);
7174
7175         result = mono_string_from_utf16_checked (utf16_output, error);
7176         g_free (utf16_output);
7177         return result;
7178 }
7179
7180 static char *
7181 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7182 {
7183         MONO_REQ_GC_UNSAFE_MODE;
7184
7185         char *r;
7186         char *mp_s;
7187         int len;
7188
7189         if (ignore_error) {
7190                 r = mono_string_to_utf8_ignore (s);
7191         } else {
7192                 r = mono_string_to_utf8_checked (s, error);
7193                 if (!mono_error_ok (error))
7194                         return NULL;
7195         }
7196
7197         if (!mp && !image)
7198                 return r;
7199
7200         len = strlen (r) + 1;
7201         if (mp)
7202                 mp_s = (char *)mono_mempool_alloc (mp, len);
7203         else
7204                 mp_s = (char *)mono_image_alloc (image, len);
7205
7206         memcpy (mp_s, r, len);
7207
7208         g_free (r);
7209
7210         return mp_s;
7211 }
7212
7213 /**
7214  * mono_string_to_utf8_image:
7215  * \param s a \c System.String
7216  * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7217  */
7218 char *
7219 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7220 {
7221         MONO_REQ_GC_UNSAFE_MODE;
7222
7223         return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7224 }
7225
7226 /**
7227  * mono_string_to_utf8_mp:
7228  * \param s a \c System.String
7229  * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7230  */
7231 char *
7232 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7233 {
7234         MONO_REQ_GC_UNSAFE_MODE;
7235
7236         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7237 }
7238
7239
7240 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7241
7242 void
7243 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7244 {
7245         eh_callbacks = *cbs;
7246 }
7247
7248 MonoRuntimeExceptionHandlingCallbacks *
7249 mono_get_eh_callbacks (void)
7250 {
7251         return &eh_callbacks;
7252 }
7253
7254 /**
7255  * mono_raise_exception:
7256  * \param ex exception object
7257  * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7258  */
7259 void
7260 mono_raise_exception (MonoException *ex) 
7261 {
7262         MONO_REQ_GC_UNSAFE_MODE;
7263
7264         /*
7265          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7266          * that will cause gcc to omit the function epilog, causing problems when
7267          * the JIT tries to walk the stack, since the return address on the stack
7268          * will point into the next function in the executable, not this one.
7269          */     
7270         eh_callbacks.mono_raise_exception (ex);
7271 }
7272
7273 void
7274 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
7275 {
7276         MONO_REQ_GC_UNSAFE_MODE;
7277
7278         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7279 }
7280
7281 /**
7282  * mono_wait_handle_new:
7283  * \param domain Domain where the object will be created
7284  * \param handle Handle for the wait handle
7285  * \param error set on error.
7286  * \returns A new \c MonoWaitHandle created in the given domain for the
7287  * given handle.  On failure returns NULL and sets \p error.
7288  */
7289 MonoWaitHandle *
7290 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7291 {
7292         MONO_REQ_GC_UNSAFE_MODE;
7293
7294         MonoWaitHandle *res;
7295         gpointer params [1];
7296         static MonoMethod *handle_set;
7297
7298         error_init (error);
7299         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7300         return_val_if_nok (error, NULL);
7301
7302         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
7303         if (!handle_set)
7304                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7305
7306         params [0] = &handle;
7307
7308         mono_runtime_invoke_checked (handle_set, res, params, error);
7309         return res;
7310 }
7311
7312 HANDLE
7313 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7314 {
7315         MONO_REQ_GC_UNSAFE_MODE;
7316
7317         static MonoClassField *f_safe_handle = NULL;
7318         MonoSafeHandle *sh;
7319
7320         if (!f_safe_handle) {
7321                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7322                 g_assert (f_safe_handle);
7323         }
7324
7325         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7326         return sh->handle;
7327 }
7328
7329
7330 static MonoObject*
7331 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7332 {
7333         MONO_REQ_GC_UNSAFE_MODE;
7334
7335         RuntimeInvokeFunction runtime_invoke;
7336
7337         error_init (error);
7338
7339         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7340                 MonoMethod *method = mono_get_context_capture_method ();
7341                 MonoMethod *wrapper;
7342                 if (!method)
7343                         return NULL;
7344                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7345                 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7346                 return_val_if_nok (error, NULL);
7347                 domain->capture_context_method = mono_compile_method_checked (method, error);
7348                 return_val_if_nok (error, NULL);
7349         }
7350
7351         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7352
7353         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7354 }
7355 /**
7356  * mono_async_result_new:
7357  * \param domain domain where the object will be created.
7358  * \param handle wait handle.
7359  * \param state state to pass to AsyncResult
7360  * \param data C closure data.
7361  * \param error set on error.
7362  * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7363  * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7364  * On failure returns NULL and sets \p error.
7365  */
7366 MonoAsyncResult *
7367 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7368 {
7369         MONO_REQ_GC_UNSAFE_MODE;
7370
7371         error_init (error);
7372         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7373         return_val_if_nok (error, NULL);
7374         MonoObject *context = mono_runtime_capture_context (domain, error);
7375         return_val_if_nok (error, NULL);
7376         /* we must capture the execution context from the original thread */
7377         if (context) {
7378                 MONO_OBJECT_SETREF (res, execution_context, context);
7379                 /* note: result may be null if the flow is suppressed */
7380         }
7381
7382         res->data = (void **)data;
7383         MONO_OBJECT_SETREF (res, object_data, object_data);
7384         MONO_OBJECT_SETREF (res, async_state, state);
7385         MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7386         return_val_if_nok (error, NULL);
7387         if (handle != NULL)
7388                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7389
7390         res->sync_completed = FALSE;
7391         res->completed = FALSE;
7392
7393         return res;
7394 }
7395
7396 MonoObject *
7397 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7398 {
7399         MONO_REQ_GC_UNSAFE_MODE;
7400
7401         MonoError error;
7402         MonoAsyncCall *ac;
7403         MonoObject *res;
7404
7405         g_assert (ares);
7406         g_assert (ares->async_delegate);
7407
7408         ac = (MonoAsyncCall*) ares->object_data;
7409         if (!ac) {
7410                 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7411                 if (mono_error_set_pending_exception (&error))
7412                         return NULL;
7413         } else {
7414                 gpointer wait_event = NULL;
7415
7416                 ac->msg->exc = NULL;
7417
7418                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7419
7420                 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7421                 mono_threads_begin_abort_protected_block ();
7422
7423                 if (!ac->msg->exc) {
7424                         MonoException *ex = mono_error_convert_to_exception (&error);
7425                         ac->msg->exc = (MonoObject *)ex;
7426                 } else {
7427                         mono_error_cleanup (&error);
7428                 }
7429
7430                 MONO_OBJECT_SETREF (ac, res, res);
7431
7432                 mono_monitor_enter ((MonoObject*) ares);
7433                 ares->completed = 1;
7434                 if (ares->handle)
7435                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7436                 mono_monitor_exit ((MonoObject*) ares);
7437
7438                 if (wait_event != NULL)
7439                         mono_w32event_set (wait_event);
7440
7441                 error_init (&error); //the else branch would leave it in an undefined state
7442                 if (ac->cb_method)
7443                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7444
7445                 mono_threads_end_abort_protected_block ();
7446
7447                 if (mono_error_set_pending_exception (&error))
7448                         return NULL;
7449         }
7450
7451         return res;
7452 }
7453
7454 gboolean
7455 mono_message_init (MonoDomain *domain,
7456                    MonoMethodMessage *this_obj, 
7457                    MonoReflectionMethod *method,
7458                    MonoArray *out_args,
7459                    MonoError *error)
7460 {
7461         MONO_REQ_GC_UNSAFE_MODE;
7462
7463         static MonoMethod *init_message_method = NULL;
7464
7465         if (!init_message_method) {
7466                 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7467                 g_assert (init_message_method != NULL);
7468         }
7469
7470         error_init (error);
7471         /* FIXME set domain instead? */
7472         g_assert (domain == mono_domain_get ());
7473         
7474         gpointer args[2];
7475
7476         args[0] = method;
7477         args[1] = out_args;
7478
7479         mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7480         return is_ok (error);
7481 }
7482
7483 #ifndef DISABLE_REMOTING
7484 /**
7485  * mono_remoting_invoke:
7486  * \param real_proxy pointer to a \c RealProxy object
7487  * \param msg The \c MonoMethodMessage to execute
7488  * \param exc used to store exceptions
7489  * \param out_args used to store output arguments
7490  * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7491  * \c IMessage interface and it is not trivial to extract results from there. So
7492  * we call an helper method \c PrivateInvoke instead of calling
7493  * \c RealProxy::Invoke() directly.
7494  * \returns the result object.
7495  */
7496 MonoObject *
7497 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7498 {
7499         MONO_REQ_GC_UNSAFE_MODE;
7500
7501         MonoObject *o;
7502         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7503         gpointer pa [4];
7504
7505         g_assert (exc);
7506
7507         error_init (error);
7508
7509         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7510
7511         if (!im) {
7512                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7513                 if (!im) {
7514                         mono_error_set_not_supported (error, "Linked away.");
7515                         return NULL;
7516                 }
7517                 real_proxy->vtable->domain->private_invoke_method = im;
7518         }
7519
7520         pa [0] = real_proxy;
7521         pa [1] = msg;
7522         pa [2] = exc;
7523         pa [3] = out_args;
7524
7525         o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7526         return_val_if_nok (error, NULL);
7527
7528         return o;
7529 }
7530 #endif
7531
7532 MonoObject *
7533 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
7534                      MonoObject **exc, MonoArray **out_args, MonoError *error) 
7535 {
7536         MONO_REQ_GC_UNSAFE_MODE;
7537
7538         static MonoClass *object_array_klass;
7539         error_init (error);
7540
7541         MonoDomain *domain; 
7542         MonoMethod *method;
7543         MonoMethodSignature *sig;
7544         MonoArray *arr;
7545         int i, j, outarg_count = 0;
7546
7547 #ifndef DISABLE_REMOTING
7548         if (target && mono_object_is_transparent_proxy (target)) {
7549                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7550                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7551                         target = tp->rp->unwrapped_server;
7552                 } else {
7553                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7554                 }
7555         }
7556 #endif
7557
7558         domain = mono_domain_get (); 
7559         method = msg->method->method;
7560         sig = mono_method_signature (method);
7561
7562         for (i = 0; i < sig->param_count; i++) {
7563                 if (sig->params [i]->byref) 
7564                         outarg_count++;
7565         }
7566
7567         if (!object_array_klass) {
7568                 MonoClass *klass;
7569
7570                 klass = mono_array_class_get (mono_defaults.object_class, 1);
7571                 g_assert (klass);
7572
7573                 mono_memory_barrier ();
7574                 object_array_klass = klass;
7575         }
7576
7577         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7578         return_val_if_nok (error, NULL);
7579
7580         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7581         *exc = NULL;
7582
7583         MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7584         return_val_if_nok (error, NULL);
7585
7586         for (i = 0, j = 0; i < sig->param_count; i++) {
7587                 if (sig->params [i]->byref) {
7588                         MonoObject* arg;
7589                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7590                         mono_array_setref (*out_args, j, arg);
7591                         j++;
7592                 }
7593         }
7594
7595         return ret;
7596 }
7597
7598 /**
7599  * prepare_to_string_method:
7600  * @obj: The object
7601  * @target: Set to @obj or unboxed value if a valuetype
7602  *
7603  * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7604  */
7605 static MonoMethod *
7606 prepare_to_string_method (MonoObject *obj, void **target)
7607 {
7608         MONO_REQ_GC_UNSAFE_MODE;
7609
7610         static MonoMethod *to_string = NULL;
7611         MonoMethod *method;
7612         g_assert (target);
7613         g_assert (obj);
7614
7615         *target = obj;
7616
7617         if (!to_string)
7618                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7619
7620         method = mono_object_get_virtual_method (obj, to_string);
7621
7622         // Unbox value type if needed
7623         if (mono_class_is_valuetype (mono_method_get_class (method))) {
7624                 *target = mono_object_unbox (obj);
7625         }
7626         return method;
7627 }
7628
7629 /**
7630  * mono_object_to_string:
7631  * \param obj The object
7632  * \param exc Any exception thrown by \c ToString. May be NULL.
7633  * \returns the result of calling \c ToString on an object.
7634  */
7635 MonoString *
7636 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7637 {
7638         MonoError error;
7639         MonoString *s = NULL;
7640         void *target;
7641         MonoMethod *method = prepare_to_string_method (obj, &target);
7642         if (exc) {
7643                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7644                 if (*exc == NULL && !mono_error_ok (&error))
7645                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7646                 else
7647                         mono_error_cleanup (&error);
7648         } else {
7649                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7650                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7651         }
7652
7653         return s;
7654 }
7655
7656 /**
7657  * mono_object_to_string_checked:
7658  * \param obj The object
7659  * \param error Set on error.
7660  * \returns the result of calling \c ToString() on an object. If the
7661  * method cannot be invoked or if it raises an exception, sets \p error
7662  * and returns NULL.
7663  */
7664 MonoString *
7665 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7666 {
7667         error_init (error);
7668         void *target;
7669         MonoMethod *method = prepare_to_string_method (obj, &target);
7670         return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7671 }
7672
7673 /**
7674  * mono_object_try_to_string:
7675  * \param obj The object
7676  * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7677  * \param error Set if method cannot be invoked.
7678  * \returns the result of calling \c ToString() on an object. If the
7679  * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7680  * and returns NULL.
7681  */
7682 MonoString *
7683 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7684 {
7685         g_assert (exc);
7686         error_init (error);
7687         void *target;
7688         MonoMethod *method = prepare_to_string_method (obj, &target);
7689         return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7690 }
7691
7692
7693
7694 static char *
7695 get_native_backtrace (MonoException *exc_raw)
7696 {
7697         HANDLE_FUNCTION_ENTER ();
7698         MONO_HANDLE_DCL(MonoException, exc);
7699         char * trace = mono_exception_handle_get_native_backtrace (exc);
7700         HANDLE_FUNCTION_RETURN_VAL (trace);
7701 }
7702
7703 /**
7704  * mono_print_unhandled_exception:
7705  * \param exc The exception
7706  * Prints the unhandled exception.
7707  */
7708 void
7709 mono_print_unhandled_exception (MonoObject *exc)
7710 {
7711         MONO_REQ_GC_UNSAFE_MODE;
7712
7713         MonoString * str;
7714         char *message = (char*)"";
7715         gboolean free_message = FALSE;
7716         MonoError error;
7717
7718         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7719                 message = g_strdup ("OutOfMemoryException");
7720                 free_message = TRUE;
7721         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7722                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7723                 free_message = TRUE;
7724         } else {
7725                 
7726                 if (((MonoException*)exc)->native_trace_ips) {
7727                         message = get_native_backtrace ((MonoException*)exc);
7728                         free_message = TRUE;
7729                 } else {
7730                         MonoObject *other_exc = NULL;
7731                         str = mono_object_try_to_string (exc, &other_exc, &error);
7732                         if (other_exc == NULL && !is_ok (&error))
7733                                 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7734                         else
7735                                 mono_error_cleanup (&error);
7736                         if (other_exc) {
7737                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7738                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7739                                 
7740                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7741                                         original_backtrace, nested_backtrace);
7742
7743                                 g_free (original_backtrace);
7744                                 g_free (nested_backtrace);
7745                                 free_message = TRUE;
7746                         } else if (str) {
7747                                 message = mono_string_to_utf8_checked (str, &error);
7748                                 if (!mono_error_ok (&error)) {
7749                                         mono_error_cleanup (&error);
7750                                         message = (char *) "";
7751                                 } else {
7752                                         free_message = TRUE;
7753                                 }
7754                         }
7755                 }
7756         }
7757
7758         /*
7759          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7760          *         exc->vtable->klass->name, message);
7761          */
7762         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7763         
7764         if (free_message)
7765                 g_free (message);
7766 }
7767
7768 /**
7769  * mono_delegate_ctor_with_method:
7770  * \param this pointer to an uninitialized delegate object
7771  * \param target target object
7772  * \param addr pointer to native code
7773  * \param method method
7774  * \param error set on error.
7775  * Initialize a delegate and sets a specific method, not the one
7776  * associated with \p addr.  This is useful when sharing generic code.
7777  * In that case \p addr will most probably not be associated with the
7778  * correct instantiation of the method.
7779  * On failure returns FALSE and sets \p error.
7780  */
7781 gboolean
7782 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7783 {
7784         MONO_REQ_GC_UNSAFE_MODE;
7785
7786         error_init (error);
7787         MonoDelegate *delegate = (MonoDelegate *)this_obj;
7788
7789         g_assert (this_obj);
7790         g_assert (addr);
7791
7792         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7793
7794         if (method)
7795                 delegate->method = method;
7796
7797         mono_stats.delegate_creations++;
7798
7799 #ifndef DISABLE_REMOTING
7800         if (target && mono_object_is_transparent_proxy (target)) {
7801                 g_assert (method);
7802                 method = mono_marshal_get_remoting_invoke (method);
7803 #ifdef ENABLE_INTERPRETER
7804                 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7805 #endif
7806                 delegate->method_ptr = mono_compile_method_checked (method, error);
7807                 return_val_if_nok (error, FALSE);
7808                 MONO_OBJECT_SETREF (delegate, target, target);
7809         } else
7810 #endif
7811         {
7812                 delegate->method_ptr = addr;
7813                 MONO_OBJECT_SETREF (delegate, target, target);
7814         }
7815
7816         delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7817         if (callbacks.init_delegate)
7818                 callbacks.init_delegate (delegate);
7819         return TRUE;
7820 }
7821
7822 /**
7823  * mono_delegate_ctor:
7824  * \param this pointer to an uninitialized delegate object
7825  * \param target target object
7826  * \param addr pointer to native code
7827  * \param error set on error.
7828  * This is used to initialize a delegate.
7829  * On failure returns FALSE and sets \p error.
7830  */
7831 gboolean
7832 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7833 {
7834         MONO_REQ_GC_UNSAFE_MODE;
7835
7836         error_init (error);
7837         MonoDomain *domain = mono_domain_get ();
7838         MonoJitInfo *ji;
7839         MonoMethod *method = NULL;
7840
7841         g_assert (addr);
7842
7843         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7844         /* Shared code */
7845         if (!ji && domain != mono_get_root_domain ())
7846                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7847         if (ji) {
7848                 method = mono_jit_info_get_method (ji);
7849                 g_assert (!mono_class_is_gtd (method->klass));
7850         }
7851
7852         return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7853 }
7854
7855 /**
7856  * mono_method_call_message_new:
7857  * \param method method to encapsulate
7858  * \param params parameters to the method
7859  * \param invoke optional, delegate invoke.
7860  * \param cb async callback delegate.
7861  * \param state state passed to the async callback.
7862  * \param error set on error.
7863   * Translates arguments pointers into a \c MonoMethodMessage.
7864  * On failure returns NULL and sets \p error.
7865  */
7866 MonoMethodMessage *
7867 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7868                               MonoDelegate **cb, MonoObject **state, MonoError *error)
7869 {
7870         MONO_REQ_GC_UNSAFE_MODE;
7871
7872         error_init (error);
7873
7874         MonoDomain *domain = mono_domain_get ();
7875         MonoMethodSignature *sig = mono_method_signature (method);
7876         MonoMethodMessage *msg;
7877         int i, count;
7878
7879         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error); 
7880         return_val_if_nok  (error, NULL);
7881
7882         if (invoke) {
7883                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7884                 return_val_if_nok (error, NULL);
7885                 mono_message_init (domain, msg, rm, NULL, error);
7886                 return_val_if_nok (error, NULL);
7887                 count =  sig->param_count - 2;
7888         } else {
7889                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7890                 return_val_if_nok (error, NULL);
7891                 mono_message_init (domain, msg, rm, NULL, error);
7892                 return_val_if_nok (error, NULL);
7893                 count =  sig->param_count;
7894         }
7895
7896         for (i = 0; i < count; i++) {
7897                 gpointer vpos;
7898                 MonoClass *klass;
7899                 MonoObject *arg;
7900
7901                 if (sig->params [i]->byref)
7902                         vpos = *((gpointer *)params [i]);
7903                 else 
7904                         vpos = params [i];
7905
7906                 klass = mono_class_from_mono_type (sig->params [i]);
7907
7908                 if (klass->valuetype) {
7909                         arg = mono_value_box_checked (domain, klass, vpos, error);
7910                         return_val_if_nok (error, NULL);
7911                 } else 
7912                         arg = *((MonoObject **)vpos);
7913                       
7914                 mono_array_setref (msg->args, i, arg);
7915         }
7916
7917         if (cb != NULL && state != NULL) {
7918                 *cb = *((MonoDelegate **)params [i]);
7919                 i++;
7920                 *state = *((MonoObject **)params [i]);
7921         }
7922
7923         return msg;
7924 }
7925
7926 /**
7927  * mono_method_return_message_restore:
7928  *
7929  * Restore results from message based processing back to arguments pointers
7930  */
7931 void
7932 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7933 {
7934         MONO_REQ_GC_UNSAFE_MODE;
7935
7936         error_init (error);
7937
7938         MonoMethodSignature *sig = mono_method_signature (method);
7939         int i, j, type, size, out_len;
7940         
7941         if (out_args == NULL)
7942                 return;
7943         out_len = mono_array_length (out_args);
7944         if (out_len == 0)
7945                 return;
7946
7947         for (i = 0, j = 0; i < sig->param_count; i++) {
7948                 MonoType *pt = sig->params [i];
7949
7950                 if (pt->byref) {
7951                         char *arg;
7952                         if (j >= out_len) {
7953                                 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7954                                 return;
7955                         }
7956
7957                         arg = (char *)mono_array_get (out_args, gpointer, j);
7958                         type = pt->type;
7959
7960                         g_assert (type != MONO_TYPE_VOID);
7961
7962                         if (MONO_TYPE_IS_REFERENCE (pt)) {
7963                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7964                         } else {
7965                                 if (arg) {
7966                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7967                                         size = mono_class_value_size (klass, NULL);
7968                                         if (klass->has_references)
7969                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7970                                         else
7971                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7972                                 } else {
7973                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7974                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7975                                 }
7976                         }
7977
7978                         j++;
7979                 }
7980         }
7981 }
7982
7983 #ifndef DISABLE_REMOTING
7984
7985 /**
7986  * mono_load_remote_field:
7987  * \param this pointer to an object
7988  * \param klass klass of the object containing \p field
7989  * \param field the field to load
7990  * \param res a storage to store the result
7991  * This method is called by the runtime on attempts to load fields of
7992  * transparent proxy objects. \p this points to such TP, \p klass is the class of
7993  * the object containing \p field. \p res is a storage location which can be
7994  * used to store the result.
7995  * \returns an address pointing to the value of field.
7996  */
7997 gpointer
7998 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7999 {
8000         MonoError error;
8001         gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8002         mono_error_cleanup (&error);
8003         return result;
8004 }
8005
8006 /**
8007  * mono_load_remote_field_checked:
8008  * \param this pointer to an object
8009  * \param klass klass of the object containing \p field
8010  * \param field the field to load
8011  * \param res a storage to store the result
8012  * \param error set on error
8013  * This method is called by the runtime on attempts to load fields of
8014  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8015  * the object containing \p field. \p res is a storage location which can be
8016  * used to store the result.
8017  * \returns an address pointing to the value of field.  On failure returns NULL and sets \p error.
8018  */
8019 gpointer
8020 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8021 {
8022         MONO_REQ_GC_UNSAFE_MODE;
8023
8024         static MonoMethod *getter = NULL;
8025
8026         error_init (error);
8027
8028         MonoDomain *domain = mono_domain_get ();
8029         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8030         MonoClass *field_class;
8031         MonoMethodMessage *msg;
8032         MonoArray *out_args;
8033         MonoObject *exc;
8034         char* full_name;
8035
8036         g_assert (mono_object_is_transparent_proxy (this_obj));
8037         g_assert (res != NULL);
8038
8039         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8040                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8041                 return res;
8042         }
8043         
8044         if (!getter) {
8045                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8046                 if (!getter) {
8047                         mono_error_set_not_supported (error, "Linked away.");
8048                         return NULL;
8049                 }
8050         }
8051         
8052         field_class = mono_class_from_mono_type (field->type);
8053
8054         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8055         return_val_if_nok (error, NULL);
8056         out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8057         return_val_if_nok (error, NULL);
8058         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8059         return_val_if_nok (error, NULL);
8060         mono_message_init (domain, msg, rm, out_args, error);
8061         return_val_if_nok (error, NULL);
8062
8063         full_name = mono_type_get_full_name (klass);
8064         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8065         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8066         g_free (full_name);
8067
8068         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8069         return_val_if_nok (error, NULL);
8070
8071         if (exc) {
8072                 mono_error_set_exception_instance (error, (MonoException *)exc);
8073                 return NULL;
8074         }
8075
8076         if (mono_array_length (out_args) == 0)
8077                 return NULL;
8078
8079         mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8080
8081         if (field_class->valuetype) {
8082                 return ((char *)*res) + sizeof (MonoObject);
8083         } else
8084                 return res;
8085 }
8086
8087 /**
8088  * mono_load_remote_field_new:
8089  * \param this
8090  * \param klass
8091  * \param field
8092  * Missing documentation.
8093  */
8094 MonoObject *
8095 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8096 {
8097         MonoError error;
8098
8099         MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8100         mono_error_cleanup (&error);
8101         return result;
8102 }
8103
8104 /**
8105  * mono_load_remote_field_new_checked:
8106  * \param this pointer to an object
8107  * \param klass klass of the object containing \p field
8108  * \param field the field to load
8109  * \param error set on error.
8110  * This method is called by the runtime on attempts to load fields of
8111  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8112  * the object containing \p field.
8113  * \returns a freshly allocated object containing the value of the field.  On failure returns NULL and sets \p error.
8114  */
8115 MonoObject *
8116 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8117 {
8118         MONO_REQ_GC_UNSAFE_MODE;
8119
8120         error_init (error);
8121
8122         static MonoMethod *tp_load = NULL;
8123
8124         g_assert (mono_object_is_transparent_proxy (this_obj));
8125
8126         if (!tp_load) {
8127                 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8128                 if (!tp_load) {
8129                         mono_error_set_not_supported (error, "Linked away.");
8130                         return NULL;
8131                 }
8132         }
8133         
8134         /* MonoType *type = mono_class_get_type (klass); */
8135
8136         gpointer args[2];
8137         args [0] = &klass;
8138         args [1] = &field;
8139
8140         return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8141 }
8142
8143 /**
8144  * mono_store_remote_field:
8145  * \param this_obj pointer to an object
8146  * \param klass klass of the object containing \p field
8147  * \param field the field to load
8148  * \param val the value/object to store
8149  * This method is called by the runtime on attempts to store fields of
8150  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8151  * the object containing \p field. \p val is the new value to store in \p field.
8152  */
8153 void
8154 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8155 {
8156         MonoError error;
8157         (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8158         mono_error_cleanup (&error);
8159 }
8160
8161 /**
8162  * mono_store_remote_field_checked:
8163  * \param this_obj pointer to an object
8164  * \param klass klass of the object containing \p field
8165  * \param field the field to load
8166  * \param val the value/object to store
8167  * \param error set on error
8168  * This method is called by the runtime on attempts to store fields of
8169  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8170  * the object containing \p field. \p val is the new value to store in \p field.
8171  * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8172  */
8173 gboolean
8174 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8175 {
8176         
8177         MONO_REQ_GC_UNSAFE_MODE;
8178
8179         error_init (error);
8180
8181         MonoDomain *domain = mono_domain_get ();
8182         MonoClass *field_class;
8183         MonoObject *arg;
8184
8185         g_assert (mono_object_is_transparent_proxy (this_obj));
8186
8187         field_class = mono_class_from_mono_type (field->type);
8188
8189         if (field_class->valuetype) {
8190                 arg = mono_value_box_checked (domain, field_class, val, error);
8191                 return_val_if_nok (error, FALSE);
8192         } else {
8193                 arg = *((MonoObject**)val);
8194         }
8195
8196         return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8197 }
8198
8199 /**
8200  * mono_store_remote_field_new:
8201  * \param this_obj
8202  * \param klass
8203  * \param field
8204  * \param arg
8205  * Missing documentation
8206  */
8207 void
8208 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8209 {
8210         MonoError error;
8211         (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8212         mono_error_cleanup (&error);
8213 }
8214
8215 /**
8216  * mono_store_remote_field_new_checked:
8217  * \param this_obj
8218  * \param klass
8219  * \param field
8220  * \param arg
8221  * \param error
8222  * Missing documentation
8223  */
8224 gboolean
8225 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8226 {
8227         MONO_REQ_GC_UNSAFE_MODE;
8228
8229         static MonoMethod *tp_store = NULL;
8230
8231         error_init (error);
8232
8233         g_assert (mono_object_is_transparent_proxy (this_obj));
8234
8235         if (!tp_store) {
8236                 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8237                 if (!tp_store) {
8238                         mono_error_set_not_supported (error, "Linked away.");
8239                         return FALSE;
8240                 }
8241         }
8242
8243         gpointer args[3];
8244         args [0] = &klass;
8245         args [1] = &field;
8246         args [2] = arg;
8247
8248         mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8249         return is_ok (error);
8250 }
8251 #endif
8252
8253 /**
8254  * mono_create_ftnptr:
8255  *
8256  * Given a function address, create a function descriptor for it.
8257  * This is only needed on some platforms.
8258  */
8259 gpointer
8260 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8261 {
8262         return callbacks.create_ftnptr (domain, addr);
8263 }
8264
8265 /*
8266  * mono_get_addr_from_ftnptr:
8267  *
8268  *   Given a pointer to a function descriptor, return the function address.
8269  * This is only needed on some platforms.
8270  */
8271 gpointer
8272 mono_get_addr_from_ftnptr (gpointer descr)
8273 {
8274         return callbacks.get_addr_from_ftnptr (descr);
8275 }       
8276
8277 /**
8278  * mono_string_chars:
8279  * \param s a \c MonoString
8280  * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8281  */
8282 gunichar2 *
8283 mono_string_chars (MonoString *s)
8284 {
8285         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8286
8287         return s->chars;
8288 }
8289
8290 /**
8291  * mono_string_length:
8292  * \param s MonoString
8293  * \returns the length in characters of the string
8294  */
8295 int
8296 mono_string_length (MonoString *s)
8297 {
8298         MONO_REQ_GC_UNSAFE_MODE;
8299
8300         return s->length;
8301 }
8302
8303 /**
8304  * mono_string_handle_length:
8305  * \param s \c MonoString
8306  * \returns the length in characters of the string
8307  */
8308 int
8309 mono_string_handle_length (MonoStringHandle s)
8310 {
8311         MONO_REQ_GC_UNSAFE_MODE;
8312
8313         return MONO_HANDLE_GETVAL (s, length);
8314 }
8315
8316
8317 /**
8318  * mono_array_length:
8319  * \param array a \c MonoArray*
8320  * \returns the total number of elements in the array. This works for
8321  * both vectors and multidimensional arrays.
8322  */
8323 uintptr_t
8324 mono_array_length (MonoArray *array)
8325 {
8326         MONO_REQ_GC_UNSAFE_MODE;
8327
8328         return array->max_length;
8329 }
8330
8331 /**
8332  * mono_array_addr_with_size:
8333  * \param array a \c MonoArray*
8334  * \param size size of the array elements
8335  * \param idx index into the array
8336  * Use this function to obtain the address for the \p idx item on the
8337  * \p array containing elements of size \p size.
8338  *
8339  * This method performs no bounds checking or type checking.
8340  * \returns the address of the \p idx element in the array.
8341  */
8342 char*
8343 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8344 {
8345         MONO_REQ_GC_UNSAFE_MODE;
8346
8347         return ((char*)(array)->vector) + size * idx;
8348 }
8349
8350
8351 MonoArray *
8352 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error) 
8353 {
8354         MonoDomain *domain = mono_domain_get ();
8355         MonoArray *res;
8356         int len, i;
8357
8358         error_init (error);
8359         if (!list)
8360                 return NULL;
8361
8362         len = g_list_length (list);
8363         res = mono_array_new_checked (domain, eclass, len, error);
8364         return_val_if_nok (error, NULL);
8365
8366         for (i = 0; list; list = list->next, i++)
8367                 mono_array_set (res, gpointer, i, list->data);
8368
8369         return res;
8370 }
8371
8372 #if NEVER_DEFINED
8373 /*
8374  * The following section is purely to declare prototypes and
8375  * document the API, as these C files are processed by our
8376  * tool
8377  */
8378
8379 /**
8380  * mono_array_set:
8381  * \param array array to alter
8382  * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8383  * \param index index into the array
8384  * \param value value to set
8385  * Value Type version: This sets the \p index's element of the \p array
8386  * with elements of size sizeof(type) to the provided \p value.
8387  *
8388  * This macro does not attempt to perform type checking or bounds checking.
8389  *
8390  * Use this to set value types in a \c MonoArray.
8391  */
8392 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8393 {
8394 }
8395
8396 /**
8397  * mono_array_setref:
8398  * \param array array to alter
8399  * \param index index into the array
8400  * \param value value to set
8401  * Reference Type version. This sets the \p index's element of the
8402  * \p array with elements of size sizeof(type) to the provided \p value.
8403  *
8404  * This macro does not attempt to perform type checking or bounds checking.
8405  *
8406  * Use this to reference types in a \c MonoArray.
8407  */
8408 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8409 {
8410 }
8411
8412 /**
8413  * mono_array_get:
8414  * \param array array on which to operate on
8415  * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8416  * \param index index into the array
8417  *
8418  * Use this macro to retrieve the \p index element of an \p array and
8419  * extract the value assuming that the elements of the array match
8420  * the provided type value.
8421  *
8422  * This method can be used with both arrays holding value types and
8423  * reference types.   For reference types, the \p type parameter should
8424  * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8425  *
8426  * This macro does not attempt to perform type checking or bounds checking.
8427  *
8428  * \returns The element at the \p index position in the \p array.
8429  */
8430 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8431 {
8432 }
8433 #endif
8434