Merge pull request #1588 from BrzVlad/feature-aot-wbarrier
[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         gpointer iter;
1884         gpointer *interface_offsets;
1885
1886         mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1887         mono_domain_lock (domain);
1888         runtime_info = class->runtime_info;
1889         if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1890                 mono_domain_unlock (domain);
1891                 mono_loader_unlock ();
1892                 return runtime_info->domain_vtables [domain->domain_id];
1893         }
1894         if (!class->inited || class->exception_type) {
1895                 if (!mono_class_init (class) || class->exception_type) {
1896                         mono_domain_unlock (domain);
1897                         mono_loader_unlock ();
1898                         if (raise_on_error)
1899                                 mono_raise_exception (mono_class_get_exception_for_failure (class));
1900                         return NULL;
1901                 }
1902         }
1903
1904         /* Array types require that their element type be valid*/
1905         if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1906                 MonoClass *element_class = class->element_class;
1907                 if (!element_class->inited)
1908                         mono_class_init (element_class);
1909
1910                 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1911                 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1912                         mono_class_setup_vtable (element_class);
1913                 
1914                 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1915                         /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1916                         if (class->exception_type == MONO_EXCEPTION_NONE)
1917                                 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1918                         mono_domain_unlock (domain);
1919                         mono_loader_unlock ();
1920                         if (raise_on_error)
1921                                 mono_raise_exception (mono_class_get_exception_for_failure (class));
1922                         return NULL;
1923                 }
1924         }
1925
1926         /* 
1927          * For some classes, mono_class_init () already computed class->vtable_size, and 
1928          * that is all that is needed because of the vtable trampolines.
1929          */
1930         if (!class->vtable_size)
1931                 mono_class_setup_vtable (class);
1932
1933         if (class->generic_class && !class->vtable)
1934                 mono_class_check_vtable_constraints (class, NULL);
1935
1936         /* Initialize klass->has_finalize */
1937         mono_class_has_finalizer (class);
1938
1939         if (class->exception_type) {
1940                 mono_domain_unlock (domain);
1941                 mono_loader_unlock ();
1942                 if (raise_on_error)
1943                         mono_raise_exception (mono_class_get_exception_for_failure (class));
1944                 return NULL;
1945         }
1946
1947         vtable_slots = class->vtable_size;
1948         /* we add an additional vtable slot to store the pointer to static field data only when needed */
1949         class_size = mono_class_data_size (class);
1950         if (class_size)
1951                 vtable_slots++;
1952
1953         if (ARCH_USE_IMT) {
1954                 if (class->interface_offsets_count) {
1955                         imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1956                         mono_stats.imt_number_of_tables++;
1957                         mono_stats.imt_tables_size += imt_table_bytes;
1958                 } else {
1959                         imt_table_bytes = 0;
1960                 }
1961         } else {
1962                 imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
1963         }
1964
1965         vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1966
1967         mono_stats.used_class_count++;
1968         mono_stats.class_vtable_size += vtable_size;
1969
1970         interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1971         vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1972         g_assert (!((gsize)vt & 7));
1973
1974         vt->klass = class;
1975         vt->rank = class->rank;
1976         vt->domain = domain;
1977
1978         mono_class_compute_gc_descriptor (class);
1979                 /*
1980                  * We can't use typed allocation in the non-root domains, since the
1981                  * collector needs the GC descriptor stored in the vtable even after
1982                  * the mempool containing the vtable is destroyed when the domain is
1983                  * unloaded. An alternative might be to allocate vtables in the GC
1984                  * heap, but this does not seem to work (it leads to crashes inside
1985                  * libgc). If that approach is tried, two gc descriptors need to be
1986                  * allocated for each class: one for the root domain, and one for all
1987                  * other domains. The second descriptor should contain a bit for the
1988                  * vtable field in MonoObject, since we can no longer assume the 
1989                  * vtable is reachable by other roots after the appdomain is unloaded.
1990                  */
1991 #ifdef HAVE_BOEHM_GC
1992         if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1993                 vt->gc_descr = GC_NO_DESCRIPTOR;
1994         else
1995 #endif
1996                 vt->gc_descr = class->gc_descr;
1997
1998         gc_bits = mono_gc_get_vtable_bits (class);
1999         g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2000
2001         vt->gc_bits = gc_bits;
2002
2003         if (class_size) {
2004                 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2005                 if (class->has_static_refs) {
2006                         gpointer statics_gc_descr;
2007                         int max_set = 0;
2008                         gsize default_bitmap [4] = {0};
2009                         gsize *bitmap;
2010
2011                         bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2012                         /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2013                         statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2014                         vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2015                         mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2016                         if (bitmap != default_bitmap)
2017                                 g_free (bitmap);
2018                 } else {
2019                         vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2020                 }
2021                 vt->has_static_fields = TRUE;
2022                 mono_stats.class_static_data_size += class_size;
2023         }
2024
2025         iter = NULL;
2026         while ((field = mono_class_get_fields (class, &iter))) {
2027                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2028                         continue;
2029                 if (mono_field_is_deleted (field))
2030                         continue;
2031                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2032                         gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2033                         if (special_static != SPECIAL_STATIC_NONE) {
2034                                 guint32 size, offset;
2035                                 gint32 align;
2036                                 gsize default_bitmap [4] = {0};
2037                                 gsize *bitmap;
2038                                 int max_set = 0;
2039                                 int numbits;
2040                                 MonoClass *fclass;
2041                                 if (mono_type_is_reference (field->type)) {
2042                                         default_bitmap [0] = 1;
2043                                         numbits = 1;
2044                                         bitmap = default_bitmap;
2045                                 } else if (mono_type_is_struct (field->type)) {
2046                                         fclass = mono_class_from_mono_type (field->type);
2047                                         bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2048                                         numbits = max_set + 1;
2049                                 } else {
2050                                         default_bitmap [0] = 0;
2051                                         numbits = 0;
2052                                         bitmap = default_bitmap;
2053                                 }
2054                                 size = mono_type_size (field->type, &align);
2055                                 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2056                                 if (!domain->special_static_fields)
2057                                         domain->special_static_fields = g_hash_table_new (NULL, NULL);
2058                                 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2059                                 if (bitmap != default_bitmap)
2060                                         g_free (bitmap);
2061                                 /* 
2062                                  * This marks the field as special static to speed up the
2063                                  * checks in mono_field_static_get/set_value ().
2064                                  */
2065                                 field->offset = -1;
2066                                 continue;
2067                         }
2068                 }
2069                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2070                         MonoClass *fklass = mono_class_from_mono_type (field->type);
2071                         const char *data = mono_field_get_data (field);
2072
2073                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2074                         t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2075                         /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2076                         if (!data)
2077                                 continue;
2078                         if (fklass->valuetype) {
2079                                 memcpy (t, data, mono_class_value_size (fklass, NULL));
2080                         } else {
2081                                 /* it's a pointer type: add check */
2082                                 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2083                                 *t = *(char *)data;
2084                         }
2085                         continue;
2086                 }               
2087         }
2088
2089         vt->max_interface_id = class->max_interface_id;
2090         vt->interface_bitmap = class->interface_bitmap;
2091         
2092         //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2093         //              class->name, class->interface_offsets_count);
2094         
2095         if (! ARCH_USE_IMT) {
2096                 /* initialize interface offsets */
2097                 for (i = 0; i < class->interface_offsets_count; ++i) {
2098                         int interface_id = class->interfaces_packed [i]->interface_id;
2099                         int slot = class->interface_offsets_packed [i];
2100                         interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2101                 }
2102         }
2103
2104         /* Initialize vtable */
2105         if (callbacks.get_vtable_trampoline) {
2106                 // This also covers the AOT case
2107                 for (i = 0; i < class->vtable_size; ++i) {
2108                         vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2109                 }
2110         } else {
2111                 mono_class_setup_vtable (class);
2112
2113                 for (i = 0; i < class->vtable_size; ++i) {
2114                         MonoMethod *cm;
2115
2116                         if ((cm = class->vtable [i]))
2117                                 vt->vtable [i] = arch_create_jit_trampoline (cm);
2118                 }
2119         }
2120
2121         if (ARCH_USE_IMT && imt_table_bytes) {
2122                 /* Now that the vtable is full, we can actually fill up the IMT */
2123                 if (callbacks.get_imt_trampoline) {
2124                         /* lazy construction of the IMT entries enabled */
2125                         for (i = 0; i < MONO_IMT_SIZE; ++i)
2126                                 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2127                 } else {
2128                         build_imt (class, vt, domain, interface_offsets, NULL);
2129                 }
2130         }
2131
2132         /*
2133          * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2134          * re-acquire them and check if another thread has created the vtable in the meantime.
2135          */
2136         /* Special case System.MonoType to avoid infinite recursion */
2137         if (class != mono_defaults.monotype_class) {
2138                 /*FIXME check for OOM*/
2139                 vt->type = mono_type_get_object (domain, &class->byval_arg);
2140                 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2141                         /* This is unregistered in
2142                            unregister_vtable_reflection_type() in
2143                            domain.c. */
2144                         MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2145         }
2146
2147         mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2148
2149         /*  class_vtable_array keeps an array of created vtables
2150          */
2151         g_ptr_array_add (domain->class_vtable_array, vt);
2152         /* class->runtime_info is protected by the loader lock, both when
2153          * it it enlarged and when it is stored info.
2154          */
2155
2156         /*
2157          * Store the vtable in class->runtime_info.
2158          * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2159          */
2160         mono_memory_barrier ();
2161
2162         old_info = class->runtime_info;
2163         if (old_info && old_info->max_domain >= domain->domain_id) {
2164                 /* someone already created a large enough runtime info */
2165                 old_info->domain_vtables [domain->domain_id] = vt;
2166         } else {
2167                 int new_size = domain->domain_id;
2168                 if (old_info)
2169                         new_size = MAX (new_size, old_info->max_domain);
2170                 new_size++;
2171                 /* make the new size a power of two */
2172                 i = 2;
2173                 while (new_size > i)
2174                         i <<= 1;
2175                 new_size = i;
2176                 /* this is a bounded memory retention issue: may want to 
2177                  * handle it differently when we'll have a rcu-like system.
2178                  */
2179                 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2180                 runtime_info->max_domain = new_size - 1;
2181                 /* copy the stuff from the older info */
2182                 if (old_info) {
2183                         memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2184                 }
2185                 runtime_info->domain_vtables [domain->domain_id] = vt;
2186                 /* keep this last*/
2187                 mono_memory_barrier ();
2188                 class->runtime_info = runtime_info;
2189         }
2190
2191         if (class == mono_defaults.monotype_class) {
2192                 /*FIXME check for OOM*/
2193                 vt->type = mono_type_get_object (domain, &class->byval_arg);
2194                 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2195                         /* This is unregistered in
2196                            unregister_vtable_reflection_type() in
2197                            domain.c. */
2198                         MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2199         }
2200
2201         mono_domain_unlock (domain);
2202         mono_loader_unlock ();
2203
2204         /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2205         if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2206                 mono_raise_exception (mono_class_get_exception_for_failure (class));
2207
2208         /* make sure the parent is initialized */
2209         /*FIXME shouldn't this fail the current type?*/
2210         if (class->parent)
2211                 mono_class_vtable_full (domain, class->parent, raise_on_error);
2212
2213         return vt;
2214 }
2215
2216 #ifndef DISABLE_REMOTING
2217 /**
2218  * mono_class_proxy_vtable:
2219  * @domain: the application domain
2220  * @remove_class: the remote class
2221  *
2222  * Creates a vtable for transparent proxies. It is basically
2223  * a copy of the real vtable of the class wrapped in @remote_class,
2224  * but all function pointers invoke the remoting functions, and
2225  * vtable->klass points to the transparent proxy class, and not to @class.
2226  */
2227 static MonoVTable *
2228 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2229 {
2230         MonoError error;
2231         MonoVTable *vt, *pvt;
2232         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2233         MonoClass *k;
2234         GSList *extra_interfaces = NULL;
2235         MonoClass *class = remote_class->proxy_class;
2236         gpointer *interface_offsets;
2237         uint8_t *bitmap;
2238         int bsize;
2239         size_t imt_table_bytes;
2240         
2241 #ifdef COMPRESSED_INTERFACE_BITMAP
2242         int bcsize;
2243 #endif
2244
2245         vt = mono_class_vtable (domain, class);
2246         g_assert (vt); /*FIXME property handle failure*/
2247         max_interface_id = vt->max_interface_id;
2248         
2249         /* Calculate vtable space for extra interfaces */
2250         for (j = 0; j < remote_class->interface_count; j++) {
2251                 MonoClass* iclass = remote_class->interfaces[j];
2252                 GPtrArray *ifaces;
2253                 int method_count;
2254
2255                 /*FIXME test for interfaces with variant generic arguments*/
2256                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2257                         continue;       /* interface implemented by the class */
2258                 if (g_slist_find (extra_interfaces, iclass))
2259                         continue;
2260                         
2261                 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2262                 
2263                 method_count = mono_class_num_methods (iclass);
2264         
2265                 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2266                 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2267                 if (ifaces) {
2268                         for (i = 0; i < ifaces->len; ++i) {
2269                                 MonoClass *ic = g_ptr_array_index (ifaces, i);
2270                                 /*FIXME test for interfaces with variant generic arguments*/
2271                                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2272                                         continue;       /* interface implemented by the class */
2273                                 if (g_slist_find (extra_interfaces, ic))
2274                                         continue;
2275                                 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2276                                 method_count += mono_class_num_methods (ic);
2277                         }
2278                         g_ptr_array_free (ifaces, TRUE);
2279                 }
2280
2281                 extra_interface_vtsize += method_count * sizeof (gpointer);
2282                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2283         }
2284
2285         if (ARCH_USE_IMT) {
2286                 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2287                 mono_stats.imt_number_of_tables++;
2288                 mono_stats.imt_tables_size += imt_table_bytes;
2289         } else {
2290                 imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
2291         }
2292
2293         vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2294
2295         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2296
2297         interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2298         pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2299         g_assert (!((gsize)pvt & 7));
2300
2301         memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2302
2303         pvt->klass = mono_defaults.transparent_proxy_class;
2304         /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2305         pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2306
2307         /* initialize vtable */
2308         mono_class_setup_vtable (class);
2309         for (i = 0; i < class->vtable_size; ++i) {
2310                 MonoMethod *cm;
2311                     
2312                 if ((cm = class->vtable [i]))
2313                         pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2314                 else
2315                         pvt->vtable [i] = NULL;
2316         }
2317
2318         if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2319                 /* create trampolines for abstract methods */
2320                 for (k = class; k; k = k->parent) {
2321                         MonoMethod* m;
2322                         gpointer iter = NULL;
2323                         while ((m = mono_class_get_methods (k, &iter)))
2324                                 if (!pvt->vtable [m->slot])
2325                                         pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2326                 }
2327         }
2328
2329         pvt->max_interface_id = max_interface_id;
2330         bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2331 #ifdef COMPRESSED_INTERFACE_BITMAP
2332         bitmap = g_malloc0 (bsize);
2333 #else
2334         bitmap = mono_domain_alloc0 (domain, bsize);
2335 #endif
2336
2337         if (! ARCH_USE_IMT) {
2338                 /* initialize interface offsets */
2339                 for (i = 0; i < class->interface_offsets_count; ++i) {
2340                         int interface_id = class->interfaces_packed [i]->interface_id;
2341                         int slot = class->interface_offsets_packed [i];
2342                         interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2343                 }
2344         }
2345         for (i = 0; i < class->interface_offsets_count; ++i) {
2346                 int interface_id = class->interfaces_packed [i]->interface_id;
2347                 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2348         }
2349
2350         if (extra_interfaces) {
2351                 int slot = class->vtable_size;
2352                 MonoClass* interf;
2353                 gpointer iter;
2354                 MonoMethod* cm;
2355                 GSList *list_item;
2356
2357                 /* Create trampolines for the methods of the interfaces */
2358                 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2359                         interf = list_item->data;
2360                         
2361                         if (! ARCH_USE_IMT) {
2362                                 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2363                         }
2364                         bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2365
2366                         iter = NULL;
2367                         j = 0;
2368                         while ((cm = mono_class_get_methods (interf, &iter)))
2369                                 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2370                         
2371                         slot += mono_class_num_methods (interf);
2372                 }
2373                 if (! ARCH_USE_IMT) {
2374                         g_slist_free (extra_interfaces);
2375                 }
2376         }
2377
2378         if (ARCH_USE_IMT) {
2379                 /* Now that the vtable is full, we can actually fill up the IMT */
2380                 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2381                 if (extra_interfaces) {
2382                         g_slist_free (extra_interfaces);
2383                 }
2384         }
2385
2386 #ifdef COMPRESSED_INTERFACE_BITMAP
2387         bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2388         pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2389         mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2390         g_free (bitmap);
2391 #else
2392         pvt->interface_bitmap = bitmap;
2393 #endif
2394         return pvt;
2395 }
2396
2397 #endif /* DISABLE_REMOTING */
2398
2399 /**
2400  * mono_class_field_is_special_static:
2401  *
2402  *   Returns whether @field is a thread/context static field.
2403  */
2404 gboolean
2405 mono_class_field_is_special_static (MonoClassField *field)
2406 {
2407         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2408                 return FALSE;
2409         if (mono_field_is_deleted (field))
2410                 return FALSE;
2411         if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2412                 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2413                         return TRUE;
2414         }
2415         return FALSE;
2416 }
2417
2418 /**
2419  * mono_class_field_get_special_static_type:
2420  * @field: The MonoClassField describing the field.
2421  *
2422  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2423  * SPECIAL_STATIC_NONE otherwise.
2424  */
2425 guint32
2426 mono_class_field_get_special_static_type (MonoClassField *field)
2427 {
2428         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2429                 return SPECIAL_STATIC_NONE;
2430         if (mono_field_is_deleted (field))
2431                 return SPECIAL_STATIC_NONE;
2432         if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2433                 return field_is_special_static (field->parent, field);
2434         return SPECIAL_STATIC_NONE;
2435 }
2436
2437 /**
2438  * mono_class_has_special_static_fields:
2439  * 
2440  *   Returns whenever @klass has any thread/context static fields.
2441  */
2442 gboolean
2443 mono_class_has_special_static_fields (MonoClass *klass)
2444 {
2445         MonoClassField *field;
2446         gpointer iter;
2447
2448         iter = NULL;
2449         while ((field = mono_class_get_fields (klass, &iter))) {
2450                 g_assert (field->parent == klass);
2451                 if (mono_class_field_is_special_static (field))
2452                         return TRUE;
2453         }
2454
2455         return FALSE;
2456 }
2457
2458 #ifndef DISABLE_REMOTING
2459 /**
2460  * create_remote_class_key:
2461  * Creates an array of pointers that can be used as a hash key for a remote class.
2462  * The first element of the array is the number of pointers.
2463  */
2464 static gpointer*
2465 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2466 {
2467         gpointer *key;
2468         int i, j;
2469         
2470         if (remote_class == NULL) {
2471                 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2472                         key = g_malloc (sizeof(gpointer) * 3);
2473                         key [0] = GINT_TO_POINTER (2);
2474                         key [1] = mono_defaults.marshalbyrefobject_class;
2475                         key [2] = extra_class;
2476                 } else {
2477                         key = g_malloc (sizeof(gpointer) * 2);
2478                         key [0] = GINT_TO_POINTER (1);
2479                         key [1] = extra_class;
2480                 }
2481         } else {
2482                 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2483                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2484                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2485                         key [1] = remote_class->proxy_class;
2486
2487                         // Keep the list of interfaces sorted
2488                         for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2489                                 if (extra_class && remote_class->interfaces [i] > extra_class) {
2490                                         key [j++] = extra_class;
2491                                         extra_class = NULL;
2492                                 }
2493                                 key [j] = remote_class->interfaces [i];
2494                         }
2495                         if (extra_class)
2496                                 key [j] = extra_class;
2497                 } else {
2498                         // Replace the old class. The interface list is the same
2499                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2500                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2501                         key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2502                         for (i = 0; i < remote_class->interface_count; i++)
2503                                 key [2 + i] = remote_class->interfaces [i];
2504                 }
2505         }
2506         
2507         return key;
2508 }
2509
2510 /**
2511  * copy_remote_class_key:
2512  *
2513  *   Make a copy of KEY in the domain and return the copy.
2514  */
2515 static gpointer*
2516 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2517 {
2518         int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2519         gpointer *mp_key = mono_domain_alloc (domain, key_size);
2520
2521         memcpy (mp_key, key, key_size);
2522
2523         return mp_key;
2524 }
2525
2526 /**
2527  * mono_remote_class:
2528  * @domain: the application domain
2529  * @class_name: name of the remote class
2530  *
2531  * Creates and initializes a MonoRemoteClass object for a remote type. 
2532  *
2533  * Can raise an exception on failure. 
2534  */
2535 MonoRemoteClass*
2536 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2537 {
2538         MonoError error;
2539         MonoRemoteClass *rc;
2540         gpointer* key, *mp_key;
2541         char *name;
2542         
2543         key = create_remote_class_key (NULL, proxy_class);
2544         
2545         mono_domain_lock (domain);
2546         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2547
2548         if (rc) {
2549                 g_free (key);
2550                 mono_domain_unlock (domain);
2551                 return rc;
2552         }
2553
2554         name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2555         if (!mono_error_ok (&error)) {
2556                 g_free (key);
2557                 mono_domain_unlock (domain);
2558                 mono_error_raise_exception (&error);
2559         }
2560
2561         mp_key = copy_remote_class_key (domain, key);
2562         g_free (key);
2563         key = mp_key;
2564
2565         if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2566                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2567                 rc->interface_count = 1;
2568                 rc->interfaces [0] = proxy_class;
2569                 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2570         } else {
2571                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2572                 rc->interface_count = 0;
2573                 rc->proxy_class = proxy_class;
2574         }
2575         
2576         rc->default_vtable = NULL;
2577         rc->xdomain_vtable = NULL;
2578         rc->proxy_class_name = name;
2579 #ifndef DISABLE_PERFCOUNTERS
2580         mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2581 #endif
2582
2583         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2584
2585         mono_domain_unlock (domain);
2586         return rc;
2587 }
2588
2589 /**
2590  * clone_remote_class:
2591  * Creates a copy of the remote_class, adding the provided class or interface
2592  */
2593 static MonoRemoteClass*
2594 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2595 {
2596         MonoRemoteClass *rc;
2597         gpointer* key, *mp_key;
2598         
2599         key = create_remote_class_key (remote_class, extra_class);
2600         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2601         if (rc != NULL) {
2602                 g_free (key);
2603                 return rc;
2604         }
2605
2606         mp_key = copy_remote_class_key (domain, key);
2607         g_free (key);
2608         key = mp_key;
2609
2610         if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2611                 int i,j;
2612                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2613                 rc->proxy_class = remote_class->proxy_class;
2614                 rc->interface_count = remote_class->interface_count + 1;
2615                 
2616                 // Keep the list of interfaces sorted, since the hash key of
2617                 // the remote class depends on this
2618                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2619                         if (remote_class->interfaces [i] > extra_class && i == j)
2620                                 rc->interfaces [j++] = extra_class;
2621                         rc->interfaces [j] = remote_class->interfaces [i];
2622                 }
2623                 if (i == j)
2624                         rc->interfaces [j] = extra_class;
2625         } else {
2626                 // Replace the old class. The interface array is the same
2627                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2628                 rc->proxy_class = extra_class;
2629                 rc->interface_count = remote_class->interface_count;
2630                 if (rc->interface_count > 0)
2631                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2632         }
2633         
2634         rc->default_vtable = NULL;
2635         rc->xdomain_vtable = NULL;
2636         rc->proxy_class_name = remote_class->proxy_class_name;
2637
2638         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2639
2640         return rc;
2641 }
2642
2643 gpointer
2644 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2645 {
2646         mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2647         mono_domain_lock (domain);
2648         if (rp->target_domain_id != -1) {
2649                 if (remote_class->xdomain_vtable == NULL)
2650                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2651                 mono_domain_unlock (domain);
2652                 mono_loader_unlock ();
2653                 return remote_class->xdomain_vtable;
2654         }
2655         if (remote_class->default_vtable == NULL) {
2656                 MonoType *type;
2657                 MonoClass *klass;
2658                 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2659                 klass = mono_class_from_mono_type (type);
2660 #ifndef DISABLE_COM
2661                 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)))
2662                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2663                 else
2664 #endif
2665                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2666         }
2667         
2668         mono_domain_unlock (domain);
2669         mono_loader_unlock ();
2670         return remote_class->default_vtable;
2671 }
2672
2673 /**
2674  * mono_upgrade_remote_class:
2675  * @domain: the application domain
2676  * @tproxy: the proxy whose remote class has to be upgraded.
2677  * @klass: class to which the remote class can be casted.
2678  *
2679  * Updates the vtable of the remote class by adding the necessary method slots
2680  * and interface offsets so it can be safely casted to klass. klass can be a
2681  * class or an interface.
2682  */
2683 void
2684 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2685 {
2686         MonoTransparentProxy *tproxy;
2687         MonoRemoteClass *remote_class;
2688         gboolean redo_vtable;
2689
2690         mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2691         mono_domain_lock (domain);
2692
2693         tproxy = (MonoTransparentProxy*) proxy_object;
2694         remote_class = tproxy->remote_class;
2695         
2696         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2697                 int i;
2698                 redo_vtable = TRUE;
2699                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2700                         if (remote_class->interfaces [i] == klass)
2701                                 redo_vtable = FALSE;
2702         }
2703         else {
2704                 redo_vtable = (remote_class->proxy_class != klass);
2705         }
2706
2707         if (redo_vtable) {
2708                 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2709                 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2710         }
2711         
2712         mono_domain_unlock (domain);
2713         mono_loader_unlock ();
2714 }
2715 #endif /* DISABLE_REMOTING */
2716
2717
2718 /**
2719  * mono_object_get_virtual_method:
2720  * @obj: object to operate on.
2721  * @method: method 
2722  *
2723  * Retrieves the MonoMethod that would be called on obj if obj is passed as
2724  * the instance of a callvirt of method.
2725  */
2726 MonoMethod*
2727 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2728 {
2729         MonoClass *klass;
2730         MonoMethod **vtable;
2731         gboolean is_proxy = FALSE;
2732         MonoMethod *res = NULL;
2733
2734         klass = mono_object_class (obj);
2735 #ifndef DISABLE_REMOTING
2736         if (klass == mono_defaults.transparent_proxy_class) {
2737                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2738                 is_proxy = TRUE;
2739         }
2740 #endif
2741
2742         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2743                         return method;
2744
2745         mono_class_setup_vtable (klass);
2746         vtable = klass->vtable;
2747
2748         if (method->slot == -1) {
2749                 /* method->slot might not be set for instances of generic methods */
2750                 if (method->is_inflated) {
2751                         g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2752                         method->slot = ((MonoMethodInflated*)method)->declaring->slot; 
2753                 } else {
2754                         if (!is_proxy)
2755                                 g_assert_not_reached ();
2756                 }
2757         }
2758
2759         /* check method->slot is a valid index: perform isinstance? */
2760         if (method->slot != -1) {
2761                 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2762                         if (!is_proxy) {
2763                                 gboolean variance_used = FALSE;
2764                                 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2765                                 g_assert (iface_offset > 0);
2766                                 res = vtable [iface_offset + method->slot];
2767                         }
2768                 } else {
2769                         res = vtable [method->slot];
2770                 }
2771     }
2772
2773 #ifndef DISABLE_REMOTING
2774         if (is_proxy) {
2775                 /* It may be an interface, abstract class method or generic method */
2776                 if (!res || mono_method_signature (res)->generic_param_count)
2777                         res = method;
2778
2779                 /* generic methods demand invoke_with_check */
2780                 if (mono_method_signature (res)->generic_param_count)
2781                         res = mono_marshal_get_remoting_invoke_with_check (res);
2782                 else {
2783 #ifndef DISABLE_COM
2784                         if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2785                                 res = mono_cominterop_get_invoke (res);
2786                         else
2787 #endif
2788                                 res = mono_marshal_get_remoting_invoke (res);
2789                 }
2790         } else
2791 #endif
2792         {
2793                 if (method->is_inflated) {
2794                         MonoError error;
2795                         /* Have to inflate the result */
2796                         res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2797                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2798                 }
2799         }
2800
2801         g_assert (res);
2802         
2803         return res;
2804 }
2805
2806 static MonoObject*
2807 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2808 {
2809         g_error ("runtime invoke called on uninitialized runtime");
2810         return NULL;
2811 }
2812
2813 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2814
2815 /**
2816  * mono_runtime_invoke:
2817  * @method: method to invoke
2818  * @obJ: object instance
2819  * @params: arguments to the method
2820  * @exc: exception information.
2821  *
2822  * Invokes the method represented by @method on the object @obj.
2823  *
2824  * obj is the 'this' pointer, it should be NULL for static
2825  * methods, a MonoObject* for object instances and a pointer to
2826  * the value type for value types.
2827  *
2828  * The params array contains the arguments to the method with the
2829  * same convention: MonoObject* pointers for object instances and
2830  * pointers to the value type otherwise. 
2831  * 
2832  * From unmanaged code you'll usually use the
2833  * mono_runtime_invoke() variant.
2834  *
2835  * Note that this function doesn't handle virtual methods for
2836  * you, it will exec the exact method you pass: we still need to
2837  * expose a function to lookup the derived class implementation
2838  * of a virtual method (there are examples of this in the code,
2839  * though).
2840  * 
2841  * You can pass NULL as the exc argument if you don't want to
2842  * catch exceptions, otherwise, *exc will be set to the exception
2843  * thrown, if any.  if an exception is thrown, you can't use the
2844  * MonoObject* result from the function.
2845  * 
2846  * If the method returns a value type, it is boxed in an object
2847  * reference.
2848  */
2849 MonoObject*
2850 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2851 {
2852         MonoObject *result;
2853
2854         if (mono_runtime_get_no_exec ())
2855                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2856
2857         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2858                 mono_profiler_method_start_invoke (method);
2859
2860         result = default_mono_runtime_invoke (method, obj, params, exc);
2861
2862         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2863                 mono_profiler_method_end_invoke (method);
2864
2865         return result;
2866 }
2867
2868 /**
2869  * mono_method_get_unmanaged_thunk:
2870  * @method: method to generate a thunk for.
2871  *
2872  * Returns an unmanaged->managed thunk that can be used to call
2873  * a managed method directly from C.
2874  *
2875  * The thunk's C signature closely matches the managed signature:
2876  *
2877  * C#: public bool Equals (object obj);
2878  * C:  typedef MonoBoolean (*Equals)(MonoObject*,
2879  *             MonoObject*, MonoException**);
2880  *
2881  * The 1st ("this") parameter must not be used with static methods:
2882  *
2883  * C#: public static bool ReferenceEquals (object a, object b);
2884  * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2885  *             MonoException**);
2886  *
2887  * The last argument must be a non-null pointer of a MonoException* pointer.
2888  * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2889  * exception has been thrown in managed code. Otherwise it will point
2890  * to the MonoException* caught by the thunk. In this case, the result of
2891  * the thunk is undefined:
2892  *
2893  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2894  * MonoException *ex = NULL;
2895  * Equals func = mono_method_get_unmanaged_thunk (method);
2896  * MonoBoolean res = func (thisObj, objToCompare, &ex);
2897  * if (ex) {
2898  *    // handle exception
2899  * }
2900  *
2901  * The calling convention of the thunk matches the platform's default
2902  * convention. This means that under Windows, C declarations must
2903  * contain the __stdcall attribute:
2904  *
2905  * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2906  *             MonoObject*, MonoException**);
2907  *
2908  * LIMITATIONS
2909  *
2910  * Value type arguments and return values are treated as they were objects:
2911  *
2912  * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2913  * C:  typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2914  *
2915  * Arguments must be properly boxed upon trunk's invocation, while return
2916  * values must be unboxed.
2917  */
2918 gpointer
2919 mono_method_get_unmanaged_thunk (MonoMethod *method)
2920 {
2921         method = mono_marshal_get_thunk_invoke_wrapper (method);
2922         return mono_compile_method (method);
2923 }
2924
2925 void
2926 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2927 {
2928         int t;
2929         if (type->byref) {
2930                 /* object fields cannot be byref, so we don't need a
2931                    wbarrier here */
2932                 gpointer *p = (gpointer*)dest;
2933                 *p = value;
2934                 return;
2935         }
2936         t = type->type;
2937 handle_enum:
2938         switch (t) {
2939         case MONO_TYPE_BOOLEAN:
2940         case MONO_TYPE_I1:
2941         case MONO_TYPE_U1: {
2942                 guint8 *p = (guint8*)dest;
2943                 *p = value ? *(guint8*)value : 0;
2944                 return;
2945         }
2946         case MONO_TYPE_I2:
2947         case MONO_TYPE_U2:
2948         case MONO_TYPE_CHAR: {
2949                 guint16 *p = (guint16*)dest;
2950                 *p = value ? *(guint16*)value : 0;
2951                 return;
2952         }
2953 #if SIZEOF_VOID_P == 4
2954         case MONO_TYPE_I:
2955         case MONO_TYPE_U:
2956 #endif
2957         case MONO_TYPE_I4:
2958         case MONO_TYPE_U4: {
2959                 gint32 *p = (gint32*)dest;
2960                 *p = value ? *(gint32*)value : 0;
2961                 return;
2962         }
2963 #if SIZEOF_VOID_P == 8
2964         case MONO_TYPE_I:
2965         case MONO_TYPE_U:
2966 #endif
2967         case MONO_TYPE_I8:
2968         case MONO_TYPE_U8: {
2969                 gint64 *p = (gint64*)dest;
2970                 *p = value ? *(gint64*)value : 0;
2971                 return;
2972         }
2973         case MONO_TYPE_R4: {
2974                 float *p = (float*)dest;
2975                 *p = value ? *(float*)value : 0;
2976                 return;
2977         }
2978         case MONO_TYPE_R8: {
2979                 double *p = (double*)dest;
2980                 *p = value ? *(double*)value : 0;
2981                 return;
2982         }
2983         case MONO_TYPE_STRING:
2984         case MONO_TYPE_SZARRAY:
2985         case MONO_TYPE_CLASS:
2986         case MONO_TYPE_OBJECT:
2987         case MONO_TYPE_ARRAY:
2988                 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2989                 return;
2990         case MONO_TYPE_FNPTR:
2991         case MONO_TYPE_PTR: {
2992                 gpointer *p = (gpointer*)dest;
2993                 *p = deref_pointer? *(gpointer*)value: value;
2994                 return;
2995         }
2996         case MONO_TYPE_VALUETYPE:
2997                 /* note that 't' and 'type->type' can be different */
2998                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2999                         t = mono_class_enum_basetype (type->data.klass)->type;
3000                         goto handle_enum;
3001                 } else {
3002                         MonoClass *class = mono_class_from_mono_type (type);
3003                         int size = mono_class_value_size (class, NULL);
3004                         if (value == NULL)
3005                                 mono_gc_bzero_atomic (dest, size);
3006                         else
3007                                 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3008                 }
3009                 return;
3010         case MONO_TYPE_GENERICINST:
3011                 t = type->data.generic_class->container_class->byval_arg.type;
3012                 goto handle_enum;
3013         default:
3014                 g_error ("got type %x", type->type);
3015         }
3016 }
3017
3018 /**
3019  * mono_field_set_value:
3020  * @obj: Instance object
3021  * @field: MonoClassField describing the field to set
3022  * @value: The value to be set
3023  *
3024  * Sets the value of the field described by @field in the object instance @obj
3025  * to the value passed in @value.   This method should only be used for instance
3026  * fields.   For static fields, use mono_field_static_set_value.
3027  *
3028  * The value must be on the native format of the field type. 
3029  */
3030 void
3031 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3032 {
3033         void *dest;
3034
3035         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3036
3037         dest = (char*)obj + field->offset;
3038         mono_copy_value (field->type, dest, value, FALSE);
3039 }
3040
3041 /**
3042  * mono_field_static_set_value:
3043  * @field: MonoClassField describing the field to set
3044  * @value: The value to be set
3045  *
3046  * Sets the value of the static field described by @field
3047  * to the value passed in @value.
3048  *
3049  * The value must be on the native format of the field type. 
3050  */
3051 void
3052 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3053 {
3054         void *dest;
3055
3056         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3057         /* you cant set a constant! */
3058         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3059
3060         if (field->offset == -1) {
3061                 /* Special static */
3062                 gpointer addr;
3063
3064                 mono_domain_lock (vt->domain);
3065                 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3066                 mono_domain_unlock (vt->domain);
3067                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3068         } else {
3069                 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3070         }
3071         mono_copy_value (field->type, dest, value, FALSE);
3072 }
3073
3074 /**
3075  * mono_vtable_get_static_field_data:
3076  *
3077  * Internal use function: return a pointer to the memory holding the static fields
3078  * for a class or NULL if there are no static fields.
3079  * This is exported only for use by the debugger.
3080  */
3081 void *
3082 mono_vtable_get_static_field_data (MonoVTable *vt)
3083 {
3084         if (!vt->has_static_fields)
3085                 return NULL;
3086         return vt->vtable [vt->klass->vtable_size];
3087 }
3088
3089 static guint8*
3090 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3091 {
3092         guint8 *src;
3093
3094         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3095                 if (field->offset == -1) {
3096                         /* Special static */
3097                         gpointer addr;
3098
3099                         mono_domain_lock (vt->domain);
3100                         addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3101                         mono_domain_unlock (vt->domain);
3102                         src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3103                 } else {
3104                         src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3105                 }
3106         } else {
3107                 src = (guint8*)obj + field->offset;
3108         }
3109
3110         return src;
3111 }
3112
3113 /**
3114  * mono_field_get_value:
3115  * @obj: Object instance
3116  * @field: MonoClassField describing the field to fetch information from
3117  * @value: pointer to the location where the value will be stored
3118  *
3119  * Use this routine to get the value of the field @field in the object
3120  * passed.
3121  *
3122  * The pointer provided by value must be of the field type, for reference
3123  * types this is a MonoObject*, for value types its the actual pointer to
3124  * the value type.
3125  *
3126  * For example:
3127  *     int i;
3128  *     mono_field_get_value (obj, int_field, &i);
3129  */
3130 void
3131 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3132 {
3133         void *src;
3134
3135         g_assert (obj);
3136
3137         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3138
3139         src = (char*)obj + field->offset;
3140         mono_copy_value (field->type, value, src, TRUE);
3141 }
3142
3143 /**
3144  * mono_field_get_value_object:
3145  * @domain: domain where the object will be created (if boxing)
3146  * @field: MonoClassField describing the field to fetch information from
3147  * @obj: The object instance for the field.
3148  *
3149  * Returns: a new MonoObject with the value from the given field.  If the
3150  * field represents a value type, the value is boxed.
3151  *
3152  */
3153 MonoObject *
3154 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3155 {       
3156         MonoObject *o;
3157         MonoClass *klass;
3158         MonoVTable *vtable = NULL;
3159         gchar *v;
3160         gboolean is_static = FALSE;
3161         gboolean is_ref = FALSE;
3162         gboolean is_literal = FALSE;
3163         gboolean is_ptr = FALSE;
3164         MonoError error;
3165         MonoType *type = mono_field_get_type_checked (field, &error);
3166
3167         if (!mono_error_ok (&error))
3168                 mono_error_raise_exception (&error);
3169
3170         switch (type->type) {
3171         case MONO_TYPE_STRING:
3172         case MONO_TYPE_OBJECT:
3173         case MONO_TYPE_CLASS:
3174         case MONO_TYPE_ARRAY:
3175         case MONO_TYPE_SZARRAY:
3176                 is_ref = TRUE;
3177                 break;
3178         case MONO_TYPE_U1:
3179         case MONO_TYPE_I1:
3180         case MONO_TYPE_BOOLEAN:
3181         case MONO_TYPE_U2:
3182         case MONO_TYPE_I2:
3183         case MONO_TYPE_CHAR:
3184         case MONO_TYPE_U:
3185         case MONO_TYPE_I:
3186         case MONO_TYPE_U4:
3187         case MONO_TYPE_I4:
3188         case MONO_TYPE_R4:
3189         case MONO_TYPE_U8:
3190         case MONO_TYPE_I8:
3191         case MONO_TYPE_R8:
3192         case MONO_TYPE_VALUETYPE:
3193                 is_ref = type->byref;
3194                 break;
3195         case MONO_TYPE_GENERICINST:
3196                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3197                 break;
3198         case MONO_TYPE_PTR:
3199                 is_ptr = TRUE;
3200                 break;
3201         default:
3202                 g_error ("type 0x%x not handled in "
3203                          "mono_field_get_value_object", type->type);
3204                 return NULL;
3205         }
3206
3207         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3208                 is_literal = TRUE;
3209
3210         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3211                 is_static = TRUE;
3212
3213                 if (!is_literal) {
3214                         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3215                         if (!vtable->initialized)
3216                                 mono_runtime_class_init (vtable);
3217                 }
3218         } else {
3219                 g_assert (obj);
3220         }
3221         
3222         if (is_ref) {
3223                 if (is_literal) {
3224                         get_default_field_value (domain, field, &o);
3225                 } else if (is_static) {
3226                         mono_field_static_get_value (vtable, field, &o);
3227                 } else {
3228                         mono_field_get_value (obj, field, &o);
3229                 }
3230                 return o;
3231         }
3232
3233         if (is_ptr) {
3234                 static MonoMethod *m;
3235                 gpointer args [2];
3236                 gpointer *ptr;
3237                 gpointer v;
3238
3239                 if (!m) {
3240                         MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3241                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3242                         g_assert (m);
3243                 }
3244
3245                 v = &ptr;
3246                 if (is_literal) {
3247                         get_default_field_value (domain, field, v);
3248                 } else if (is_static) {
3249                         mono_field_static_get_value (vtable, field, v);
3250                 } else {
3251                         mono_field_get_value (obj, field, v);
3252                 }
3253
3254                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3255                 args [0] = ptr ? *ptr : NULL;
3256                 args [1] = mono_type_get_object (mono_domain_get (), type);
3257
3258                 return mono_runtime_invoke (m, NULL, args, NULL);
3259         }
3260
3261         /* boxed value type */
3262         klass = mono_class_from_mono_type (type);
3263
3264         if (mono_class_is_nullable (klass))
3265                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3266
3267         o = mono_object_new (domain, klass);
3268         v = ((gchar *) o) + sizeof (MonoObject);
3269
3270         if (is_literal) {
3271                 get_default_field_value (domain, field, v);
3272         } else if (is_static) {
3273                 mono_field_static_get_value (vtable, field, v);
3274         } else {
3275                 mono_field_get_value (obj, field, v);
3276         }
3277
3278         return o;
3279 }
3280
3281 int
3282 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3283 {
3284         int retval = 0;
3285         const char *p = blob;
3286         mono_metadata_decode_blob_size (p, &p);
3287
3288         switch (type) {
3289         case MONO_TYPE_BOOLEAN:
3290         case MONO_TYPE_U1:
3291         case MONO_TYPE_I1:
3292                 *(guint8 *) value = *p;
3293                 break;
3294         case MONO_TYPE_CHAR:
3295         case MONO_TYPE_U2:
3296         case MONO_TYPE_I2:
3297                 *(guint16*) value = read16 (p);
3298                 break;
3299         case MONO_TYPE_U4:
3300         case MONO_TYPE_I4:
3301                 *(guint32*) value = read32 (p);
3302                 break;
3303         case MONO_TYPE_U8:
3304         case MONO_TYPE_I8:
3305                 *(guint64*) value = read64 (p);
3306                 break;
3307         case MONO_TYPE_R4:
3308                 readr4 (p, (float*) value);
3309                 break;
3310         case MONO_TYPE_R8:
3311                 readr8 (p, (double*) value);
3312                 break;
3313         case MONO_TYPE_STRING:
3314                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3315                 break;
3316         case MONO_TYPE_CLASS:
3317                 *(gpointer*) value = NULL;
3318                 break;
3319         default:
3320                 retval = -1;
3321                 g_warning ("type 0x%02x should not be in constant table", type);
3322         }
3323         return retval;
3324 }
3325
3326 static void
3327 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3328 {
3329         MonoTypeEnum def_type;
3330         const char* data;
3331         
3332         data = mono_class_get_field_default_value (field, &def_type);
3333         mono_get_constant_value_from_blob (domain, def_type, data, value);
3334 }
3335
3336 void
3337 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3338 {
3339         void *src;
3340
3341         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3342         
3343         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3344                 get_default_field_value (vt->domain, field, value);
3345                 return;
3346         }
3347
3348         if (field->offset == -1) {
3349                 /* Special static */
3350                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3351                 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3352         } else {
3353                 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3354         }
3355         mono_copy_value (field->type, value, src, TRUE);
3356 }
3357
3358 /**
3359  * mono_field_static_get_value:
3360  * @vt: vtable to the object
3361  * @field: MonoClassField describing the field to fetch information from
3362  * @value: where the value is returned
3363  *
3364  * Use this routine to get the value of the static field @field value.
3365  *
3366  * The pointer provided by value must be of the field type, for reference
3367  * types this is a MonoObject*, for value types its the actual pointer to
3368  * the value type.
3369  *
3370  * For example:
3371  *     int i;
3372  *     mono_field_static_get_value (vt, int_field, &i);
3373  */
3374 void
3375 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3376 {
3377         mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3378 }
3379
3380 /**
3381  * mono_property_set_value:
3382  * @prop: MonoProperty to set
3383  * @obj: instance object on which to act
3384  * @params: parameters to pass to the propery
3385  * @exc: optional exception
3386  *
3387  * Invokes the property's set method with the given arguments on the
3388  * object instance obj (or NULL for static properties). 
3389  * 
3390  * You can pass NULL as the exc argument if you don't want to
3391  * catch exceptions, otherwise, *exc will be set to the exception
3392  * thrown, if any.  if an exception is thrown, you can't use the
3393  * MonoObject* result from the function.
3394  */
3395 void
3396 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3397 {
3398         default_mono_runtime_invoke (prop->set, obj, params, exc);
3399 }
3400
3401 /**
3402  * mono_property_get_value:
3403  * @prop: MonoProperty to fetch
3404  * @obj: instance object on which to act
3405  * @params: parameters to pass to the propery
3406  * @exc: optional exception
3407  *
3408  * Invokes the property's get method with the given arguments on the
3409  * object instance obj (or NULL for static properties). 
3410  * 
3411  * You can pass NULL as the exc argument if you don't want to
3412  * catch exceptions, otherwise, *exc will be set to the exception
3413  * thrown, if any.  if an exception is thrown, you can't use the
3414  * MonoObject* result from the function.
3415  *
3416  * Returns: the value from invoking the get method on the property.
3417  */
3418 MonoObject*
3419 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3420 {
3421         return default_mono_runtime_invoke (prop->get, obj, params, exc);
3422 }
3423
3424 /*
3425  * mono_nullable_init:
3426  * @buf: The nullable structure to initialize.
3427  * @value: the value to initialize from
3428  * @klass: the type for the object
3429  *
3430  * Initialize the nullable structure pointed to by @buf from @value which
3431  * should be a boxed value type.   The size of @buf should be able to hold
3432  * as much data as the @klass->instance_size (which is the number of bytes
3433  * that will be copies).
3434  *
3435  * Since Nullables have variable structure, we can not define a C
3436  * structure for them.
3437  */
3438 void
3439 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3440 {
3441         MonoClass *param_class = klass->cast_class;
3442
3443         mono_class_setup_fields_locking (klass);
3444         g_assert (klass->fields_inited);
3445                                 
3446         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3447         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3448
3449         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3450         if (value) {
3451                 if (param_class->has_references)
3452                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3453                 else
3454                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3455         } else {
3456                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3457         }
3458 }
3459
3460 /**
3461  * mono_nullable_box:
3462  * @buf: The buffer representing the data to be boxed
3463  * @klass: the type to box it as.
3464  *
3465  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3466  * @buf.
3467  */
3468 MonoObject*
3469 mono_nullable_box (guint8 *buf, MonoClass *klass)
3470 {
3471         MonoClass *param_class = klass->cast_class;
3472
3473         mono_class_setup_fields_locking (klass);
3474         g_assert (klass->fields_inited);
3475
3476         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3477         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3478
3479         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3480                 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3481                 if (param_class->has_references)
3482                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3483                 else
3484                         mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3485                 return o;
3486         }
3487         else
3488                 return NULL;
3489 }
3490
3491 /**
3492  * mono_get_delegate_invoke:
3493  * @klass: The delegate class
3494  *
3495  * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3496  */
3497 MonoMethod *
3498 mono_get_delegate_invoke (MonoClass *klass)
3499 {
3500         MonoMethod *im;
3501
3502         /* This is called at runtime, so avoid the slower search in metadata */
3503         mono_class_setup_methods (klass);
3504         if (klass->exception_type)
3505                 return NULL;
3506         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3507         return im;
3508 }
3509
3510 /**
3511  * mono_get_delegate_begin_invoke:
3512  * @klass: The delegate class
3513  *
3514  * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3515  */
3516 MonoMethod *
3517 mono_get_delegate_begin_invoke (MonoClass *klass)
3518 {
3519         MonoMethod *im;
3520
3521         /* This is called at runtime, so avoid the slower search in metadata */
3522         mono_class_setup_methods (klass);
3523         if (klass->exception_type)
3524                 return NULL;
3525         im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3526         return im;
3527 }
3528
3529 /**
3530  * mono_get_delegate_end_invoke:
3531  * @klass: The delegate class
3532  *
3533  * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3534  */
3535 MonoMethod *
3536 mono_get_delegate_end_invoke (MonoClass *klass)
3537 {
3538         MonoMethod *im;
3539
3540         /* This is called at runtime, so avoid the slower search in metadata */
3541         mono_class_setup_methods (klass);
3542         if (klass->exception_type)
3543                 return NULL;
3544         im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3545         return im;
3546 }
3547
3548 /**
3549  * mono_runtime_delegate_invoke:
3550  * @delegate: pointer to a delegate object.
3551  * @params: parameters for the delegate.
3552  * @exc: Pointer to the exception result.
3553  *
3554  * Invokes the delegate method @delegate with the parameters provided.
3555  *
3556  * You can pass NULL as the exc argument if you don't want to
3557  * catch exceptions, otherwise, *exc will be set to the exception
3558  * thrown, if any.  if an exception is thrown, you can't use the
3559  * MonoObject* result from the function.
3560  */
3561 MonoObject*
3562 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3563 {
3564         MonoMethod *im;
3565         MonoClass *klass = delegate->vtable->klass;
3566
3567         im = mono_get_delegate_invoke (klass);
3568         if (!im)
3569                 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3570
3571         return mono_runtime_invoke (im, delegate, params, exc);
3572 }
3573
3574 static char **main_args = NULL;
3575 static int num_main_args = 0;
3576
3577 /**
3578  * mono_runtime_get_main_args:
3579  *
3580  * Returns: a MonoArray with the arguments passed to the main program
3581  */
3582 MonoArray*
3583 mono_runtime_get_main_args (void)
3584 {
3585         MonoArray *res;
3586         int i;
3587         MonoDomain *domain = mono_domain_get ();
3588
3589         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3590
3591         for (i = 0; i < num_main_args; ++i)
3592                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3593
3594         return res;
3595 }
3596
3597 static void
3598 free_main_args (void)
3599 {
3600         int i;
3601
3602         for (i = 0; i < num_main_args; ++i)
3603                 g_free (main_args [i]);
3604         g_free (main_args);
3605         num_main_args = 0;
3606         main_args = NULL;
3607 }
3608
3609 /**
3610  * mono_runtime_set_main_args:
3611  * @argc: number of arguments from the command line
3612  * @argv: array of strings from the command line
3613  *
3614  * Set the command line arguments from an embedding application that doesn't otherwise call
3615  * mono_runtime_run_main ().
3616  */
3617 int
3618 mono_runtime_set_main_args (int argc, char* argv[])
3619 {
3620         int i;
3621
3622         free_main_args ();
3623         main_args = g_new0 (char*, argc);
3624         num_main_args = argc;
3625
3626         for (i = 0; i < argc; ++i) {
3627                 gchar *utf8_arg;
3628
3629                 utf8_arg = mono_utf8_from_external (argv[i]);
3630                 if (utf8_arg == NULL) {
3631                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3632                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3633                         exit (-1);
3634                 }
3635
3636                 main_args [i] = utf8_arg;
3637         }
3638
3639         return 0;
3640 }
3641
3642 /**
3643  * mono_runtime_run_main:
3644  * @method: the method to start the application with (usually Main)
3645  * @argc: number of arguments from the command line
3646  * @argv: array of strings from the command line
3647  * @exc: excetption results
3648  *
3649  * Execute a standard Main() method (argc/argv contains the
3650  * executable name). This method also sets the command line argument value
3651  * needed by System.Environment.
3652  *
3653  * 
3654  */
3655 int
3656 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3657                        MonoObject **exc)
3658 {
3659         int i;
3660         MonoArray *args = NULL;
3661         MonoDomain *domain = mono_domain_get ();
3662         gchar *utf8_fullpath;
3663         MonoMethodSignature *sig;
3664
3665         g_assert (method != NULL);
3666         
3667         mono_thread_set_main (mono_thread_current ());
3668
3669         main_args = g_new0 (char*, argc);
3670         num_main_args = argc;
3671
3672         if (!g_path_is_absolute (argv [0])) {
3673                 gchar *basename = g_path_get_basename (argv [0]);
3674                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3675                                                     basename,
3676                                                     NULL);
3677
3678                 utf8_fullpath = mono_utf8_from_external (fullpath);
3679                 if(utf8_fullpath == NULL) {
3680                         /* Printing the arg text will cause glib to
3681                          * whinge about "Invalid UTF-8", but at least
3682                          * its relevant, and shows the problem text
3683                          * string.
3684                          */
3685                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3686                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3687                         exit (-1);
3688                 }
3689
3690                 g_free (fullpath);
3691                 g_free (basename);
3692         } else {
3693                 utf8_fullpath = mono_utf8_from_external (argv[0]);
3694                 if(utf8_fullpath == NULL) {
3695                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3696                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3697                         exit (-1);
3698                 }
3699         }
3700
3701         main_args [0] = utf8_fullpath;
3702
3703         for (i = 1; i < argc; ++i) {
3704                 gchar *utf8_arg;
3705
3706                 utf8_arg=mono_utf8_from_external (argv[i]);
3707                 if(utf8_arg==NULL) {
3708                         /* Ditto the comment about Invalid UTF-8 here */
3709                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3710                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3711                         exit (-1);
3712                 }
3713
3714                 main_args [i] = utf8_arg;
3715         }
3716         argc--;
3717         argv++;
3718
3719         sig = mono_method_signature (method);
3720         if (!sig) {
3721                 g_print ("Unable to load Main method.\n");
3722                 exit (-1);
3723         }
3724
3725         if (sig->param_count) {
3726                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3727                 for (i = 0; i < argc; ++i) {
3728                         /* The encodings should all work, given that
3729                          * we've checked all these args for the
3730                          * main_args array.
3731                          */
3732                         gchar *str = mono_utf8_from_external (argv [i]);
3733                         MonoString *arg = mono_string_new (domain, str);
3734                         mono_array_setref (args, i, arg);
3735                         g_free (str);
3736                 }
3737         } else {
3738                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3739         }
3740         
3741         mono_assembly_set_main (method->klass->image->assembly);
3742
3743         return mono_runtime_exec_main (method, args, exc);
3744 }
3745
3746 static MonoObject*
3747 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3748 {
3749         static MonoMethod *serialize_method;
3750
3751         void *params [1];
3752         MonoObject *array;
3753
3754         if (!serialize_method) {
3755                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3756                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3757         }
3758
3759         if (!serialize_method) {
3760                 *failure = TRUE;
3761                 return NULL;
3762         }
3763
3764         g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3765
3766         params [0] = obj;
3767         *exc = NULL;
3768         array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3769         if (*exc)
3770                 *failure = TRUE;
3771
3772         return array;
3773 }
3774
3775 static MonoObject*
3776 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3777 {
3778         static MonoMethod *deserialize_method;
3779
3780         void *params [1];
3781         MonoObject *result;
3782
3783         if (!deserialize_method) {
3784                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3785                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3786         }
3787         if (!deserialize_method) {
3788                 *failure = TRUE;
3789                 return NULL;
3790         }
3791
3792         params [0] = obj;
3793         *exc = NULL;
3794         result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3795         if (*exc)
3796                 *failure = TRUE;
3797
3798         return result;
3799 }
3800
3801 #ifndef DISABLE_REMOTING
3802 static MonoObject*
3803 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3804 {
3805         static MonoMethod *get_proxy_method;
3806
3807         MonoDomain *domain = mono_domain_get ();
3808         MonoRealProxy *real_proxy;
3809         MonoReflectionType *reflection_type;
3810         MonoTransparentProxy *transparent_proxy;
3811
3812         if (!get_proxy_method)
3813                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3814
3815         g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3816
3817         real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3818         reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3819
3820         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3821         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3822
3823         *exc = NULL;
3824         transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3825         if (*exc)
3826                 *failure = TRUE;
3827
3828         return (MonoObject*) transparent_proxy;
3829 }
3830 #endif /* DISABLE_REMOTING */
3831
3832 /**
3833  * mono_object_xdomain_representation
3834  * @obj: an object
3835  * @target_domain: a domain
3836  * @exc: pointer to a MonoObject*
3837  *
3838  * Creates a representation of obj in the domain target_domain.  This
3839  * is either a copy of obj arrived through via serialization and
3840  * deserialization or a proxy, depending on whether the object is
3841  * serializable or marshal by ref.  obj must not be in target_domain.
3842  *
3843  * If the object cannot be represented in target_domain, NULL is
3844  * returned and *exc is set to an appropriate exception.
3845  */
3846 MonoObject*
3847 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3848 {
3849         MonoObject *deserialized = NULL;
3850         gboolean failure = FALSE;
3851
3852         *exc = NULL;
3853
3854 #ifndef DISABLE_REMOTING
3855         if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3856                 deserialized = make_transparent_proxy (obj, &failure, exc);
3857         } 
3858         else
3859 #endif
3860         {
3861                 MonoDomain *domain = mono_domain_get ();
3862                 MonoObject *serialized;
3863
3864                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3865                 serialized = serialize_object (obj, &failure, exc);
3866                 mono_domain_set_internal_with_options (target_domain, FALSE);
3867                 if (!failure)
3868                         deserialized = deserialize_object (serialized, &failure, exc);
3869                 if (domain != target_domain)
3870                         mono_domain_set_internal_with_options (domain, FALSE);
3871         }
3872
3873         return deserialized;
3874 }
3875
3876 /* Used in call_unhandled_exception_delegate */
3877 static MonoObject *
3878 create_unhandled_exception_eventargs (MonoObject *exc)
3879 {
3880         MonoClass *klass;
3881         gpointer args [2];
3882         MonoMethod *method = NULL;
3883         MonoBoolean is_terminating = TRUE;
3884         MonoObject *obj;
3885
3886         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3887         g_assert (klass);
3888
3889         mono_class_init (klass);
3890
3891         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3892         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3893         g_assert (method);
3894
3895         args [0] = exc;
3896         args [1] = &is_terminating;
3897
3898         obj = mono_object_new (mono_domain_get (), klass);
3899         mono_runtime_invoke (method, obj, args, NULL);
3900
3901         return obj;
3902 }
3903
3904 /* Used in mono_unhandled_exception */
3905 static void
3906 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3907         MonoObject *e = NULL;
3908         gpointer pa [2];
3909         MonoDomain *current_domain = mono_domain_get ();
3910
3911         if (domain != current_domain)
3912                 mono_domain_set_internal_with_options (domain, FALSE);
3913
3914         g_assert (domain == mono_object_domain (domain->domain));
3915
3916         if (mono_object_domain (exc) != domain) {
3917                 MonoObject *serialization_exc;
3918
3919                 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3920                 if (!exc) {
3921                         if (serialization_exc) {
3922                                 MonoObject *dummy;
3923                                 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3924                                 g_assert (exc);
3925                         } else {
3926                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3927                                                 "System.Runtime.Serialization", "SerializationException",
3928                                                 "Could not serialize unhandled exception.");
3929                         }
3930                 }
3931         }
3932         g_assert (mono_object_domain (exc) == domain);
3933
3934         pa [0] = domain->domain;
3935         pa [1] = create_unhandled_exception_eventargs (exc);
3936         mono_runtime_delegate_invoke (delegate, pa, &e);
3937
3938         if (domain != current_domain)
3939                 mono_domain_set_internal_with_options (current_domain, FALSE);
3940
3941         if (e) {
3942                 MonoError error;
3943                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3944                 if (!mono_error_ok (&error)) {
3945                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3946                         mono_error_cleanup (&error);
3947                 } else {
3948                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
3949                         g_free (msg);
3950                 }
3951         }
3952 }
3953
3954 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3955
3956 /**
3957  * mono_runtime_unhandled_exception_policy_set:
3958  * @policy: the new policy
3959  * 
3960  * This is a VM internal routine.
3961  *
3962  * Sets the runtime policy for handling unhandled exceptions.
3963  */
3964 void
3965 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3966         runtime_unhandled_exception_policy = policy;
3967 }
3968
3969 /**
3970  * mono_runtime_unhandled_exception_policy_get:
3971  *
3972  * This is a VM internal routine.
3973  *
3974  * Gets the runtime policy for handling unhandled exceptions.
3975  */
3976 MonoRuntimeUnhandledExceptionPolicy
3977 mono_runtime_unhandled_exception_policy_get (void) {
3978         return runtime_unhandled_exception_policy;
3979 }
3980
3981 /**
3982  * mono_unhandled_exception:
3983  * @exc: exception thrown
3984  *
3985  * This is a VM internal routine.
3986  *
3987  * We call this function when we detect an unhandled exception
3988  * in the default domain.
3989  *
3990  * It invokes the * UnhandledException event in AppDomain or prints
3991  * a warning to the console 
3992  */
3993 void
3994 mono_unhandled_exception (MonoObject *exc)
3995 {
3996         MonoDomain *current_domain = mono_domain_get ();
3997         MonoDomain *root_domain = mono_get_root_domain ();
3998         MonoClassField *field;
3999         MonoObject *current_appdomain_delegate;
4000         MonoObject *root_appdomain_delegate;
4001
4002         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
4003                                              "UnhandledException");
4004         g_assert (field);
4005
4006         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4007                 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4008                                 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4009                 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4010                 if (current_domain != root_domain) {
4011                         current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4012                 } else {
4013                         current_appdomain_delegate = NULL;
4014                 }
4015
4016                 /* set exitcode only if we will abort the process */
4017                 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4018                         if (abort_process)
4019                                 mono_environment_exitcode_set (1);
4020                         mono_print_unhandled_exception (exc);
4021                 } else {
4022                         if (root_appdomain_delegate) {
4023                                 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4024                         }
4025                         if (current_appdomain_delegate) {
4026                                 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4027                         }
4028                 }
4029         }
4030 }
4031
4032 /**
4033  * mono_runtime_exec_managed_code:
4034  * @domain: Application domain
4035  * @main_func: function to invoke from the execution thread
4036  * @main_args: parameter to the main_func
4037  *
4038  * Launch a new thread to execute a function
4039  *
4040  * main_func is called back from the thread with main_args as the
4041  * parameter.  The callback function is expected to start Main()
4042  * eventually.  This function then waits for all managed threads to
4043  * finish.
4044  * It is not necesseray anymore to execute managed code in a subthread,
4045  * so this function should not be used anymore by default: just
4046  * execute the code and then call mono_thread_manage ().
4047  */
4048 void
4049 mono_runtime_exec_managed_code (MonoDomain *domain,
4050                                 MonoMainThreadFunc main_func,
4051                                 gpointer main_args)
4052 {
4053         mono_thread_create (domain, main_func, main_args);
4054
4055         mono_thread_manage ();
4056 }
4057
4058 /*
4059  * Execute a standard Main() method (args doesn't contain the
4060  * executable name).
4061  */
4062 int
4063 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4064 {
4065         MonoDomain *domain;
4066         gpointer pa [1];
4067         int rval;
4068         MonoCustomAttrInfo* cinfo;
4069         gboolean has_stathread_attribute;
4070         MonoInternalThread* thread = mono_thread_internal_current ();
4071
4072         g_assert (args);
4073
4074         pa [0] = args;
4075
4076         domain = mono_object_domain (args);
4077         if (!domain->entry_assembly) {
4078                 gchar *str;
4079                 MonoAssembly *assembly;
4080
4081                 assembly = method->klass->image->assembly;
4082                 domain->entry_assembly = assembly;
4083                 /* Domains created from another domain already have application_base and configuration_file set */
4084                 if (domain->setup->application_base == NULL) {
4085                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4086                 }
4087
4088                 if (domain->setup->configuration_file == NULL) {
4089                         str = g_strconcat (assembly->image->name, ".config", NULL);
4090                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4091                         g_free (str);
4092                         mono_set_private_bin_path_from_config (domain);
4093                 }
4094         }
4095
4096         cinfo = mono_custom_attrs_from_method (method);
4097         if (cinfo) {
4098                 static MonoClass *stathread_attribute = NULL;
4099                 if (!stathread_attribute)
4100                         stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4101                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4102                 if (!cinfo->cached)
4103                         mono_custom_attrs_free (cinfo);
4104         } else {
4105                 has_stathread_attribute = FALSE;
4106         }
4107         if (has_stathread_attribute) {
4108                 thread->apartment_state = ThreadApartmentState_STA;
4109         } else {
4110                 thread->apartment_state = ThreadApartmentState_MTA;
4111         }
4112         mono_thread_init_apartment_state ();
4113
4114         /* FIXME: check signature of method */
4115         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4116                 MonoObject *res;
4117                 res = mono_runtime_invoke (method, NULL, pa, exc);
4118                 if (!exc || !*exc)
4119                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4120                 else
4121                         rval = -1;
4122
4123                 mono_environment_exitcode_set (rval);
4124         } else {
4125                 mono_runtime_invoke (method, NULL, pa, exc);
4126                 if (!exc || !*exc)
4127                         rval = 0;
4128                 else {
4129                         /* If the return type of Main is void, only
4130                          * set the exitcode if an exception was thrown
4131                          * (we don't want to blow away an
4132                          * explicitly-set exit code)
4133                          */
4134                         rval = -1;
4135                         mono_environment_exitcode_set (rval);
4136                 }
4137         }
4138
4139         return rval;
4140 }
4141
4142 /**
4143  * mono_install_runtime_invoke:
4144  * @func: Function to install
4145  *
4146  * This is a VM internal routine
4147  */
4148 void
4149 mono_install_runtime_invoke (MonoInvokeFunc func)
4150 {
4151         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4152 }
4153
4154
4155 /**
4156  * mono_runtime_invoke_array:
4157  * @method: method to invoke
4158  * @obJ: object instance
4159  * @params: arguments to the method
4160  * @exc: exception information.
4161  *
4162  * Invokes the method represented by @method on the object @obj.
4163  *
4164  * obj is the 'this' pointer, it should be NULL for static
4165  * methods, a MonoObject* for object instances and a pointer to
4166  * the value type for value types.
4167  *
4168  * The params array contains the arguments to the method with the
4169  * same convention: MonoObject* pointers for object instances and
4170  * pointers to the value type otherwise. The _invoke_array
4171  * variant takes a C# object[] as the params argument (MonoArray
4172  * *params): in this case the value types are boxed inside the
4173  * respective reference representation.
4174  * 
4175  * From unmanaged code you'll usually use the
4176  * mono_runtime_invoke() variant.
4177  *
4178  * Note that this function doesn't handle virtual methods for
4179  * you, it will exec the exact method you pass: we still need to
4180  * expose a function to lookup the derived class implementation
4181  * of a virtual method (there are examples of this in the code,
4182  * though).
4183  * 
4184  * You can pass NULL as the exc argument if you don't want to
4185  * catch exceptions, otherwise, *exc will be set to the exception
4186  * thrown, if any.  if an exception is thrown, you can't use the
4187  * MonoObject* result from the function.
4188  * 
4189  * If the method returns a value type, it is boxed in an object
4190  * reference.
4191  */
4192 MonoObject*
4193 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4194                            MonoObject **exc)
4195 {
4196         MonoMethodSignature *sig = mono_method_signature (method);
4197         gpointer *pa = NULL;
4198         MonoObject *res;
4199         int i;
4200         gboolean has_byref_nullables = FALSE;
4201
4202         if (NULL != params) {
4203                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4204                 for (i = 0; i < mono_array_length (params); i++) {
4205                         MonoType *t = sig->params [i];
4206
4207                 again:
4208                         switch (t->type) {
4209                         case MONO_TYPE_U1:
4210                         case MONO_TYPE_I1:
4211                         case MONO_TYPE_BOOLEAN:
4212                         case MONO_TYPE_U2:
4213                         case MONO_TYPE_I2:
4214                         case MONO_TYPE_CHAR:
4215                         case MONO_TYPE_U:
4216                         case MONO_TYPE_I:
4217                         case MONO_TYPE_U4:
4218                         case MONO_TYPE_I4:
4219                         case MONO_TYPE_U8:
4220                         case MONO_TYPE_I8:
4221                         case MONO_TYPE_R4:
4222                         case MONO_TYPE_R8:
4223                         case MONO_TYPE_VALUETYPE:
4224                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4225                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4226                                         pa [i] = mono_array_get (params, MonoObject*, i);
4227                                         if (t->byref)
4228                                                 has_byref_nullables = TRUE;
4229                                 } else {
4230                                         /* MS seems to create the objects if a null is passed in */
4231                                         if (!mono_array_get (params, MonoObject*, i))
4232                                                 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
4233
4234                                         if (t->byref) {
4235                                                 /*
4236                                                  * We can't pass the unboxed vtype byref to the callee, since
4237                                                  * that would mean the callee would be able to modify boxed
4238                                                  * primitive types. So we (and MS) make a copy of the boxed
4239                                                  * object, pass that to the callee, and replace the original
4240                                                  * boxed object in the arg array with the copy.
4241                                                  */
4242                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4243                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4244                                                 mono_array_setref (params, i, copy);
4245                                         }
4246                                                 
4247                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4248                                 }
4249                                 break;
4250                         case MONO_TYPE_STRING:
4251                         case MONO_TYPE_OBJECT:
4252                         case MONO_TYPE_CLASS:
4253                         case MONO_TYPE_ARRAY:
4254                         case MONO_TYPE_SZARRAY:
4255                                 if (t->byref)
4256                                         pa [i] = mono_array_addr (params, MonoObject*, i);
4257                                         // FIXME: I need to check this code path
4258                                 else
4259                                         pa [i] = mono_array_get (params, MonoObject*, i);
4260                                 break;
4261                         case MONO_TYPE_GENERICINST:
4262                                 if (t->byref)
4263                                         t = &t->data.generic_class->container_class->this_arg;
4264                                 else
4265                                         t = &t->data.generic_class->container_class->byval_arg;
4266                                 goto again;
4267                         case MONO_TYPE_PTR: {
4268                                 MonoObject *arg;
4269
4270                                 /* The argument should be an IntPtr */
4271                                 arg = mono_array_get (params, MonoObject*, i);
4272                                 if (arg == NULL) {
4273                                         pa [i] = NULL;
4274                                 } else {
4275                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4276                                         pa [i] = ((MonoIntPtr*)arg)->m_value;
4277                                 }
4278                                 break;
4279                         }
4280                         default:
4281                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4282                         }
4283                 }
4284         }
4285
4286         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4287                 void *o = obj;
4288
4289                 if (mono_class_is_nullable (method->klass)) {
4290                         /* Need to create a boxed vtype instead */
4291                         g_assert (!obj);
4292
4293                         if (!params)
4294                                 return NULL;
4295                         else
4296                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4297                 }
4298
4299                 if (!obj) {
4300                         obj = mono_object_new (mono_domain_get (), method->klass);
4301                         g_assert (obj); /*maybe we should raise a TLE instead?*/
4302 #ifndef DISABLE_REMOTING
4303                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4304                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4305                         }
4306 #endif
4307                         if (method->klass->valuetype)
4308                                 o = mono_object_unbox (obj);
4309                         else
4310                                 o = obj;
4311                 } else if (method->klass->valuetype) {
4312                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
4313                 }
4314
4315                 mono_runtime_invoke (method, o, pa, exc);
4316                 return obj;
4317         } else {
4318                 if (mono_class_is_nullable (method->klass)) {
4319                         MonoObject *nullable;
4320
4321                         /* Convert the unboxed vtype into a Nullable structure */
4322                         nullable = mono_object_new (mono_domain_get (), method->klass);
4323
4324                         mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4325                         obj = mono_object_unbox (nullable);
4326                 }
4327
4328                 /* obj must be already unboxed if needed */
4329                 res = mono_runtime_invoke (method, obj, pa, exc);
4330
4331                 if (sig->ret->type == MONO_TYPE_PTR) {
4332                         MonoClass *pointer_class;
4333                         static MonoMethod *box_method;
4334                         void *box_args [2];
4335                         MonoObject *box_exc;
4336
4337                         /* 
4338                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
4339                          * convert it to a Pointer object.
4340                          */
4341                         pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4342                         if (!box_method)
4343                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4344
4345                         g_assert (res->vtable->klass == mono_defaults.int_class);
4346                         box_args [0] = ((MonoIntPtr*)res)->m_value;
4347                         box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4348                         res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4349                         g_assert (!box_exc);
4350                 }
4351
4352                 if (has_byref_nullables) {
4353                         /* 
4354                          * The runtime invoke wrapper already converted byref nullables back,
4355                          * and stored them in pa, we just need to copy them back to the
4356                          * managed array.
4357                          */
4358                         for (i = 0; i < mono_array_length (params); i++) {
4359                                 MonoType *t = sig->params [i];
4360
4361                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4362                                         mono_array_setref (params, i, pa [i]);
4363                         }
4364                 }
4365
4366                 return res;
4367         }
4368 }
4369
4370 static void
4371 arith_overflow (void)
4372 {
4373         mono_raise_exception (mono_get_exception_overflow ());
4374 }
4375
4376 /**
4377  * mono_object_allocate:
4378  * @size: number of bytes to allocate
4379  *
4380  * This is a very simplistic routine until we have our GC-aware
4381  * memory allocator. 
4382  *
4383  * Returns: an allocated object of size @size, or NULL on failure.
4384  */
4385 static inline void *
4386 mono_object_allocate (size_t size, MonoVTable *vtable)
4387 {
4388         MonoObject *o;
4389         ALLOC_OBJECT (o, vtable, size);
4390
4391         return o;
4392 }
4393
4394 #ifndef HAVE_SGEN_GC
4395 /**
4396  * mono_object_allocate_ptrfree:
4397  * @size: number of bytes to allocate
4398  *
4399  * Note that the memory allocated is not zeroed.
4400  * Returns: an allocated object of size @size, or NULL on failure.
4401  */
4402 static inline void *
4403 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4404 {
4405         MonoObject *o;
4406         ALLOC_PTRFREE (o, vtable, size);
4407         return o;
4408 }
4409 #endif
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 *s, *res;
5459         MonoDomain *domain;
5460         
5461         domain = ((MonoObject *)str)->vtable->domain;
5462         ldstr_table = domain->ldstr_table;
5463         ldstr_lock ();
5464         res = mono_g_hash_table_lookup (ldstr_table, str);
5465         if (res) {
5466                 ldstr_unlock ();
5467                 return res;
5468         }
5469         if (insert) {
5470                 /* Allocate outside the lock */
5471                 ldstr_unlock ();
5472                 s = mono_string_get_pinned (str);
5473                 if (s) {
5474                         ldstr_lock ();
5475                         res = mono_g_hash_table_lookup (ldstr_table, str);
5476                         if (res) {
5477                                 ldstr_unlock ();
5478                                 return res;
5479                         }
5480                         mono_g_hash_table_insert (ldstr_table, s, s);
5481                         ldstr_unlock ();
5482                 }
5483                 return s;
5484         } else {
5485                 LDStrInfo ldstr_info;
5486                 ldstr_info.orig_domain = domain;
5487                 ldstr_info.ins = str;
5488                 ldstr_info.res = NULL;
5489
5490                 mono_domain_foreach (str_lookup, &ldstr_info);
5491                 if (ldstr_info.res) {
5492                         /* 
5493                          * the string was already interned in some other domain:
5494                          * intern it in the current one as well.
5495                          */
5496                         mono_g_hash_table_insert (ldstr_table, str, str);
5497                         ldstr_unlock ();
5498                         return str;
5499                 }
5500         }
5501         ldstr_unlock ();
5502         return NULL;
5503 }
5504
5505 /**
5506  * mono_string_is_interned:
5507  * @o: String to probe
5508  *
5509  * Returns whether the string has been interned.
5510  */
5511 MonoString*
5512 mono_string_is_interned (MonoString *o)
5513 {
5514         return mono_string_is_interned_lookup (o, FALSE);
5515 }
5516
5517 /**
5518  * mono_string_intern:
5519  * @o: String to intern
5520  *
5521  * Interns the string passed.  
5522  * Returns: The interned string.
5523  */
5524 MonoString*
5525 mono_string_intern (MonoString *str)
5526 {
5527         return mono_string_is_interned_lookup (str, TRUE);
5528 }
5529
5530 /**
5531  * mono_ldstr:
5532  * @domain: the domain where the string will be used.
5533  * @image: a metadata context
5534  * @idx: index into the user string table.
5535  * 
5536  * Implementation for the ldstr opcode.
5537  * Returns: a loaded string from the @image/@idx combination.
5538  */
5539 MonoString*
5540 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5541 {
5542         if (image->dynamic) {
5543                 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5544                 return str;
5545         } else {
5546                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5547                         return NULL; /*FIXME we should probably be raising an exception here*/
5548                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5549         }
5550 }
5551
5552 /**
5553  * mono_ldstr_metadata_sig
5554  * @domain: the domain for the string
5555  * @sig: the signature of a metadata string
5556  *
5557  * Returns: a MonoString for a string stored in the metadata
5558  */
5559 static MonoString*
5560 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5561 {
5562         const char *str = sig;
5563         MonoString *o, *interned;
5564         size_t len2;
5565
5566         len2 = mono_metadata_decode_blob_size (str, &str);
5567         len2 >>= 1;
5568
5569         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5570 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5571         {
5572                 int i;
5573                 guint16 *p2 = (guint16*)mono_string_chars (o);
5574                 for (i = 0; i < len2; ++i) {
5575                         *p2 = GUINT16_FROM_LE (*p2);
5576                         ++p2;
5577                 }
5578         }
5579 #endif
5580         ldstr_lock ();
5581         if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5582                 ldstr_unlock ();
5583                 /* o will get garbage collected */
5584                 return interned;
5585         }
5586
5587         o = mono_string_get_pinned (o);
5588         if (o)
5589                 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5590         ldstr_unlock ();
5591
5592         return o;
5593 }
5594
5595 /**
5596  * mono_string_to_utf8:
5597  * @s: a System.String
5598  *
5599  * Returns the UTF8 representation for @s.
5600  * The resulting buffer needs to be freed with mono_free().
5601  *
5602  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5603  */
5604 char *
5605 mono_string_to_utf8 (MonoString *s)
5606 {
5607         MonoError error;
5608         char *result = mono_string_to_utf8_checked (s, &error);
5609         
5610         if (!mono_error_ok (&error))
5611                 mono_error_raise_exception (&error);
5612         return result;
5613 }
5614
5615 /**
5616  * mono_string_to_utf8_checked:
5617  * @s: a System.String
5618  * @error: a MonoError.
5619  * 
5620  * Converts a MonoString to its UTF8 representation. May fail; check 
5621  * @error to determine whether the conversion was successful.
5622  * The resulting buffer should be freed with mono_free().
5623  */
5624 char *
5625 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5626 {
5627         long written = 0;
5628         char *as;
5629         GError *gerror = NULL;
5630
5631         mono_error_init (error);
5632
5633         if (s == NULL)
5634                 return NULL;
5635
5636         if (!s->length)
5637                 return g_strdup ("");
5638
5639         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5640         if (gerror) {
5641                 mono_error_set_argument (error, "string", "%s", gerror->message);
5642                 g_error_free (gerror);
5643                 return NULL;
5644         }
5645         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5646         if (s->length > written) {
5647                 /* allocate the total length and copy the part of the string that has been converted */
5648                 char *as2 = g_malloc0 (s->length);
5649                 memcpy (as2, as, written);
5650                 g_free (as);
5651                 as = as2;
5652         }
5653
5654         return as;
5655 }
5656
5657 /**
5658  * mono_string_to_utf8_ignore:
5659  * @s: a MonoString
5660  *
5661  * Converts a MonoString to its UTF8 representation. Will ignore
5662  * invalid surrogate pairs.
5663  * The resulting buffer should be freed with mono_free().
5664  * 
5665  */
5666 char *
5667 mono_string_to_utf8_ignore (MonoString *s)
5668 {
5669         long written = 0;
5670         char *as;
5671
5672         if (s == NULL)
5673                 return NULL;
5674
5675         if (!s->length)
5676                 return g_strdup ("");
5677
5678         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5679
5680         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5681         if (s->length > written) {
5682                 /* allocate the total length and copy the part of the string that has been converted */
5683                 char *as2 = g_malloc0 (s->length);
5684                 memcpy (as2, as, written);
5685                 g_free (as);
5686                 as = as2;
5687         }
5688
5689         return as;
5690 }
5691
5692 /**
5693  * mono_string_to_utf8_image_ignore:
5694  * @s: a System.String
5695  *
5696  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5697  */
5698 char *
5699 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5700 {
5701         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5702 }
5703
5704 /**
5705  * mono_string_to_utf8_mp_ignore:
5706  * @s: a System.String
5707  *
5708  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5709  */
5710 char *
5711 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5712 {
5713         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5714 }
5715
5716
5717 /**
5718  * mono_string_to_utf16:
5719  * @s: a MonoString
5720  *
5721  * Return an null-terminated array of the utf-16 chars
5722  * contained in @s. The result must be freed with g_free().
5723  * This is a temporary helper until our string implementation
5724  * is reworked to always include the null terminating char.
5725  */
5726 mono_unichar2*
5727 mono_string_to_utf16 (MonoString *s)
5728 {
5729         char *as;
5730
5731         if (s == NULL)
5732                 return NULL;
5733
5734         as = g_malloc ((s->length * 2) + 2);
5735         as [(s->length * 2)] = '\0';
5736         as [(s->length * 2) + 1] = '\0';
5737
5738         if (!s->length) {
5739                 return (gunichar2 *)(as);
5740         }
5741         
5742         memcpy (as, mono_string_chars(s), s->length * 2);
5743         return (gunichar2 *)(as);
5744 }
5745
5746 /**
5747  * mono_string_to_utf32:
5748  * @s: a MonoString
5749  *
5750  * Return an null-terminated array of the UTF-32 (UCS-4) chars
5751  * contained in @s. The result must be freed with g_free().
5752  */
5753 mono_unichar4*
5754 mono_string_to_utf32 (MonoString *s)
5755 {
5756         mono_unichar4 *utf32_output = NULL; 
5757         GError *error = NULL;
5758         glong items_written;
5759         
5760         if (s == NULL)
5761                 return NULL;
5762                 
5763         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5764         
5765         if (error)
5766                 g_error_free (error);
5767
5768         return utf32_output;
5769 }
5770
5771 /**
5772  * mono_string_from_utf16:
5773  * @data: the UTF16 string (LPWSTR) to convert
5774  *
5775  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5776  *
5777  * Returns: a MonoString.
5778  */
5779 MonoString *
5780 mono_string_from_utf16 (gunichar2 *data)
5781 {
5782         MonoDomain *domain = mono_domain_get ();
5783         int len = 0;
5784
5785         if (!data)
5786                 return NULL;
5787
5788         while (data [len]) len++;
5789
5790         return mono_string_new_utf16 (domain, data, len);
5791 }
5792
5793 /**
5794  * mono_string_from_utf32:
5795  * @data: the UTF32 string (LPWSTR) to convert
5796  *
5797  * Converts a UTF32 (UCS-4)to a MonoString.
5798  *
5799  * Returns: a MonoString.
5800  */
5801 MonoString *
5802 mono_string_from_utf32 (mono_unichar4 *data)
5803 {
5804         MonoString* result = NULL;
5805         mono_unichar2 *utf16_output = NULL;
5806         GError *error = NULL;
5807         glong items_written;
5808         int len = 0;
5809
5810         if (!data)
5811                 return NULL;
5812
5813         while (data [len]) len++;
5814
5815         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5816
5817         if (error)
5818                 g_error_free (error);
5819
5820         result = mono_string_from_utf16 (utf16_output);
5821         g_free (utf16_output);
5822         return result;
5823 }
5824
5825 static char *
5826 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5827 {
5828         char *r;
5829         char *mp_s;
5830         int len;
5831
5832         if (ignore_error) {
5833                 r = mono_string_to_utf8_ignore (s);
5834         } else {
5835                 r = mono_string_to_utf8_checked (s, error);
5836                 if (!mono_error_ok (error))
5837                         return NULL;
5838         }
5839
5840         if (!mp && !image)
5841                 return r;
5842
5843         len = strlen (r) + 1;
5844         if (mp)
5845                 mp_s = mono_mempool_alloc (mp, len);
5846         else
5847                 mp_s = mono_image_alloc (image, len);
5848
5849         memcpy (mp_s, r, len);
5850
5851         g_free (r);
5852
5853         return mp_s;
5854 }
5855
5856 /**
5857  * mono_string_to_utf8_image:
5858  * @s: a System.String
5859  *
5860  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5861  */
5862 char *
5863 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5864 {
5865         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5866 }
5867
5868 /**
5869  * mono_string_to_utf8_mp:
5870  * @s: a System.String
5871  *
5872  * Same as mono_string_to_utf8, but allocate the string from a mempool.
5873  */
5874 char *
5875 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5876 {
5877         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5878 }
5879
5880
5881 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5882
5883 void
5884 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5885 {
5886         eh_callbacks = *cbs;
5887 }
5888
5889 MonoRuntimeExceptionHandlingCallbacks *
5890 mono_get_eh_callbacks (void)
5891 {
5892         return &eh_callbacks;
5893 }
5894
5895 /**
5896  * mono_raise_exception:
5897  * @ex: exception object
5898  *
5899  * Signal the runtime that the exception @ex has been raised in unmanaged code.
5900  */
5901 void
5902 mono_raise_exception (MonoException *ex) 
5903 {
5904         /*
5905          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5906          * that will cause gcc to omit the function epilog, causing problems when
5907          * the JIT tries to walk the stack, since the return address on the stack
5908          * will point into the next function in the executable, not this one.
5909          */     
5910         eh_callbacks.mono_raise_exception (ex);
5911 }
5912
5913 void
5914 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
5915 {
5916         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5917 }
5918
5919 /**
5920  * mono_wait_handle_new:
5921  * @domain: Domain where the object will be created
5922  * @handle: Handle for the wait handle
5923  *
5924  * Returns: A new MonoWaitHandle created in the given domain for the given handle
5925  */
5926 MonoWaitHandle *
5927 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5928 {
5929         MonoWaitHandle *res;
5930         gpointer params [1];
5931         static MonoMethod *handle_set;
5932
5933         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5934
5935         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
5936         if (!handle_set)
5937                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5938
5939         params [0] = &handle;
5940         mono_runtime_invoke (handle_set, res, params, NULL);
5941
5942         return res;
5943 }
5944
5945 HANDLE
5946 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5947 {
5948         static MonoClassField *f_os_handle;
5949         static MonoClassField *f_safe_handle;
5950
5951         if (!f_os_handle && !f_safe_handle) {
5952                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5953                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5954         }
5955
5956         if (f_os_handle) {
5957                 HANDLE retval;
5958                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5959                 return retval;
5960         } else {
5961                 MonoSafeHandle *sh;
5962                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5963                 return sh->handle;
5964         }
5965 }
5966
5967
5968 static MonoObject*
5969 mono_runtime_capture_context (MonoDomain *domain)
5970 {
5971         RuntimeInvokeFunction runtime_invoke;
5972
5973         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5974                 MonoMethod *method = mono_get_context_capture_method ();
5975                 MonoMethod *wrapper;
5976                 if (!method)
5977                         return NULL;
5978                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5979                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5980                 domain->capture_context_method = mono_compile_method (method);
5981         }
5982
5983         runtime_invoke = domain->capture_context_runtime_invoke;
5984
5985         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5986 }
5987 /**
5988  * mono_async_result_new:
5989  * @domain:domain where the object will be created.
5990  * @handle: wait handle.
5991  * @state: state to pass to AsyncResult
5992  * @data: C closure data.
5993  *
5994  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5995  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5996  *
5997  */
5998 MonoAsyncResult *
5999 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6000 {
6001         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6002         MonoObject *context = mono_runtime_capture_context (domain);
6003         /* we must capture the execution context from the original thread */
6004         if (context) {
6005                 MONO_OBJECT_SETREF (res, execution_context, context);
6006                 /* note: result may be null if the flow is suppressed */
6007         }
6008
6009         res->data = data;
6010         MONO_OBJECT_SETREF (res, object_data, object_data);
6011         MONO_OBJECT_SETREF (res, async_state, state);
6012         if (handle != NULL)
6013                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6014
6015         res->sync_completed = FALSE;
6016         res->completed = FALSE;
6017
6018         return res;
6019 }
6020
6021 void
6022 mono_message_init (MonoDomain *domain,
6023                    MonoMethodMessage *this, 
6024                    MonoReflectionMethod *method,
6025                    MonoArray *out_args)
6026 {
6027         static MonoClass *object_array_klass;
6028         static MonoClass *byte_array_klass;
6029         static MonoClass *string_array_klass;
6030         MonoMethodSignature *sig = mono_method_signature (method->method);
6031         MonoString *name;
6032         int i, j;
6033         char **names;
6034         guint8 arg_type;
6035
6036         if (!object_array_klass) {
6037                 MonoClass *klass;
6038
6039                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6040                 g_assert (klass);
6041                 byte_array_klass = klass;
6042
6043                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6044                 g_assert (klass);
6045                 string_array_klass = klass;
6046
6047                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6048                 g_assert (klass);
6049
6050                 mono_atomic_store_release (&object_array_klass, klass);
6051         }
6052
6053         MONO_OBJECT_SETREF (this, method, method);
6054
6055         MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6056         MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6057         this->async_result = NULL;
6058         this->call_type = CallType_Sync;
6059
6060         names = g_new (char *, sig->param_count);
6061         mono_method_get_param_names (method->method, (const char **) names);
6062         MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6063         
6064         for (i = 0; i < sig->param_count; i++) {
6065                 name = mono_string_new (domain, names [i]);
6066                 mono_array_setref (this->names, i, name);       
6067         }
6068
6069         g_free (names);
6070         for (i = 0, j = 0; i < sig->param_count; i++) {
6071                 if (sig->params [i]->byref) {
6072                         if (out_args) {
6073                                 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6074                                 mono_array_setref (this->args, i, arg);
6075                                 j++;
6076                         }
6077                         arg_type = 2;
6078                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6079                                 arg_type |= 1;
6080                 } else {
6081                         arg_type = 1;
6082                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6083                                 arg_type |= 4;
6084                 }
6085                 mono_array_set (this->arg_types, guint8, i, arg_type);
6086         }
6087 }
6088
6089 #ifndef DISABLE_REMOTING
6090 /**
6091  * mono_remoting_invoke:
6092  * @real_proxy: pointer to a RealProxy object
6093  * @msg: The MonoMethodMessage to execute
6094  * @exc: used to store exceptions
6095  * @out_args: used to store output arguments
6096  *
6097  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6098  * IMessage interface and it is not trivial to extract results from there. So
6099  * we call an helper method PrivateInvoke instead of calling
6100  * RealProxy::Invoke() directly.
6101  *
6102  * Returns: the result object.
6103  */
6104 MonoObject *
6105 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
6106                       MonoObject **exc, MonoArray **out_args)
6107 {
6108         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6109         gpointer pa [4];
6110
6111         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6112
6113         if (!im) {
6114                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6115                 g_assert (im);
6116                 real_proxy->vtable->domain->private_invoke_method = im;
6117         }
6118
6119         pa [0] = real_proxy;
6120         pa [1] = msg;
6121         pa [2] = exc;
6122         pa [3] = out_args;
6123
6124         return mono_runtime_invoke (im, NULL, pa, exc);
6125 }
6126 #endif
6127
6128 MonoObject *
6129 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6130                      MonoObject **exc, MonoArray **out_args) 
6131 {
6132         static MonoClass *object_array_klass;
6133         MonoDomain *domain; 
6134         MonoMethod *method;
6135         MonoMethodSignature *sig;
6136         MonoObject *ret;
6137         int i, j, outarg_count = 0;
6138
6139 #ifndef DISABLE_REMOTING
6140         if (target && mono_object_is_transparent_proxy (target)) {
6141                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6142                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6143                         target = tp->rp->unwrapped_server;
6144                 } else {
6145                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6146                 }
6147         }
6148 #endif
6149
6150         domain = mono_domain_get (); 
6151         method = msg->method->method;
6152         sig = mono_method_signature (method);
6153
6154         for (i = 0; i < sig->param_count; i++) {
6155                 if (sig->params [i]->byref) 
6156                         outarg_count++;
6157         }
6158
6159         if (!object_array_klass) {
6160                 MonoClass *klass;
6161
6162                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6163                 g_assert (klass);
6164
6165                 mono_memory_barrier ();
6166                 object_array_klass = klass;
6167         }
6168
6169         /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6170         *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6171         *exc = NULL;
6172
6173         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6174
6175         for (i = 0, j = 0; i < sig->param_count; i++) {
6176                 if (sig->params [i]->byref) {
6177                         MonoObject* arg;
6178                         arg = mono_array_get (msg->args, gpointer, i);
6179                         mono_array_setref (*out_args, j, arg);
6180                         j++;
6181                 }
6182         }
6183
6184         return ret;
6185 }
6186
6187 /**
6188  * mono_object_to_string:
6189  * @obj: The object
6190  * @exc: Any exception thrown by ToString (). May be NULL.
6191  *
6192  * Returns: the result of calling ToString () on an object.
6193  */
6194 MonoString *
6195 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6196 {
6197         static MonoMethod *to_string = NULL;
6198         MonoMethod *method;
6199         void *target = obj;
6200
6201         g_assert (obj);
6202
6203         if (!to_string)
6204                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6205
6206         method = mono_object_get_virtual_method (obj, to_string);
6207
6208         // Unbox value type if needed
6209         if (mono_class_is_valuetype (mono_method_get_class (method))) {
6210                 target = mono_object_unbox (obj);
6211         }
6212
6213         return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6214 }
6215
6216 /**
6217  * mono_print_unhandled_exception:
6218  * @exc: The exception
6219  *
6220  * Prints the unhandled exception.
6221  */
6222 void
6223 mono_print_unhandled_exception (MonoObject *exc)
6224 {
6225         MonoString * str;
6226         char *message = (char*)"";
6227         gboolean free_message = FALSE;
6228         MonoError error;
6229
6230         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6231                 message = g_strdup ("OutOfMemoryException");
6232                 free_message = TRUE;
6233         } else {
6234                 
6235                 if (((MonoException*)exc)->native_trace_ips) {
6236                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
6237                         free_message = TRUE;
6238                 } else {
6239                         MonoObject *other_exc = NULL;
6240                         str = mono_object_to_string (exc, &other_exc);
6241                         if (other_exc) {
6242                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6243                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6244                                 
6245                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6246                                         original_backtrace, nested_backtrace);
6247
6248                                 g_free (original_backtrace);
6249                                 g_free (nested_backtrace);
6250                                 free_message = TRUE;
6251                         } else if (str) {
6252                                 message = mono_string_to_utf8_checked (str, &error);
6253                                 if (!mono_error_ok (&error)) {
6254                                         mono_error_cleanup (&error);
6255                                         message = (char *) "";
6256                                 } else {
6257                                         free_message = TRUE;
6258                                 }
6259                         }
6260                 }
6261         }
6262
6263         /*
6264          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
6265          *         exc->vtable->klass->name, message);
6266          */
6267         g_printerr ("\nUnhandled Exception:\n%s\n", message);
6268         
6269         if (free_message)
6270                 g_free (message);
6271 }
6272
6273 /**
6274  * mono_delegate_ctor:
6275  * @this: pointer to an uninitialized delegate object
6276  * @target: target object
6277  * @addr: pointer to native code
6278  * @method: method
6279  *
6280  * Initialize a delegate and sets a specific method, not the one
6281  * associated with addr.  This is useful when sharing generic code.
6282  * In that case addr will most probably not be associated with the
6283  * correct instantiation of the method.
6284  */
6285 void
6286 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6287 {
6288         MonoDelegate *delegate = (MonoDelegate *)this;
6289
6290         g_assert (this);
6291         g_assert (addr);
6292
6293         if (method)
6294                 delegate->method = method;
6295
6296         mono_stats.delegate_creations++;
6297
6298 #ifndef DISABLE_REMOTING
6299         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6300                 g_assert (method);
6301                 method = mono_marshal_get_remoting_invoke (method);
6302                 delegate->method_ptr = mono_compile_method (method);
6303                 MONO_OBJECT_SETREF (delegate, target, target);
6304         } else
6305 #endif
6306         {
6307                 delegate->method_ptr = addr;
6308                 MONO_OBJECT_SETREF (delegate, target, target);
6309         }
6310
6311         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6312 }
6313
6314 /**
6315  * mono_delegate_ctor:
6316  * @this: pointer to an uninitialized delegate object
6317  * @target: target object
6318  * @addr: pointer to native code
6319  *
6320  * This is used to initialize a delegate.
6321  */
6322 void
6323 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6324 {
6325         MonoDomain *domain = mono_domain_get ();
6326         MonoJitInfo *ji;
6327         MonoMethod *method = NULL;
6328
6329         g_assert (addr);
6330
6331         ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6332         /* Shared code */
6333         if (!ji && domain != mono_get_root_domain ())
6334                 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6335         if (ji) {
6336                 method = mono_jit_info_get_method (ji);
6337                 g_assert (!method->klass->generic_container);
6338         }
6339
6340         mono_delegate_ctor_with_method (this, target, addr, method);
6341 }
6342
6343 /**
6344  * mono_method_call_message_new:
6345  * @method: method to encapsulate
6346  * @params: parameters to the method
6347  * @invoke: optional, delegate invoke.
6348  * @cb: async callback delegate.
6349  * @state: state passed to the async callback.
6350  *
6351  * Translates arguments pointers into a MonoMethodMessage.
6352  */
6353 MonoMethodMessage *
6354 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
6355                               MonoDelegate **cb, MonoObject **state)
6356 {
6357         MonoDomain *domain = mono_domain_get ();
6358         MonoMethodSignature *sig = mono_method_signature (method);
6359         MonoMethodMessage *msg;
6360         int i, count;
6361
6362         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
6363         
6364         if (invoke) {
6365                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6366                 count =  sig->param_count - 2;
6367         } else {
6368                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6369                 count =  sig->param_count;
6370         }
6371
6372         for (i = 0; i < count; i++) {
6373                 gpointer vpos;
6374                 MonoClass *class;
6375                 MonoObject *arg;
6376
6377                 if (sig->params [i]->byref)
6378                         vpos = *((gpointer *)params [i]);
6379                 else 
6380                         vpos = params [i];
6381
6382                 class = mono_class_from_mono_type (sig->params [i]);
6383
6384                 if (class->valuetype)
6385                         arg = mono_value_box (domain, class, vpos);
6386                 else 
6387                         arg = *((MonoObject **)vpos);
6388                       
6389                 mono_array_setref (msg->args, i, arg);
6390         }
6391
6392         if (cb != NULL && state != NULL) {
6393                 *cb = *((MonoDelegate **)params [i]);
6394                 i++;
6395                 *state = *((MonoObject **)params [i]);
6396         }
6397
6398         return msg;
6399 }
6400
6401 /**
6402  * mono_method_return_message_restore:
6403  *
6404  * Restore results from message based processing back to arguments pointers
6405  */
6406 void
6407 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6408 {
6409         MonoMethodSignature *sig = mono_method_signature (method);
6410         int i, j, type, size, out_len;
6411         
6412         if (out_args == NULL)
6413                 return;
6414         out_len = mono_array_length (out_args);
6415         if (out_len == 0)
6416                 return;
6417
6418         for (i = 0, j = 0; i < sig->param_count; i++) {
6419                 MonoType *pt = sig->params [i];
6420
6421                 if (pt->byref) {
6422                         char *arg;
6423                         if (j >= out_len)
6424                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6425
6426                         arg = mono_array_get (out_args, gpointer, j);
6427                         type = pt->type;
6428
6429                         g_assert (type != MONO_TYPE_VOID);
6430
6431                         if (MONO_TYPE_IS_REFERENCE (pt)) {
6432                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6433                         } else {
6434                                 if (arg) {
6435                                         MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6436                                         size = mono_class_value_size (class, NULL);
6437                                         if (class->has_references)
6438                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6439                                         else
6440                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6441                                 } else {
6442                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6443                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6444                                 }
6445                         }
6446
6447                         j++;
6448                 }
6449         }
6450 }
6451
6452 #ifndef DISABLE_REMOTING
6453
6454 /**
6455  * mono_load_remote_field:
6456  * @this: pointer to an object
6457  * @klass: klass of the object containing @field
6458  * @field: the field to load
6459  * @res: a storage to store the result
6460  *
6461  * This method is called by the runtime on attempts to load fields of
6462  * transparent proxy objects. @this points to such TP, @klass is the class of
6463  * the object containing @field. @res is a storage location which can be
6464  * used to store the result.
6465  *
6466  * Returns: an address pointing to the value of field.
6467  */
6468 gpointer
6469 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6470 {
6471         static MonoMethod *getter = NULL;
6472         MonoDomain *domain = mono_domain_get ();
6473         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6474         MonoClass *field_class;
6475         MonoMethodMessage *msg;
6476         MonoArray *out_args;
6477         MonoObject *exc;
6478         char* full_name;
6479
6480         g_assert (mono_object_is_transparent_proxy (this));
6481         g_assert (res != NULL);
6482
6483         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6484                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6485                 return res;
6486         }
6487         
6488         if (!getter) {
6489                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6490                 g_assert (getter);
6491         }
6492         
6493         field_class = mono_class_from_mono_type (field->type);
6494
6495         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6496         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6497         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6498
6499         full_name = mono_type_get_full_name (klass);
6500         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6501         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6502         g_free (full_name);
6503
6504         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6505
6506         if (exc) mono_raise_exception ((MonoException *)exc);
6507
6508         if (mono_array_length (out_args) == 0)
6509                 return NULL;
6510
6511         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6512
6513         if (field_class->valuetype) {
6514                 return ((char *)*res) + sizeof (MonoObject);
6515         } else
6516                 return res;
6517 }
6518
6519 /**
6520  * mono_load_remote_field_new:
6521  * @this: 
6522  * @klass: 
6523  * @field:
6524  *
6525  * Missing documentation.
6526  */
6527 MonoObject *
6528 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6529 {
6530         static MonoMethod *getter = NULL;
6531         MonoDomain *domain = mono_domain_get ();
6532         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6533         MonoClass *field_class;
6534         MonoMethodMessage *msg;
6535         MonoArray *out_args;
6536         MonoObject *exc, *res;
6537         char* full_name;
6538
6539         g_assert (mono_object_is_transparent_proxy (this));
6540
6541         field_class = mono_class_from_mono_type (field->type);
6542
6543         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6544                 gpointer val;
6545                 if (field_class->valuetype) {
6546                         res = mono_object_new (domain, field_class);
6547                         val = ((gchar *) res) + sizeof (MonoObject);
6548                 } else {
6549                         val = &res;
6550                 }
6551                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6552                 return res;
6553         }
6554
6555         if (!getter) {
6556                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6557                 g_assert (getter);
6558         }
6559         
6560         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6561         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6562
6563         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6564
6565         full_name = mono_type_get_full_name (klass);
6566         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6567         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6568         g_free (full_name);
6569
6570         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6571
6572         if (exc) mono_raise_exception ((MonoException *)exc);
6573
6574         if (mono_array_length (out_args) == 0)
6575                 res = NULL;
6576         else
6577                 res = mono_array_get (out_args, MonoObject *, 0);
6578
6579         return res;
6580 }
6581
6582 /**
6583  * mono_store_remote_field:
6584  * @this: pointer to an object
6585  * @klass: klass of the object containing @field
6586  * @field: the field to load
6587  * @val: the value/object to store
6588  *
6589  * This method is called by the runtime on attempts to store fields of
6590  * transparent proxy objects. @this points to such TP, @klass is the class of
6591  * the object containing @field. @val is the new value to store in @field.
6592  */
6593 void
6594 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6595 {
6596         static MonoMethod *setter = NULL;
6597         MonoDomain *domain = mono_domain_get ();
6598         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6599         MonoClass *field_class;
6600         MonoMethodMessage *msg;
6601         MonoArray *out_args;
6602         MonoObject *exc;
6603         MonoObject *arg;
6604         char* full_name;
6605
6606         g_assert (mono_object_is_transparent_proxy (this));
6607
6608         field_class = mono_class_from_mono_type (field->type);
6609
6610         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6611                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6612                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6613                 return;
6614         }
6615
6616         if (!setter) {
6617                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6618                 g_assert (setter);
6619         }
6620
6621         if (field_class->valuetype)
6622                 arg = mono_value_box (domain, field_class, val);
6623         else 
6624                 arg = *((MonoObject **)val);
6625                 
6626
6627         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6628         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6629
6630         full_name = mono_type_get_full_name (klass);
6631         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6632         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6633         mono_array_setref (msg->args, 2, arg);
6634         g_free (full_name);
6635
6636         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6637
6638         if (exc) mono_raise_exception ((MonoException *)exc);
6639 }
6640
6641 /**
6642  * mono_store_remote_field_new:
6643  * @this:
6644  * @klass:
6645  * @field:
6646  * @arg:
6647  *
6648  * Missing documentation
6649  */
6650 void
6651 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6652 {
6653         static MonoMethod *setter = NULL;
6654         MonoDomain *domain = mono_domain_get ();
6655         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6656         MonoClass *field_class;
6657         MonoMethodMessage *msg;
6658         MonoArray *out_args;
6659         MonoObject *exc;
6660         char* full_name;
6661
6662         g_assert (mono_object_is_transparent_proxy (this));
6663
6664         field_class = mono_class_from_mono_type (field->type);
6665
6666         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6667                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6668                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6669                 return;
6670         }
6671
6672         if (!setter) {
6673                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6674                 g_assert (setter);
6675         }
6676
6677         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6678         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6679
6680         full_name = mono_type_get_full_name (klass);
6681         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6682         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6683         mono_array_setref (msg->args, 2, arg);
6684         g_free (full_name);
6685
6686         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6687
6688         if (exc) mono_raise_exception ((MonoException *)exc);
6689 }
6690 #endif
6691
6692 /*
6693  * mono_create_ftnptr:
6694  *
6695  *   Given a function address, create a function descriptor for it.
6696  * This is only needed on some platforms.
6697  */
6698 gpointer
6699 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6700 {
6701         return callbacks.create_ftnptr (domain, addr);
6702 }
6703
6704 /*
6705  * mono_get_addr_from_ftnptr:
6706  *
6707  *   Given a pointer to a function descriptor, return the function address.
6708  * This is only needed on some platforms.
6709  */
6710 gpointer
6711 mono_get_addr_from_ftnptr (gpointer descr)
6712 {
6713         return callbacks.get_addr_from_ftnptr (descr);
6714 }       
6715
6716 /**
6717  * mono_string_chars:
6718  * @s: a MonoString
6719  *
6720  * Returns a pointer to the UCS16 characters stored in the MonoString
6721  */
6722 gunichar2 *
6723 mono_string_chars (MonoString *s)
6724 {
6725         return s->chars;
6726 }
6727
6728 /**
6729  * mono_string_length:
6730  * @s: MonoString
6731  *
6732  * Returns the lenght in characters of the string
6733  */
6734 int
6735 mono_string_length (MonoString *s)
6736 {
6737         return s->length;
6738 }
6739
6740 /**
6741  * mono_array_length:
6742  * @array: a MonoArray*
6743  *
6744  * Returns the total number of elements in the array. This works for
6745  * both vectors and multidimensional arrays.
6746  */
6747 uintptr_t
6748 mono_array_length (MonoArray *array)
6749 {
6750         return array->max_length;
6751 }
6752
6753 /**
6754  * mono_array_addr_with_size:
6755  * @array: a MonoArray*
6756  * @size: size of the array elements
6757  * @idx: index into the array
6758  *
6759  * Returns the address of the @idx element in the array.
6760  */
6761 char*
6762 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6763 {
6764         return ((char*)(array)->vector) + size * idx;
6765 }
6766