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