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