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