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