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