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