Merge pull request #4615 from alexanderkyte/string_error_handling
[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                 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6189         }
6190         
6191         g_free (ut);
6192     
6193 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6194 #if 0
6195         gunichar2 *str;
6196         const gchar *end;
6197         int len;
6198         MonoString *o = NULL;
6199
6200         if (!g_utf8_validate (text, -1, &end)) {
6201                 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6202                 goto leave;
6203         }
6204
6205         len = g_utf8_strlen (text, -1);
6206         o = mono_string_new_size_checked (domain, len, error);
6207         if (!o)
6208                 goto leave;
6209         str = mono_string_chars (o);
6210
6211         while (text < end) {
6212                 *str++ = g_utf8_get_char (text);
6213                 text = g_utf8_next_char (text);
6214         }
6215
6216 leave:
6217 #endif
6218         return o;
6219 }
6220
6221 /**
6222  * mono_string_new_wrapper:
6223  * \param text pointer to UTF-8 characters.
6224  * Helper function to create a string object from \p text in the current domain.
6225  */
6226 MonoString*
6227 mono_string_new_wrapper (const char *text)
6228 {
6229         MONO_REQ_GC_UNSAFE_MODE;
6230
6231         MonoDomain *domain = mono_domain_get ();
6232
6233         if (text)
6234                 return mono_string_new (domain, text);
6235
6236         return NULL;
6237 }
6238
6239 /**
6240  * mono_value_box:
6241  * \param class the class of the value
6242  * \param value a pointer to the unboxed data
6243  * \returns A newly created object which contains \p value.
6244  */
6245 MonoObject *
6246 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6247 {
6248         MonoError error;
6249         MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6250         mono_error_cleanup (&error);
6251         return result;
6252 }
6253
6254 /**
6255  * mono_value_box_checked:
6256  * \param domain the domain of the new object
6257  * \param class the class of the value
6258  * \param value a pointer to the unboxed data
6259  * \param error set on error
6260  * \returns A newly created object which contains \p value. On failure
6261  * returns NULL and sets \p error.
6262  */
6263 MonoObject *
6264 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6265 {
6266         MONO_REQ_GC_UNSAFE_MODE;
6267         MonoObject *res;
6268         int size;
6269         MonoVTable *vtable;
6270
6271         error_init (error);
6272
6273         g_assert (klass->valuetype);
6274         if (mono_class_is_nullable (klass))
6275                 return mono_nullable_box ((guint8 *)value, klass, error);
6276
6277         vtable = mono_class_vtable (domain, klass);
6278         if (!vtable)
6279                 return NULL;
6280         size = mono_class_instance_size (klass);
6281         res = mono_object_new_alloc_specific_checked (vtable, error);
6282         return_val_if_nok (error, NULL);
6283
6284         size = size - sizeof (MonoObject);
6285
6286 #ifdef HAVE_SGEN_GC
6287         g_assert (size == mono_class_value_size (klass, NULL));
6288         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6289 #else
6290 #if NO_UNALIGNED_ACCESS
6291         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6292 #else
6293         switch (size) {
6294         case 1:
6295                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6296                 break;
6297         case 2:
6298                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6299                 break;
6300         case 4:
6301                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6302                 break;
6303         case 8:
6304                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6305                 break;
6306         default:
6307                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6308         }
6309 #endif
6310 #endif
6311         if (klass->has_finalize) {
6312                 mono_object_register_finalizer (res);
6313                 return_val_if_nok (error, NULL);
6314         }
6315         return res;
6316 }
6317
6318 /**
6319  * mono_value_copy:
6320  * \param dest destination pointer
6321  * \param src source pointer
6322  * \param klass a valuetype class
6323  * Copy a valuetype from \p src to \p dest. This function must be used
6324  * when \p klass contains reference fields.
6325  */
6326 void
6327 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6328 {
6329         MONO_REQ_GC_UNSAFE_MODE;
6330
6331         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6332 }
6333
6334 /**
6335  * mono_value_copy_array:
6336  * \param dest destination array
6337  * \param dest_idx index in the \p dest array
6338  * \param src source pointer
6339  * \param count number of items
6340  * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx. 
6341  * This function must be used when \p klass contains references fields.
6342  * Overlap is handled.
6343  */
6344 void
6345 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6346 {
6347         MONO_REQ_GC_UNSAFE_MODE;
6348
6349         int size = mono_array_element_size (dest->obj.vtable->klass);
6350         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6351         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6352         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6353 }
6354
6355 /**
6356  * mono_object_get_domain:
6357  * \param obj object to query
6358  * \returns the \c MonoDomain where the object is hosted
6359  */
6360 MonoDomain*
6361 mono_object_get_domain (MonoObject *obj)
6362 {
6363         MONO_REQ_GC_UNSAFE_MODE;
6364
6365         return mono_object_domain (obj);
6366 }
6367
6368 /**
6369  * mono_object_get_class:
6370  * \param obj object to query
6371  * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6372  * \returns the \c MonoClass of the object.
6373  */
6374 MonoClass*
6375 mono_object_get_class (MonoObject *obj)
6376 {
6377         MONO_REQ_GC_UNSAFE_MODE;
6378
6379         return mono_object_class (obj);
6380 }
6381 /**
6382  * mono_object_get_size:
6383  * \param o object to query
6384  * \returns the size, in bytes, of \p o
6385  */
6386 guint
6387 mono_object_get_size (MonoObject* o)
6388 {
6389         MONO_REQ_GC_UNSAFE_MODE;
6390
6391         MonoClass* klass = mono_object_class (o);
6392         if (klass == mono_defaults.string_class) {
6393                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6394         } else if (o->vtable->rank) {
6395                 MonoArray *array = (MonoArray*)o;
6396                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6397                 if (array->bounds) {
6398                         size += 3;
6399                         size &= ~3;
6400                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
6401                 }
6402                 return size;
6403         } else {
6404                 return mono_class_instance_size (klass);
6405         }
6406 }
6407
6408 /**
6409  * mono_object_unbox:
6410  * \param obj object to unbox
6411  * \returns a pointer to the start of the valuetype boxed in this
6412  * object.
6413  *
6414  * This method will assert if the object passed is not a valuetype.
6415  */
6416 gpointer
6417 mono_object_unbox (MonoObject *obj)
6418 {
6419         MONO_REQ_GC_UNSAFE_MODE;
6420
6421         /* add assert for valuetypes? */
6422         g_assert (obj->vtable->klass->valuetype);
6423         return ((char*)obj) + sizeof (MonoObject);
6424 }
6425
6426 /**
6427  * mono_object_isinst:
6428  * \param obj an object
6429  * \param klass a pointer to a class 
6430  * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6431  */
6432 MonoObject *
6433 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6434 {
6435         MONO_REQ_GC_UNSAFE_MODE;
6436
6437         HANDLE_FUNCTION_ENTER ();
6438         MONO_HANDLE_DCL (MonoObject, obj);
6439         MonoError error;
6440         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6441         mono_error_cleanup (&error);
6442         HANDLE_FUNCTION_RETURN_OBJ (result);
6443 }
6444         
6445
6446 /**
6447  * mono_object_isinst_checked:
6448  * \param obj an object
6449  * \param klass a pointer to a class 
6450  * \param error set on error
6451  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6452  * On failure returns NULL and sets \p error.
6453  */
6454 MonoObject *
6455 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6456 {
6457         MONO_REQ_GC_UNSAFE_MODE;
6458
6459         HANDLE_FUNCTION_ENTER ();
6460         error_init (error);
6461         MONO_HANDLE_DCL (MonoObject, obj);
6462         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6463         HANDLE_FUNCTION_RETURN_OBJ (result);
6464 }
6465
6466 /**
6467  * mono_object_handle_isinst:
6468  * \param obj an object
6469  * \param klass a pointer to a class 
6470  * \param error set on error
6471  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6472  * On failure returns NULL and sets \p error.
6473  */
6474 MonoObjectHandle
6475 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6476 {
6477         error_init (error);
6478         
6479         if (!klass->inited)
6480                 mono_class_init (klass);
6481
6482         if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6483                 return mono_object_handle_isinst_mbyref (obj, klass, error);
6484         }
6485
6486         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6487
6488         if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6489                 MONO_HANDLE_ASSIGN (result, obj);
6490         return result;
6491 }
6492
6493 /**
6494  * mono_object_isinst_mbyref:
6495  */
6496 MonoObject *
6497 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6498 {
6499         MONO_REQ_GC_UNSAFE_MODE;
6500
6501         HANDLE_FUNCTION_ENTER ();
6502         MonoError error;
6503         MONO_HANDLE_DCL (MonoObject, obj);
6504         MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6505         mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6506         HANDLE_FUNCTION_RETURN_OBJ (result);
6507 }
6508
6509 MonoObjectHandle
6510 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6511 {
6512         error_init (error);
6513
6514         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6515
6516         if (MONO_HANDLE_IS_NULL (obj))
6517                 goto leave;
6518
6519         MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6520         
6521         if (mono_class_is_interface (klass)) {
6522                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6523                         MONO_HANDLE_ASSIGN (result, obj);
6524                         goto leave;
6525                 }
6526
6527                 /* casting an array one of the invariant interfaces that must act as such */
6528                 if (klass->is_array_special_interface) {
6529                         if (mono_class_is_assignable_from (klass, vt->klass)) {
6530                                 MONO_HANDLE_ASSIGN (result, obj);
6531                                 goto leave;
6532                         }
6533                 }
6534
6535                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6536                 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6537                         MONO_HANDLE_ASSIGN (result, obj);
6538                         goto leave;
6539                 }
6540         } else {
6541                 MonoClass *oklass = vt->klass;
6542                 if (mono_class_is_transparent_proxy (oklass)){
6543                         MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6544                         oklass = remote_class->proxy_class;
6545                 }
6546
6547                 mono_class_setup_supertypes (klass);    
6548                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6549                         MONO_HANDLE_ASSIGN (result, obj);
6550                         goto leave;
6551                 }
6552         }
6553 #ifndef DISABLE_REMOTING
6554         if (mono_class_is_transparent_proxy (vt->klass)) 
6555         {
6556                 MonoBoolean custom_type_info =  MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6557                 if (!custom_type_info)
6558                         goto leave;
6559                 MonoDomain *domain = mono_domain_get ();
6560                 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6561                 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6562                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6563                 MonoMethod *im = NULL;
6564                 gpointer pa [2];
6565
6566                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6567                 if (!im) {
6568                         mono_error_set_not_supported (error, "Linked away.");
6569                         goto leave;
6570                 }
6571                 im = mono_object_handle_get_virtual_method (rp, im, error);
6572                 if (!is_ok (error))
6573                         goto leave;
6574                 g_assert (im);
6575         
6576                 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6577                 if (!is_ok (error))
6578                         goto leave;
6579
6580                 pa [0] = MONO_HANDLE_RAW (reftype);
6581                 pa [1] = MONO_HANDLE_RAW (obj);
6582                 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6583                 if (!is_ok (error))
6584                         goto leave;
6585
6586                 if (*(MonoBoolean *) mono_object_unbox(res)) {
6587                         /* Update the vtable of the remote type, so it can safely cast to this new type */
6588                         mono_upgrade_remote_class (domain, obj, klass, error);
6589                         if (!is_ok (error))
6590                                 goto leave;
6591                         MONO_HANDLE_ASSIGN (result, obj);
6592                 }
6593         }
6594 #endif /* DISABLE_REMOTING */
6595 leave:
6596         return result;
6597 }
6598
6599 /**
6600  * mono_object_castclass_mbyref:
6601  * \param obj an object
6602  * \param klass a pointer to a class 
6603  * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6604  */
6605 MonoObject *
6606 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6607 {
6608         MONO_REQ_GC_UNSAFE_MODE;
6609         HANDLE_FUNCTION_ENTER ();
6610         MonoError error;
6611         MONO_HANDLE_DCL (MonoObject, obj);
6612         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6613         if (MONO_HANDLE_IS_NULL (obj))
6614                 goto leave;
6615         MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6616         mono_error_cleanup (&error);
6617 leave:
6618         HANDLE_FUNCTION_RETURN_OBJ (result);
6619 }
6620
6621 typedef struct {
6622         MonoDomain *orig_domain;
6623         MonoString *ins;
6624         MonoString *res;
6625 } LDStrInfo;
6626
6627 static void
6628 str_lookup (MonoDomain *domain, gpointer user_data)
6629 {
6630         MONO_REQ_GC_UNSAFE_MODE;
6631
6632         LDStrInfo *info = (LDStrInfo *)user_data;
6633         if (info->res || domain == info->orig_domain)
6634                 return;
6635         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6636 }
6637
6638 static MonoString*
6639 mono_string_get_pinned (MonoString *str, MonoError *error)
6640 {
6641         MONO_REQ_GC_UNSAFE_MODE;
6642
6643         error_init (error);
6644
6645         /* We only need to make a pinned version of a string if this is a moving GC */
6646         if (!mono_gc_is_moving ())
6647                 return str;
6648         int size;
6649         MonoString *news;
6650         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6651         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6652         if (news) {
6653                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6654                 news->length = mono_string_length (str);
6655         } else {
6656                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6657         }
6658         return news;
6659 }
6660
6661 static MonoString*
6662 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6663 {
6664         MONO_REQ_GC_UNSAFE_MODE;
6665
6666         MonoGHashTable *ldstr_table;
6667         MonoString *s, *res;
6668         MonoDomain *domain;
6669         
6670         error_init (error);
6671
6672         domain = ((MonoObject *)str)->vtable->domain;
6673         ldstr_table = domain->ldstr_table;
6674         ldstr_lock ();
6675         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6676         if (res) {
6677                 ldstr_unlock ();
6678                 return res;
6679         }
6680         if (insert) {
6681                 /* Allocate outside the lock */
6682                 ldstr_unlock ();
6683                 s = mono_string_get_pinned (str, error);
6684                 return_val_if_nok (error, NULL);
6685                 if (s) {
6686                         ldstr_lock ();
6687                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6688                         if (res) {
6689                                 ldstr_unlock ();
6690                                 return res;
6691                         }
6692                         mono_g_hash_table_insert (ldstr_table, s, s);
6693                         ldstr_unlock ();
6694                 }
6695                 return s;
6696         } else {
6697                 LDStrInfo ldstr_info;
6698                 ldstr_info.orig_domain = domain;
6699                 ldstr_info.ins = str;
6700                 ldstr_info.res = NULL;
6701
6702                 mono_domain_foreach (str_lookup, &ldstr_info);
6703                 if (ldstr_info.res) {
6704                         /* 
6705                          * the string was already interned in some other domain:
6706                          * intern it in the current one as well.
6707                          */
6708                         mono_g_hash_table_insert (ldstr_table, str, str);
6709                         ldstr_unlock ();
6710                         return str;
6711                 }
6712         }
6713         ldstr_unlock ();
6714         return NULL;
6715 }
6716
6717 /**
6718  * mono_string_is_interned:
6719  * \param o String to probe
6720  * \returns Whether the string has been interned.
6721  */
6722 MonoString*
6723 mono_string_is_interned (MonoString *o)
6724 {
6725         MonoError error;
6726         MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6727         /* This function does not fail. */
6728         mono_error_assert_ok (&error);
6729         return result;
6730 }
6731
6732 /**
6733  * mono_string_intern:
6734  * \param o String to intern
6735  * Interns the string passed.  
6736  * \returns The interned string.
6737  */
6738 MonoString*
6739 mono_string_intern (MonoString *str)
6740 {
6741         MonoError error;
6742         MonoString *result = mono_string_intern_checked (str, &error);
6743         mono_error_assert_ok (&error);
6744         return result;
6745 }
6746
6747 /**
6748  * mono_string_intern_checked:
6749  * \param o String to intern
6750  * \param error set on error.
6751  * Interns the string passed.
6752  * \returns The interned string.  On failure returns NULL and sets \p error
6753  */
6754 MonoString*
6755 mono_string_intern_checked (MonoString *str, MonoError *error)
6756 {
6757         MONO_REQ_GC_UNSAFE_MODE;
6758
6759         error_init (error);
6760
6761         return mono_string_is_interned_lookup (str, TRUE, error);
6762 }
6763
6764 /**
6765  * mono_ldstr:
6766  * \param domain the domain where the string will be used.
6767  * \param image a metadata context
6768  * \param idx index into the user string table.
6769  * Implementation for the \c ldstr opcode.
6770  * \returns a loaded string from the \p image / \p idx combination.
6771  */
6772 MonoString*
6773 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6774 {
6775         MonoError error;
6776         MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6777         mono_error_cleanup (&error);
6778         return result;
6779 }
6780
6781 /**
6782  * mono_ldstr_checked:
6783  * \param domain the domain where the string will be used.
6784  * \param image a metadata context
6785  * \param idx index into the user string table.
6786  * \param error set on error.
6787  * Implementation for the \c ldstr opcode.
6788  * \returns A loaded string from the \p image / \p idx combination.
6789  * On failure returns NULL and sets \p error.
6790  */
6791 MonoString*
6792 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6793 {
6794         MONO_REQ_GC_UNSAFE_MODE;
6795         error_init (error);
6796
6797         if (image->dynamic) {
6798                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6799                 return str;
6800         } else {
6801                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6802                         return NULL; /*FIXME we should probably be raising an exception here*/
6803                 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6804                 return str;
6805         }
6806 }
6807
6808 /**
6809  * mono_ldstr_metadata_sig
6810  * \param domain the domain for the string
6811  * \param sig the signature of a metadata string
6812  * \param error set on error
6813  * \returns a \c MonoString for a string stored in the metadata. On
6814  * failure returns NULL and sets \p error.
6815  */
6816 static MonoString*
6817 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6818 {
6819         MONO_REQ_GC_UNSAFE_MODE;
6820
6821         error_init (error);
6822         const char *str = sig;
6823         MonoString *o, *interned;
6824         size_t len2;
6825
6826         len2 = mono_metadata_decode_blob_size (str, &str);
6827         len2 >>= 1;
6828
6829         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6830         return_val_if_nok (error, NULL);
6831 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6832         {
6833                 int i;
6834                 guint16 *p2 = (guint16*)mono_string_chars (o);
6835                 for (i = 0; i < len2; ++i) {
6836                         *p2 = GUINT16_FROM_LE (*p2);
6837                         ++p2;
6838                 }
6839         }
6840 #endif
6841         ldstr_lock ();
6842         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6843         ldstr_unlock ();
6844         if (interned)
6845                 return interned; /* o will get garbage collected */
6846
6847         o = mono_string_get_pinned (o, error);
6848         if (o) {
6849                 ldstr_lock ();
6850                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6851                 if (!interned) {
6852                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6853                         interned = o;
6854                 }
6855                 ldstr_unlock ();
6856         }
6857
6858         return interned;
6859 }
6860
6861 /*
6862  * mono_ldstr_utf8:
6863  *
6864  *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
6865  * of an object.
6866  */
6867 char*
6868 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6869 {
6870         const char *str;
6871         size_t len2;
6872         long written = 0;
6873         char *as;
6874         GError *gerror = NULL;
6875
6876         error_init (error);
6877
6878         if (!mono_verifier_verify_string_signature (image, idx, NULL))
6879                 return NULL; /*FIXME we should probably be raising an exception here*/
6880         str = mono_metadata_user_string (image, idx);
6881
6882         len2 = mono_metadata_decode_blob_size (str, &str);
6883         len2 >>= 1;
6884
6885         as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6886         if (gerror) {
6887                 mono_error_set_argument (error, "string", "%s", gerror->message);
6888                 g_error_free (gerror);
6889                 return NULL;
6890         }
6891         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6892         if (len2 > written) {
6893                 /* allocate the total length and copy the part of the string that has been converted */
6894                 char *as2 = (char *)g_malloc0 (len2);
6895                 memcpy (as2, as, written);
6896                 g_free (as);
6897                 as = as2;
6898         }
6899
6900         return as;
6901 }
6902
6903 /**
6904  * mono_string_to_utf8:
6905  * \param s a \c System.String
6906  * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6907  * \returns the UTF-8 representation for \p s.
6908  * The resulting buffer needs to be freed with \c mono_free().
6909  */
6910 char *
6911 mono_string_to_utf8 (MonoString *s)
6912 {
6913         MONO_REQ_GC_UNSAFE_MODE;
6914
6915         MonoError error;
6916         char *result = mono_string_to_utf8_checked (s, &error);
6917         
6918         if (!is_ok (&error)) {
6919                 mono_error_cleanup (&error);
6920                 return NULL;
6921         }
6922         return result;
6923 }
6924
6925 /**
6926  * mono_string_to_utf8_checked:
6927  * \param s a \c System.String
6928  * \param error a \c MonoError.
6929  * Converts a \c MonoString to its UTF-8 representation. May fail; check 
6930  * \p error to determine whether the conversion was successful.
6931  * The resulting buffer should be freed with \c mono_free().
6932  */
6933 char *
6934 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6935 {
6936         MONO_REQ_GC_UNSAFE_MODE;
6937
6938         long written = 0;
6939         char *as;
6940         GError *gerror = NULL;
6941
6942         error_init (error);
6943
6944         if (s == NULL)
6945                 return NULL;
6946
6947         if (!s->length)
6948                 return g_strdup ("");
6949
6950         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6951         if (gerror) {
6952                 mono_error_set_argument (error, "string", "%s", gerror->message);
6953                 g_error_free (gerror);
6954                 return NULL;
6955         }
6956         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6957         if (s->length > written) {
6958                 /* allocate the total length and copy the part of the string that has been converted */
6959                 char *as2 = (char *)g_malloc0 (s->length);
6960                 memcpy (as2, as, written);
6961                 g_free (as);
6962                 as = as2;
6963         }
6964
6965         return as;
6966 }
6967
6968 char *
6969 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6970 {
6971         return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6972 }
6973
6974 /**
6975  * mono_string_to_utf8_ignore:
6976  * \param s a MonoString
6977  * Converts a \c MonoString to its UTF-8 representation. Will ignore
6978  * invalid surrogate pairs.
6979  * The resulting buffer should be freed with \c mono_free().
6980  */
6981 char *
6982 mono_string_to_utf8_ignore (MonoString *s)
6983 {
6984         MONO_REQ_GC_UNSAFE_MODE;
6985
6986         long written = 0;
6987         char *as;
6988
6989         if (s == NULL)
6990                 return NULL;
6991
6992         if (!s->length)
6993                 return g_strdup ("");
6994
6995         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6996
6997         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6998         if (s->length > written) {
6999                 /* allocate the total length and copy the part of the string that has been converted */
7000                 char *as2 = (char *)g_malloc0 (s->length);
7001                 memcpy (as2, as, written);
7002                 g_free (as);
7003                 as = as2;
7004         }
7005
7006         return as;
7007 }
7008
7009 /**
7010  * mono_string_to_utf8_image_ignore:
7011  * \param s a \c System.String
7012  * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7013  */
7014 char *
7015 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7016 {
7017         MONO_REQ_GC_UNSAFE_MODE;
7018
7019         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7020 }
7021
7022 /**
7023  * mono_string_to_utf8_mp_ignore:
7024  * \param s a \c System.String
7025  * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7026  */
7027 char *
7028 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7029 {
7030         MONO_REQ_GC_UNSAFE_MODE;
7031
7032         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7033 }
7034
7035
7036 /**
7037  * mono_string_to_utf16:
7038  * \param s a \c MonoString
7039  * \returns a null-terminated array of the UTF-16 chars
7040  * contained in \p s. The result must be freed with \c g_free().
7041  * This is a temporary helper until our string implementation
7042  * is reworked to always include the null-terminating char.
7043  */
7044 mono_unichar2*
7045 mono_string_to_utf16 (MonoString *s)
7046 {
7047         MONO_REQ_GC_UNSAFE_MODE;
7048
7049         char *as;
7050
7051         if (s == NULL)
7052                 return NULL;
7053
7054         as = (char *)g_malloc ((s->length * 2) + 2);
7055         as [(s->length * 2)] = '\0';
7056         as [(s->length * 2) + 1] = '\0';
7057
7058         if (!s->length) {
7059                 return (gunichar2 *)(as);
7060         }
7061         
7062         memcpy (as, mono_string_chars(s), s->length * 2);
7063         return (gunichar2 *)(as);
7064 }
7065
7066 /**
7067  * mono_string_to_utf32:
7068  * \param s a \c MonoString
7069  * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7070  * contained in \p s. The result must be freed with \c g_free().
7071  */
7072 mono_unichar4*
7073 mono_string_to_utf32 (MonoString *s)
7074 {
7075         MONO_REQ_GC_UNSAFE_MODE;
7076
7077         mono_unichar4 *utf32_output = NULL; 
7078         GError *error = NULL;
7079         glong items_written;
7080         
7081         if (s == NULL)
7082                 return NULL;
7083                 
7084         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7085         
7086         if (error)
7087                 g_error_free (error);
7088
7089         return utf32_output;
7090 }
7091
7092 /**
7093  * mono_string_from_utf16:
7094  * \param data the UTF-16 string (LPWSTR) to convert
7095  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7096  * \returns a \c MonoString.
7097  */
7098 MonoString *
7099 mono_string_from_utf16 (gunichar2 *data)
7100 {
7101         MonoError error;
7102         MonoString *result = mono_string_from_utf16_checked (data, &error);
7103         mono_error_cleanup (&error);
7104         return result;
7105 }
7106
7107 /**
7108  * mono_string_from_utf16_checked:
7109  * \param data the UTF-16 string (LPWSTR) to convert
7110  * \param error set on error
7111  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7112  * \returns a \c MonoString. On failure sets \p error and returns NULL.
7113  */
7114 MonoString *
7115 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7116 {
7117
7118         MONO_REQ_GC_UNSAFE_MODE;
7119
7120         error_init (error);
7121         MonoDomain *domain = mono_domain_get ();
7122         int len = 0;
7123
7124         if (!data)
7125                 return NULL;
7126
7127         while (data [len]) len++;
7128
7129         return mono_string_new_utf16_checked (domain, data, len, error);
7130 }
7131
7132 /**
7133  * mono_string_from_utf32:
7134  * \param data the UTF-32 string (LPWSTR) to convert
7135  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7136  * \returns a \c MonoString.
7137  */
7138 MonoString *
7139 mono_string_from_utf32 (mono_unichar4 *data)
7140 {
7141         MonoError error;
7142         MonoString *result = mono_string_from_utf32_checked (data, &error);
7143         mono_error_cleanup (&error);
7144         return result;
7145 }
7146
7147 /**
7148  * mono_string_from_utf32_checked:
7149  * \param data the UTF-32 string (LPWSTR) to convert
7150  * \param error set on error
7151  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7152  * \returns a \c MonoString. On failure returns NULL and sets \p error.
7153  */
7154 MonoString *
7155 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7156 {
7157         MONO_REQ_GC_UNSAFE_MODE;
7158
7159         error_init (error);
7160         MonoString* result = NULL;
7161         mono_unichar2 *utf16_output = NULL;
7162         GError *gerror = NULL;
7163         glong items_written;
7164         int len = 0;
7165
7166         if (!data)
7167                 return NULL;
7168
7169         while (data [len]) len++;
7170
7171         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7172
7173         if (gerror)
7174                 g_error_free (gerror);
7175
7176         result = mono_string_from_utf16_checked (utf16_output, error);
7177         g_free (utf16_output);
7178         return result;
7179 }
7180
7181 static char *
7182 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7183 {
7184         MONO_REQ_GC_UNSAFE_MODE;
7185
7186         char *r;
7187         char *mp_s;
7188         int len;
7189
7190         if (ignore_error) {
7191                 r = mono_string_to_utf8_ignore (s);
7192         } else {
7193                 r = mono_string_to_utf8_checked (s, error);
7194                 if (!mono_error_ok (error))
7195                         return NULL;
7196         }
7197
7198         if (!mp && !image)
7199                 return r;
7200
7201         len = strlen (r) + 1;
7202         if (mp)
7203                 mp_s = (char *)mono_mempool_alloc (mp, len);
7204         else
7205                 mp_s = (char *)mono_image_alloc (image, len);
7206
7207         memcpy (mp_s, r, len);
7208
7209         g_free (r);
7210
7211         return mp_s;
7212 }
7213
7214 /**
7215  * mono_string_to_utf8_image:
7216  * \param s a \c System.String
7217  * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7218  */
7219 char *
7220 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7221 {
7222         MONO_REQ_GC_UNSAFE_MODE;
7223
7224         return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7225 }
7226
7227 /**
7228  * mono_string_to_utf8_mp:
7229  * \param s a \c System.String
7230  * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7231  */
7232 char *
7233 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7234 {
7235         MONO_REQ_GC_UNSAFE_MODE;
7236
7237         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7238 }
7239
7240
7241 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7242
7243 void
7244 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7245 {
7246         eh_callbacks = *cbs;
7247 }
7248
7249 MonoRuntimeExceptionHandlingCallbacks *
7250 mono_get_eh_callbacks (void)
7251 {
7252         return &eh_callbacks;
7253 }
7254
7255 /**
7256  * mono_raise_exception:
7257  * \param ex exception object
7258  * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7259  */
7260 void
7261 mono_raise_exception (MonoException *ex) 
7262 {
7263         MONO_REQ_GC_UNSAFE_MODE;
7264
7265         /*
7266          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7267          * that will cause gcc to omit the function epilog, causing problems when
7268          * the JIT tries to walk the stack, since the return address on the stack
7269          * will point into the next function in the executable, not this one.
7270          */     
7271         eh_callbacks.mono_raise_exception (ex);
7272 }
7273
7274 void
7275 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
7276 {
7277         MONO_REQ_GC_UNSAFE_MODE;
7278
7279         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7280 }
7281
7282 /**
7283  * mono_wait_handle_new:
7284  * \param domain Domain where the object will be created
7285  * \param handle Handle for the wait handle
7286  * \param error set on error.
7287  * \returns A new \c MonoWaitHandle created in the given domain for the
7288  * given handle.  On failure returns NULL and sets \p error.
7289  */
7290 MonoWaitHandle *
7291 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7292 {
7293         MONO_REQ_GC_UNSAFE_MODE;
7294
7295         MonoWaitHandle *res;
7296         gpointer params [1];
7297         static MonoMethod *handle_set;
7298
7299         error_init (error);
7300         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7301         return_val_if_nok (error, NULL);
7302
7303         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
7304         if (!handle_set)
7305                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7306
7307         params [0] = &handle;
7308
7309         mono_runtime_invoke_checked (handle_set, res, params, error);
7310         return res;
7311 }
7312
7313 HANDLE
7314 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7315 {
7316         MONO_REQ_GC_UNSAFE_MODE;
7317
7318         static MonoClassField *f_safe_handle = NULL;
7319         MonoSafeHandle *sh;
7320
7321         if (!f_safe_handle) {
7322                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7323                 g_assert (f_safe_handle);
7324         }
7325
7326         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7327         return sh->handle;
7328 }
7329
7330
7331 static MonoObject*
7332 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7333 {
7334         MONO_REQ_GC_UNSAFE_MODE;
7335
7336         RuntimeInvokeFunction runtime_invoke;
7337
7338         error_init (error);
7339
7340         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7341                 MonoMethod *method = mono_get_context_capture_method ();
7342                 MonoMethod *wrapper;
7343                 if (!method)
7344                         return NULL;
7345                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7346                 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7347                 return_val_if_nok (error, NULL);
7348                 domain->capture_context_method = mono_compile_method_checked (method, error);
7349                 return_val_if_nok (error, NULL);
7350         }
7351
7352         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7353
7354         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7355 }
7356 /**
7357  * mono_async_result_new:
7358  * \param domain domain where the object will be created.
7359  * \param handle wait handle.
7360  * \param state state to pass to AsyncResult
7361  * \param data C closure data.
7362  * \param error set on error.
7363  * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7364  * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7365  * On failure returns NULL and sets \p error.
7366  */
7367 MonoAsyncResult *
7368 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7369 {
7370         MONO_REQ_GC_UNSAFE_MODE;
7371
7372         error_init (error);
7373         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7374         return_val_if_nok (error, NULL);
7375         MonoObject *context = mono_runtime_capture_context (domain, error);
7376         return_val_if_nok (error, NULL);
7377         /* we must capture the execution context from the original thread */
7378         if (context) {
7379                 MONO_OBJECT_SETREF (res, execution_context, context);
7380                 /* note: result may be null if the flow is suppressed */
7381         }
7382
7383         res->data = (void **)data;
7384         MONO_OBJECT_SETREF (res, object_data, object_data);
7385         MONO_OBJECT_SETREF (res, async_state, state);
7386         MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7387         return_val_if_nok (error, NULL);
7388         if (handle != NULL)
7389                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7390
7391         res->sync_completed = FALSE;
7392         res->completed = FALSE;
7393
7394         return res;
7395 }
7396
7397 MonoObject *
7398 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7399 {
7400         MONO_REQ_GC_UNSAFE_MODE;
7401
7402         MonoError error;
7403         MonoAsyncCall *ac;
7404         MonoObject *res;
7405
7406         g_assert (ares);
7407         g_assert (ares->async_delegate);
7408
7409         ac = (MonoAsyncCall*) ares->object_data;
7410         if (!ac) {
7411                 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7412                 if (mono_error_set_pending_exception (&error))
7413                         return NULL;
7414         } else {
7415                 gpointer wait_event = NULL;
7416
7417                 ac->msg->exc = NULL;
7418
7419                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7420
7421                 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7422                 mono_threads_begin_abort_protected_block ();
7423
7424                 if (!ac->msg->exc) {
7425                         MonoException *ex = mono_error_convert_to_exception (&error);
7426                         ac->msg->exc = (MonoObject *)ex;
7427                 } else {
7428                         mono_error_cleanup (&error);
7429                 }
7430
7431                 MONO_OBJECT_SETREF (ac, res, res);
7432
7433                 mono_monitor_enter ((MonoObject*) ares);
7434                 ares->completed = 1;
7435                 if (ares->handle)
7436                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7437                 mono_monitor_exit ((MonoObject*) ares);
7438
7439                 if (wait_event != NULL)
7440                         mono_w32event_set (wait_event);
7441
7442                 error_init (&error); //the else branch would leave it in an undefined state
7443                 if (ac->cb_method)
7444                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7445
7446                 mono_threads_end_abort_protected_block ();
7447
7448                 if (mono_error_set_pending_exception (&error))
7449                         return NULL;
7450         }
7451
7452         return res;
7453 }
7454
7455 gboolean
7456 mono_message_init (MonoDomain *domain,
7457                    MonoMethodMessage *this_obj, 
7458                    MonoReflectionMethod *method,
7459                    MonoArray *out_args,
7460                    MonoError *error)
7461 {
7462         MONO_REQ_GC_UNSAFE_MODE;
7463
7464         static MonoMethod *init_message_method = NULL;
7465
7466         if (!init_message_method) {
7467                 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7468                 g_assert (init_message_method != NULL);
7469         }
7470
7471         error_init (error);
7472         /* FIXME set domain instead? */
7473         g_assert (domain == mono_domain_get ());
7474         
7475         gpointer args[2];
7476
7477         args[0] = method;
7478         args[1] = out_args;
7479
7480         mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7481         return is_ok (error);
7482 }
7483
7484 #ifndef DISABLE_REMOTING
7485 /**
7486  * mono_remoting_invoke:
7487  * \param real_proxy pointer to a \c RealProxy object
7488  * \param msg The \c MonoMethodMessage to execute
7489  * \param exc used to store exceptions
7490  * \param out_args used to store output arguments
7491  * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7492  * \c IMessage interface and it is not trivial to extract results from there. So
7493  * we call an helper method \c PrivateInvoke instead of calling
7494  * \c RealProxy::Invoke() directly.
7495  * \returns the result object.
7496  */
7497 MonoObject *
7498 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7499 {
7500         MONO_REQ_GC_UNSAFE_MODE;
7501
7502         MonoObject *o;
7503         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7504         gpointer pa [4];
7505
7506         g_assert (exc);
7507
7508         error_init (error);
7509
7510         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7511
7512         if (!im) {
7513                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7514                 if (!im) {
7515                         mono_error_set_not_supported (error, "Linked away.");
7516                         return NULL;
7517                 }
7518                 real_proxy->vtable->domain->private_invoke_method = im;
7519         }
7520
7521         pa [0] = real_proxy;
7522         pa [1] = msg;
7523         pa [2] = exc;
7524         pa [3] = out_args;
7525
7526         o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7527         return_val_if_nok (error, NULL);
7528
7529         return o;
7530 }
7531 #endif
7532
7533 MonoObject *
7534 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
7535                      MonoObject **exc, MonoArray **out_args, MonoError *error) 
7536 {
7537         MONO_REQ_GC_UNSAFE_MODE;
7538
7539         static MonoClass *object_array_klass;
7540         error_init (error);
7541
7542         MonoDomain *domain; 
7543         MonoMethod *method;
7544         MonoMethodSignature *sig;
7545         MonoArray *arr;
7546         int i, j, outarg_count = 0;
7547
7548 #ifndef DISABLE_REMOTING
7549         if (target && mono_object_is_transparent_proxy (target)) {
7550                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7551                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7552                         target = tp->rp->unwrapped_server;
7553                 } else {
7554                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7555                 }
7556         }
7557 #endif
7558
7559         domain = mono_domain_get (); 
7560         method = msg->method->method;
7561         sig = mono_method_signature (method);
7562
7563         for (i = 0; i < sig->param_count; i++) {
7564                 if (sig->params [i]->byref) 
7565                         outarg_count++;
7566         }
7567
7568         if (!object_array_klass) {
7569                 MonoClass *klass;
7570
7571                 klass = mono_array_class_get (mono_defaults.object_class, 1);
7572                 g_assert (klass);
7573
7574                 mono_memory_barrier ();
7575                 object_array_klass = klass;
7576         }
7577
7578         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7579         return_val_if_nok (error, NULL);
7580
7581         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7582         *exc = NULL;
7583
7584         MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7585         return_val_if_nok (error, NULL);
7586
7587         for (i = 0, j = 0; i < sig->param_count; i++) {
7588                 if (sig->params [i]->byref) {
7589                         MonoObject* arg;
7590                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7591                         mono_array_setref (*out_args, j, arg);
7592                         j++;
7593                 }
7594         }
7595
7596         return ret;
7597 }
7598
7599 /**
7600  * prepare_to_string_method:
7601  * @obj: The object
7602  * @target: Set to @obj or unboxed value if a valuetype
7603  *
7604  * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7605  */
7606 static MonoMethod *
7607 prepare_to_string_method (MonoObject *obj, void **target)
7608 {
7609         MONO_REQ_GC_UNSAFE_MODE;
7610
7611         static MonoMethod *to_string = NULL;
7612         MonoMethod *method;
7613         g_assert (target);
7614         g_assert (obj);
7615
7616         *target = obj;
7617
7618         if (!to_string)
7619                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7620
7621         method = mono_object_get_virtual_method (obj, to_string);
7622
7623         // Unbox value type if needed
7624         if (mono_class_is_valuetype (mono_method_get_class (method))) {
7625                 *target = mono_object_unbox (obj);
7626         }
7627         return method;
7628 }
7629
7630 /**
7631  * mono_object_to_string:
7632  * \param obj The object
7633  * \param exc Any exception thrown by \c ToString. May be NULL.
7634  * \returns the result of calling \c ToString on an object.
7635  */
7636 MonoString *
7637 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7638 {
7639         MonoError error;
7640         MonoString *s = NULL;
7641         void *target;
7642         MonoMethod *method = prepare_to_string_method (obj, &target);
7643         if (exc) {
7644                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7645                 if (*exc == NULL && !mono_error_ok (&error))
7646                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7647                 else
7648                         mono_error_cleanup (&error);
7649         } else {
7650                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7651                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7652         }
7653
7654         return s;
7655 }
7656
7657 /**
7658  * mono_object_to_string_checked:
7659  * \param obj The object
7660  * \param error Set on error.
7661  * \returns the result of calling \c ToString() on an object. If the
7662  * method cannot be invoked or if it raises an exception, sets \p error
7663  * and returns NULL.
7664  */
7665 MonoString *
7666 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7667 {
7668         error_init (error);
7669         void *target;
7670         MonoMethod *method = prepare_to_string_method (obj, &target);
7671         return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7672 }
7673
7674 /**
7675  * mono_object_try_to_string:
7676  * \param obj The object
7677  * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7678  * \param error Set if method cannot be invoked.
7679  * \returns the result of calling \c ToString() on an object. If the
7680  * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7681  * and returns NULL.
7682  */
7683 MonoString *
7684 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7685 {
7686         g_assert (exc);
7687         error_init (error);
7688         void *target;
7689         MonoMethod *method = prepare_to_string_method (obj, &target);
7690         return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7691 }
7692
7693
7694
7695 static char *
7696 get_native_backtrace (MonoException *exc_raw)
7697 {
7698         HANDLE_FUNCTION_ENTER ();
7699         MONO_HANDLE_DCL(MonoException, exc);
7700         char * trace = mono_exception_handle_get_native_backtrace (exc);
7701         HANDLE_FUNCTION_RETURN_VAL (trace);
7702 }
7703
7704 /**
7705  * mono_print_unhandled_exception:
7706  * \param exc The exception
7707  * Prints the unhandled exception.
7708  */
7709 void
7710 mono_print_unhandled_exception (MonoObject *exc)
7711 {
7712         MONO_REQ_GC_UNSAFE_MODE;
7713
7714         MonoString * str;
7715         char *message = (char*)"";
7716         gboolean free_message = FALSE;
7717         MonoError error;
7718
7719         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7720                 message = g_strdup ("OutOfMemoryException");
7721                 free_message = TRUE;
7722         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7723                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7724                 free_message = TRUE;
7725         } else {
7726                 
7727                 if (((MonoException*)exc)->native_trace_ips) {
7728                         message = get_native_backtrace ((MonoException*)exc);
7729                         free_message = TRUE;
7730                 } else {
7731                         MonoObject *other_exc = NULL;
7732                         str = mono_object_try_to_string (exc, &other_exc, &error);
7733                         if (other_exc == NULL && !is_ok (&error))
7734                                 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7735                         else
7736                                 mono_error_cleanup (&error);
7737                         if (other_exc) {
7738                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7739                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7740                                 
7741                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7742                                         original_backtrace, nested_backtrace);
7743
7744                                 g_free (original_backtrace);
7745                                 g_free (nested_backtrace);
7746                                 free_message = TRUE;
7747                         } else if (str) {
7748                                 message = mono_string_to_utf8_checked (str, &error);
7749                                 if (!mono_error_ok (&error)) {
7750                                         mono_error_cleanup (&error);
7751                                         message = (char *) "";
7752                                 } else {
7753                                         free_message = TRUE;
7754                                 }
7755                         }
7756                 }
7757         }
7758
7759         /*
7760          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7761          *         exc->vtable->klass->name, message);
7762          */
7763         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7764         
7765         if (free_message)
7766                 g_free (message);
7767 }
7768
7769 /**
7770  * mono_delegate_ctor_with_method:
7771  * \param this pointer to an uninitialized delegate object
7772  * \param target target object
7773  * \param addr pointer to native code
7774  * \param method method
7775  * \param error set on error.
7776  * Initialize a delegate and sets a specific method, not the one
7777  * associated with \p addr.  This is useful when sharing generic code.
7778  * In that case \p addr will most probably not be associated with the
7779  * correct instantiation of the method.
7780  * On failure returns FALSE and sets \p error.
7781  */
7782 gboolean
7783 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7784 {
7785         MONO_REQ_GC_UNSAFE_MODE;
7786
7787         error_init (error);
7788         MonoDelegate *delegate = (MonoDelegate *)this_obj;
7789
7790         g_assert (this_obj);
7791         g_assert (addr);
7792
7793         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7794
7795         if (method)
7796                 delegate->method = method;
7797
7798         mono_stats.delegate_creations++;
7799
7800 #ifndef DISABLE_REMOTING
7801         if (target && mono_object_is_transparent_proxy (target)) {
7802                 g_assert (method);
7803                 method = mono_marshal_get_remoting_invoke (method);
7804 #ifdef ENABLE_INTERPRETER
7805                 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7806 #endif
7807                 delegate->method_ptr = mono_compile_method_checked (method, error);
7808                 return_val_if_nok (error, FALSE);
7809                 MONO_OBJECT_SETREF (delegate, target, target);
7810         } else
7811 #endif
7812         {
7813                 delegate->method_ptr = addr;
7814                 MONO_OBJECT_SETREF (delegate, target, target);
7815         }
7816
7817         delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7818         if (callbacks.init_delegate)
7819                 callbacks.init_delegate (delegate);
7820         return TRUE;
7821 }
7822
7823 /**
7824  * mono_delegate_ctor:
7825  * \param this pointer to an uninitialized delegate object
7826  * \param target target object
7827  * \param addr pointer to native code
7828  * \param error set on error.
7829  * This is used to initialize a delegate.
7830  * On failure returns FALSE and sets \p error.
7831  */
7832 gboolean
7833 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7834 {
7835         MONO_REQ_GC_UNSAFE_MODE;
7836
7837         error_init (error);
7838         MonoDomain *domain = mono_domain_get ();
7839         MonoJitInfo *ji;
7840         MonoMethod *method = NULL;
7841
7842         g_assert (addr);
7843
7844         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7845         /* Shared code */
7846         if (!ji && domain != mono_get_root_domain ())
7847                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7848         if (ji) {
7849                 method = mono_jit_info_get_method (ji);
7850                 g_assert (!mono_class_is_gtd (method->klass));
7851         }
7852
7853         return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7854 }
7855
7856 /**
7857  * mono_method_call_message_new:
7858  * \param method method to encapsulate
7859  * \param params parameters to the method
7860  * \param invoke optional, delegate invoke.
7861  * \param cb async callback delegate.
7862  * \param state state passed to the async callback.
7863  * \param error set on error.
7864   * Translates arguments pointers into a \c MonoMethodMessage.
7865  * On failure returns NULL and sets \p error.
7866  */
7867 MonoMethodMessage *
7868 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7869                               MonoDelegate **cb, MonoObject **state, MonoError *error)
7870 {
7871         MONO_REQ_GC_UNSAFE_MODE;
7872
7873         error_init (error);
7874
7875         MonoDomain *domain = mono_domain_get ();
7876         MonoMethodSignature *sig = mono_method_signature (method);
7877         MonoMethodMessage *msg;
7878         int i, count;
7879
7880         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error); 
7881         return_val_if_nok  (error, NULL);
7882
7883         if (invoke) {
7884                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7885                 return_val_if_nok (error, NULL);
7886                 mono_message_init (domain, msg, rm, NULL, error);
7887                 return_val_if_nok (error, NULL);
7888                 count =  sig->param_count - 2;
7889         } else {
7890                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7891                 return_val_if_nok (error, NULL);
7892                 mono_message_init (domain, msg, rm, NULL, error);
7893                 return_val_if_nok (error, NULL);
7894                 count =  sig->param_count;
7895         }
7896
7897         for (i = 0; i < count; i++) {
7898                 gpointer vpos;
7899                 MonoClass *klass;
7900                 MonoObject *arg;
7901
7902                 if (sig->params [i]->byref)
7903                         vpos = *((gpointer *)params [i]);
7904                 else 
7905                         vpos = params [i];
7906
7907                 klass = mono_class_from_mono_type (sig->params [i]);
7908
7909                 if (klass->valuetype) {
7910                         arg = mono_value_box_checked (domain, klass, vpos, error);
7911                         return_val_if_nok (error, NULL);
7912                 } else 
7913                         arg = *((MonoObject **)vpos);
7914                       
7915                 mono_array_setref (msg->args, i, arg);
7916         }
7917
7918         if (cb != NULL && state != NULL) {
7919                 *cb = *((MonoDelegate **)params [i]);
7920                 i++;
7921                 *state = *((MonoObject **)params [i]);
7922         }
7923
7924         return msg;
7925 }
7926
7927 /**
7928  * mono_method_return_message_restore:
7929  *
7930  * Restore results from message based processing back to arguments pointers
7931  */
7932 void
7933 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7934 {
7935         MONO_REQ_GC_UNSAFE_MODE;
7936
7937         error_init (error);
7938
7939         MonoMethodSignature *sig = mono_method_signature (method);
7940         int i, j, type, size, out_len;
7941         
7942         if (out_args == NULL)
7943                 return;
7944         out_len = mono_array_length (out_args);
7945         if (out_len == 0)
7946                 return;
7947
7948         for (i = 0, j = 0; i < sig->param_count; i++) {
7949                 MonoType *pt = sig->params [i];
7950
7951                 if (pt->byref) {
7952                         char *arg;
7953                         if (j >= out_len) {
7954                                 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7955                                 return;
7956                         }
7957
7958                         arg = (char *)mono_array_get (out_args, gpointer, j);
7959                         type = pt->type;
7960
7961                         g_assert (type != MONO_TYPE_VOID);
7962
7963                         if (MONO_TYPE_IS_REFERENCE (pt)) {
7964                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7965                         } else {
7966                                 if (arg) {
7967                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7968                                         size = mono_class_value_size (klass, NULL);
7969                                         if (klass->has_references)
7970                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7971                                         else
7972                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7973                                 } else {
7974                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7975                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7976                                 }
7977                         }
7978
7979                         j++;
7980                 }
7981         }
7982 }
7983
7984 #ifndef DISABLE_REMOTING
7985
7986 /**
7987  * mono_load_remote_field:
7988  * \param this pointer to an object
7989  * \param klass klass of the object containing \p field
7990  * \param field the field to load
7991  * \param res a storage to store the result
7992  * This method is called by the runtime on attempts to load fields of
7993  * transparent proxy objects. \p this points to such TP, \p klass is the class of
7994  * the object containing \p field. \p res is a storage location which can be
7995  * used to store the result.
7996  * \returns an address pointing to the value of field.
7997  */
7998 gpointer
7999 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8000 {
8001         MonoError error;
8002         gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8003         mono_error_cleanup (&error);
8004         return result;
8005 }
8006
8007 /**
8008  * mono_load_remote_field_checked:
8009  * \param this pointer to an object
8010  * \param klass klass of the object containing \p field
8011  * \param field the field to load
8012  * \param res a storage to store the result
8013  * \param error set on error
8014  * This method is called by the runtime on attempts to load fields of
8015  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8016  * the object containing \p field. \p res is a storage location which can be
8017  * used to store the result.
8018  * \returns an address pointing to the value of field.  On failure returns NULL and sets \p error.
8019  */
8020 gpointer
8021 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8022 {
8023         MONO_REQ_GC_UNSAFE_MODE;
8024
8025         static MonoMethod *getter = NULL;
8026
8027         error_init (error);
8028
8029         MonoDomain *domain = mono_domain_get ();
8030         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8031         MonoClass *field_class;
8032         MonoMethodMessage *msg;
8033         MonoArray *out_args;
8034         MonoObject *exc;
8035         char* full_name;
8036
8037         g_assert (mono_object_is_transparent_proxy (this_obj));
8038         g_assert (res != NULL);
8039
8040         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8041                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8042                 return res;
8043         }
8044         
8045         if (!getter) {
8046                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8047                 if (!getter) {
8048                         mono_error_set_not_supported (error, "Linked away.");
8049                         return NULL;
8050                 }
8051         }
8052         
8053         field_class = mono_class_from_mono_type (field->type);
8054
8055         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8056         return_val_if_nok (error, NULL);
8057         out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8058         return_val_if_nok (error, NULL);
8059         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8060         return_val_if_nok (error, NULL);
8061         mono_message_init (domain, msg, rm, out_args, error);
8062         return_val_if_nok (error, NULL);
8063
8064         full_name = mono_type_get_full_name (klass);
8065         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8066         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8067         g_free (full_name);
8068
8069         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8070         return_val_if_nok (error, NULL);
8071
8072         if (exc) {
8073                 mono_error_set_exception_instance (error, (MonoException *)exc);
8074                 return NULL;
8075         }
8076
8077         if (mono_array_length (out_args) == 0)
8078                 return NULL;
8079
8080         mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8081
8082         if (field_class->valuetype) {
8083                 return ((char *)*res) + sizeof (MonoObject);
8084         } else
8085                 return res;
8086 }
8087
8088 /**
8089  * mono_load_remote_field_new:
8090  * \param this
8091  * \param klass
8092  * \param field
8093  * Missing documentation.
8094  */
8095 MonoObject *
8096 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8097 {
8098         MonoError error;
8099
8100         MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8101         mono_error_cleanup (&error);
8102         return result;
8103 }
8104
8105 /**
8106  * mono_load_remote_field_new_checked:
8107  * \param this pointer to an object
8108  * \param klass klass of the object containing \p field
8109  * \param field the field to load
8110  * \param error set on error.
8111  * This method is called by the runtime on attempts to load fields of
8112  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8113  * the object containing \p field.
8114  * \returns a freshly allocated object containing the value of the field.  On failure returns NULL and sets \p error.
8115  */
8116 MonoObject *
8117 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8118 {
8119         MONO_REQ_GC_UNSAFE_MODE;
8120
8121         error_init (error);
8122
8123         static MonoMethod *tp_load = NULL;
8124
8125         g_assert (mono_object_is_transparent_proxy (this_obj));
8126
8127         if (!tp_load) {
8128                 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8129                 if (!tp_load) {
8130                         mono_error_set_not_supported (error, "Linked away.");
8131                         return NULL;
8132                 }
8133         }
8134         
8135         /* MonoType *type = mono_class_get_type (klass); */
8136
8137         gpointer args[2];
8138         args [0] = &klass;
8139         args [1] = &field;
8140
8141         return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8142 }
8143
8144 /**
8145  * mono_store_remote_field:
8146  * \param this_obj pointer to an object
8147  * \param klass klass of the object containing \p field
8148  * \param field the field to load
8149  * \param val the value/object to store
8150  * This method is called by the runtime on attempts to store fields of
8151  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8152  * the object containing \p field. \p val is the new value to store in \p field.
8153  */
8154 void
8155 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8156 {
8157         MonoError error;
8158         (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8159         mono_error_cleanup (&error);
8160 }
8161
8162 /**
8163  * mono_store_remote_field_checked:
8164  * \param this_obj pointer to an object
8165  * \param klass klass of the object containing \p field
8166  * \param field the field to load
8167  * \param val the value/object to store
8168  * \param error set on error
8169  * This method is called by the runtime on attempts to store fields of
8170  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8171  * the object containing \p field. \p val is the new value to store in \p field.
8172  * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8173  */
8174 gboolean
8175 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8176 {
8177         
8178         MONO_REQ_GC_UNSAFE_MODE;
8179
8180         error_init (error);
8181
8182         MonoDomain *domain = mono_domain_get ();
8183         MonoClass *field_class;
8184         MonoObject *arg;
8185
8186         g_assert (mono_object_is_transparent_proxy (this_obj));
8187
8188         field_class = mono_class_from_mono_type (field->type);
8189
8190         if (field_class->valuetype) {
8191                 arg = mono_value_box_checked (domain, field_class, val, error);
8192                 return_val_if_nok (error, FALSE);
8193         } else {
8194                 arg = *((MonoObject**)val);
8195         }
8196
8197         return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8198 }
8199
8200 /**
8201  * mono_store_remote_field_new:
8202  * \param this_obj
8203  * \param klass
8204  * \param field
8205  * \param arg
8206  * Missing documentation
8207  */
8208 void
8209 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8210 {
8211         MonoError error;
8212         (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8213         mono_error_cleanup (&error);
8214 }
8215
8216 /**
8217  * mono_store_remote_field_new_checked:
8218  * \param this_obj
8219  * \param klass
8220  * \param field
8221  * \param arg
8222  * \param error
8223  * Missing documentation
8224  */
8225 gboolean
8226 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8227 {
8228         MONO_REQ_GC_UNSAFE_MODE;
8229
8230         static MonoMethod *tp_store = NULL;
8231
8232         error_init (error);
8233
8234         g_assert (mono_object_is_transparent_proxy (this_obj));
8235
8236         if (!tp_store) {
8237                 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8238                 if (!tp_store) {
8239                         mono_error_set_not_supported (error, "Linked away.");
8240                         return FALSE;
8241                 }
8242         }
8243
8244         gpointer args[3];
8245         args [0] = &klass;
8246         args [1] = &field;
8247         args [2] = arg;
8248
8249         mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8250         return is_ok (error);
8251 }
8252 #endif
8253
8254 /**
8255  * mono_create_ftnptr:
8256  *
8257  * Given a function address, create a function descriptor for it.
8258  * This is only needed on some platforms.
8259  */
8260 gpointer
8261 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8262 {
8263         return callbacks.create_ftnptr (domain, addr);
8264 }
8265
8266 /*
8267  * mono_get_addr_from_ftnptr:
8268  *
8269  *   Given a pointer to a function descriptor, return the function address.
8270  * This is only needed on some platforms.
8271  */
8272 gpointer
8273 mono_get_addr_from_ftnptr (gpointer descr)
8274 {
8275         return callbacks.get_addr_from_ftnptr (descr);
8276 }       
8277
8278 /**
8279  * mono_string_chars:
8280  * \param s a \c MonoString
8281  * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8282  */
8283 gunichar2 *
8284 mono_string_chars (MonoString *s)
8285 {
8286         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8287
8288         return s->chars;
8289 }
8290
8291 /**
8292  * mono_string_length:
8293  * \param s MonoString
8294  * \returns the length in characters of the string
8295  */
8296 int
8297 mono_string_length (MonoString *s)
8298 {
8299         MONO_REQ_GC_UNSAFE_MODE;
8300
8301         return s->length;
8302 }
8303
8304 /**
8305  * mono_string_handle_length:
8306  * \param s \c MonoString
8307  * \returns the length in characters of the string
8308  */
8309 int
8310 mono_string_handle_length (MonoStringHandle s)
8311 {
8312         MONO_REQ_GC_UNSAFE_MODE;
8313
8314         return MONO_HANDLE_GETVAL (s, length);
8315 }
8316
8317
8318 /**
8319  * mono_array_length:
8320  * \param array a \c MonoArray*
8321  * \returns the total number of elements in the array. This works for
8322  * both vectors and multidimensional arrays.
8323  */
8324 uintptr_t
8325 mono_array_length (MonoArray *array)
8326 {
8327         MONO_REQ_GC_UNSAFE_MODE;
8328
8329         return array->max_length;
8330 }
8331
8332 /**
8333  * mono_array_addr_with_size:
8334  * \param array a \c MonoArray*
8335  * \param size size of the array elements
8336  * \param idx index into the array
8337  * Use this function to obtain the address for the \p idx item on the
8338  * \p array containing elements of size \p size.
8339  *
8340  * This method performs no bounds checking or type checking.
8341  * \returns the address of the \p idx element in the array.
8342  */
8343 char*
8344 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8345 {
8346         MONO_REQ_GC_UNSAFE_MODE;
8347
8348         return ((char*)(array)->vector) + size * idx;
8349 }
8350
8351
8352 MonoArray *
8353 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error) 
8354 {
8355         MonoDomain *domain = mono_domain_get ();
8356         MonoArray *res;
8357         int len, i;
8358
8359         error_init (error);
8360         if (!list)
8361                 return NULL;
8362
8363         len = g_list_length (list);
8364         res = mono_array_new_checked (domain, eclass, len, error);
8365         return_val_if_nok (error, NULL);
8366
8367         for (i = 0; list; list = list->next, i++)
8368                 mono_array_set (res, gpointer, i, list->data);
8369
8370         return res;
8371 }
8372
8373 #if NEVER_DEFINED
8374 /*
8375  * The following section is purely to declare prototypes and
8376  * document the API, as these C files are processed by our
8377  * tool
8378  */
8379
8380 /**
8381  * mono_array_set:
8382  * \param array array to alter
8383  * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8384  * \param index index into the array
8385  * \param value value to set
8386  * Value Type version: This sets the \p index's element of the \p array
8387  * with elements of size sizeof(type) to the provided \p value.
8388  *
8389  * This macro does not attempt to perform type checking or bounds checking.
8390  *
8391  * Use this to set value types in a \c MonoArray.
8392  */
8393 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8394 {
8395 }
8396
8397 /**
8398  * mono_array_setref:
8399  * \param array array to alter
8400  * \param index index into the array
8401  * \param value value to set
8402  * Reference Type version. This sets the \p index's element of the
8403  * \p array with elements of size sizeof(type) to the provided \p value.
8404  *
8405  * This macro does not attempt to perform type checking or bounds checking.
8406  *
8407  * Use this to reference types in a \c MonoArray.
8408  */
8409 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8410 {
8411 }
8412
8413 /**
8414  * mono_array_get:
8415  * \param array array on which to operate on
8416  * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8417  * \param index index into the array
8418  *
8419  * Use this macro to retrieve the \p index element of an \p array and
8420  * extract the value assuming that the elements of the array match
8421  * the provided type value.
8422  *
8423  * This method can be used with both arrays holding value types and
8424  * reference types.   For reference types, the \p type parameter should
8425  * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8426  *
8427  * This macro does not attempt to perform type checking or bounds checking.
8428  *
8429  * \returns The element at the \p index position in the \p array.
8430  */
8431 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8432 {
8433 }
8434 #endif
8435