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