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