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