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