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