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