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