Merge pull request #2494 from nealef/master
[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 (ves_icall_object_new_fast, "ves_icall_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
4504         MonoError error;
4505         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4506         mono_error_raise_exception (&error); /* FIXME don't raise here */
4507
4508         return o;
4509 }
4510
4511 /**
4512  * mono_object_new_pinned:
4513  *
4514  *   Same as mono_object_new, but the returned object will be pinned.
4515  * For SGEN, these objects will only be freed at appdomain unload.
4516  */
4517 MonoObject *
4518 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4519 {
4520         MONO_REQ_GC_UNSAFE_MODE;
4521
4522         MonoVTable *vtable;
4523
4524         vtable = mono_class_vtable (domain, klass);
4525         if (!vtable)
4526                 return NULL;
4527
4528         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4529
4530         if (G_UNLIKELY (!o))
4531                 mono_gc_out_of_memory (mono_class_instance_size (klass));
4532         else if (G_UNLIKELY (vtable->klass->has_finalize))
4533                 mono_object_register_finalizer (o);
4534
4535         return o;
4536 }
4537
4538 /**
4539  * mono_object_new_specific:
4540  * @vtable: the vtable of the object that we want to create
4541  *
4542  * Returns: A newly created object with class and domain specified
4543  * by @vtable
4544  */
4545 MonoObject *
4546 mono_object_new_specific (MonoVTable *vtable)
4547 {
4548         MonoError error;
4549         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4550         mono_error_raise_exception (&error);
4551
4552         return o;
4553 }
4554
4555 MonoObject *
4556 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4557 {
4558         MONO_REQ_GC_UNSAFE_MODE;
4559
4560         MonoObject *o;
4561
4562         mono_error_init (error);
4563
4564         /* check for is_com_object for COM Interop */
4565         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4566         {
4567                 gpointer pa [1];
4568                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4569
4570                 if (im == NULL) {
4571                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4572
4573                         if (!klass->inited)
4574                                 mono_class_init (klass);
4575
4576                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4577                         if (!im) {
4578                                 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4579                                 return NULL;
4580                         }
4581                         vtable->domain->create_proxy_for_type_method = im;
4582                 }
4583         
4584                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4585
4586                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
4587                 if (o != NULL) return o;
4588         }
4589
4590         return mono_object_new_alloc_specific_checked (vtable, error);
4591 }
4592
4593 MonoObject *
4594 ves_icall_object_new_specific (MonoVTable *vtable)
4595 {
4596         MonoError error;
4597         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4598         mono_error_raise_exception (&error);
4599
4600         return o;
4601 }
4602
4603 MonoObject *
4604 mono_object_new_alloc_specific (MonoVTable *vtable)
4605 {
4606         MonoError error;
4607         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4608         mono_error_raise_exception (&error);
4609
4610         return o;
4611 }
4612
4613 MonoObject *
4614 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4615 {
4616         MONO_REQ_GC_UNSAFE_MODE;
4617
4618         MonoObject *o;
4619
4620         mono_error_init (error);
4621
4622         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4623
4624         if (G_UNLIKELY (!o))
4625                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4626         else if (G_UNLIKELY (vtable->klass->has_finalize))
4627                 mono_object_register_finalizer (o);
4628
4629         return o;
4630 }
4631
4632 MonoObject*
4633 mono_object_new_fast (MonoVTable *vtable)
4634 {
4635         MonoError error;
4636         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4637         mono_error_raise_exception (&error);
4638
4639         return o;
4640 }
4641
4642 MonoObject*
4643 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4644 {
4645         MONO_REQ_GC_UNSAFE_MODE;
4646
4647         MonoObject *o;
4648
4649         mono_error_init (error);
4650
4651         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4652
4653         if (G_UNLIKELY (!o))
4654                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4655
4656         return o;
4657 }
4658
4659 MonoObject *
4660 ves_icall_object_new_fast (MonoVTable *vtable)
4661 {
4662         MonoError error;
4663         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4664         mono_error_raise_exception (&error);
4665
4666         return o;
4667 }
4668
4669 MonoObject*
4670 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4671 {
4672         MONO_REQ_GC_UNSAFE_MODE;
4673
4674         MonoObject *o;
4675
4676         mono_error_init (error);
4677
4678         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4679
4680         if (G_UNLIKELY (!o))
4681                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4682         else if (G_UNLIKELY (vtable->klass->has_finalize))
4683                 mono_object_register_finalizer (o);
4684
4685         return o;
4686 }
4687
4688 /**
4689  * mono_class_get_allocation_ftn:
4690  * @vtable: vtable
4691  * @for_box: the object will be used for boxing
4692  * @pass_size_in_words: 
4693  *
4694  * Return the allocation function appropriate for the given class.
4695  */
4696
4697 void*
4698 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4699 {
4700         MONO_REQ_GC_NEUTRAL_MODE;
4701
4702         *pass_size_in_words = FALSE;
4703
4704         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4705                 return ves_icall_object_new_specific;
4706
4707         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4708
4709                 return ves_icall_object_new_fast;
4710
4711                 /* 
4712                  * FIXME: This is actually slower than ves_icall_object_new_fast, because
4713                  * of the overhead of parameter passing.
4714                  */
4715                 /*
4716                 *pass_size_in_words = TRUE;
4717 #ifdef GC_REDIRECT_TO_LOCAL
4718                 return GC_local_gcj_fast_malloc;
4719 #else
4720                 return GC_gcj_fast_malloc;
4721 #endif
4722                 */
4723         }
4724
4725         return ves_icall_object_new_specific;
4726 }
4727
4728 /**
4729  * mono_object_new_from_token:
4730  * @image: Context where the type_token is hosted
4731  * @token: a token of the type that we want to create
4732  *
4733  * Returns: A newly created object whose definition is
4734  * looked up using @token in the @image image
4735  */
4736 MonoObject *
4737 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
4738 {
4739         MONO_REQ_GC_UNSAFE_MODE;
4740
4741         MonoError error;
4742         MonoClass *klass;
4743
4744         klass = mono_class_get_checked (image, token, &error);
4745         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4746
4747         return mono_object_new (domain, klass);
4748 }
4749
4750
4751 /**
4752  * mono_object_clone:
4753  * @obj: the object to clone
4754  *
4755  * Returns: A newly created object who is a shallow copy of @obj
4756  */
4757 MonoObject *
4758 mono_object_clone (MonoObject *obj)
4759 {
4760         MonoError error;
4761         MonoObject *o = mono_object_clone_checked (obj, &error);
4762         mono_error_raise_exception (&error);
4763
4764         return o;
4765 }
4766
4767 MonoObject *
4768 mono_object_clone_checked (MonoObject *obj, MonoError *error)
4769 {
4770         MONO_REQ_GC_UNSAFE_MODE;
4771
4772         MonoObject *o;
4773         int size;
4774
4775         mono_error_init (error);
4776
4777         size = obj->vtable->klass->instance_size;
4778
4779         if (obj->vtable->klass->rank)
4780                 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4781
4782         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4783
4784         if (G_UNLIKELY (!o)) {
4785                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
4786                 return NULL;
4787         }
4788
4789         /* If the object doesn't contain references this will do a simple memmove. */
4790         mono_gc_wbarrier_object_copy (o, obj);
4791
4792         if (obj->vtable->klass->has_finalize)
4793                 mono_object_register_finalizer (o);
4794         return o;
4795 }
4796
4797 /**
4798  * mono_array_full_copy:
4799  * @src: source array to copy
4800  * @dest: destination array
4801  *
4802  * Copies the content of one array to another with exactly the same type and size.
4803  */
4804 void
4805 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4806 {
4807         MONO_REQ_GC_UNSAFE_MODE;
4808
4809         uintptr_t size;
4810         MonoClass *klass = src->obj.vtable->klass;
4811
4812         g_assert (klass == dest->obj.vtable->klass);
4813
4814         size = mono_array_length (src);
4815         g_assert (size == mono_array_length (dest));
4816         size *= mono_array_element_size (klass);
4817 #ifdef HAVE_SGEN_GC
4818         if (klass->element_class->valuetype) {
4819                 if (klass->element_class->has_references)
4820                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4821                 else
4822                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4823         } else {
4824                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4825         }
4826 #else
4827         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4828 #endif
4829 }
4830
4831 /**
4832  * mono_array_clone_in_domain:
4833  * @domain: the domain in which the array will be cloned into
4834  * @array: the array to clone
4835  *
4836  * This routine returns a copy of the array that is hosted on the
4837  * specified MonoDomain.
4838  */
4839 MonoArray*
4840 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4841 {
4842         MONO_REQ_GC_UNSAFE_MODE;
4843
4844         MonoArray *o;
4845         uintptr_t size, i;
4846         uintptr_t *sizes;
4847         MonoClass *klass = array->obj.vtable->klass;
4848
4849         if (array->bounds == NULL) {
4850                 size = mono_array_length (array);
4851                 o = mono_array_new_full (domain, klass, &size, NULL);
4852
4853                 size *= mono_array_element_size (klass);
4854 #ifdef HAVE_SGEN_GC
4855                 if (klass->element_class->valuetype) {
4856                         if (klass->element_class->has_references)
4857                                 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4858                         else
4859                                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4860                 } else {
4861                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4862                 }
4863 #else
4864                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4865 #endif
4866                 return o;
4867         }
4868         
4869         sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4870         size = mono_array_element_size (klass);
4871         for (i = 0; i < klass->rank; ++i) {
4872                 sizes [i] = array->bounds [i].length;
4873                 size *= array->bounds [i].length;
4874                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4875         }
4876         o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4877 #ifdef HAVE_SGEN_GC
4878         if (klass->element_class->valuetype) {
4879                 if (klass->element_class->has_references)
4880                         mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4881                 else
4882                         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4883         } else {
4884                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4885         }
4886 #else
4887         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4888 #endif
4889
4890         return o;
4891 }
4892
4893 /**
4894  * mono_array_clone:
4895  * @array: the array to clone
4896  *
4897  * Returns: A newly created array who is a shallow copy of @array
4898  */
4899 MonoArray*
4900 mono_array_clone (MonoArray *array)
4901 {
4902         MONO_REQ_GC_UNSAFE_MODE;
4903
4904         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4905 }
4906
4907 /* helper macros to check for overflow when calculating the size of arrays */
4908 #ifdef MONO_BIG_ARRAYS
4909 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4910 #define MYGUINT_MAX MYGUINT64_MAX
4911 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4912             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4913 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4914             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
4915                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4916 #else
4917 #define MYGUINT32_MAX 4294967295U
4918 #define MYGUINT_MAX MYGUINT32_MAX
4919 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4920             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4921 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4922             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
4923                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4924 #endif
4925
4926 gboolean
4927 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4928 {
4929         MONO_REQ_GC_NEUTRAL_MODE;
4930
4931         uintptr_t byte_len;
4932
4933         byte_len = mono_array_element_size (klass);
4934         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4935                 return FALSE;
4936         byte_len *= len;
4937         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4938                 return FALSE;
4939         byte_len += MONO_SIZEOF_MONO_ARRAY;
4940
4941         *res = byte_len;
4942
4943         return TRUE;
4944 }
4945
4946 /**
4947  * mono_array_new_full:
4948  * @domain: domain where the object is created
4949  * @array_class: array class
4950  * @lengths: lengths for each dimension in the array
4951  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4952  *
4953  * This routine creates a new array objects with the given dimensions,
4954  * lower bounds and type.
4955  */
4956 MonoArray*
4957 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4958 {
4959         MONO_REQ_GC_UNSAFE_MODE;
4960
4961         uintptr_t byte_len = 0, len, bounds_size;
4962         MonoObject *o;
4963         MonoArray *array;
4964         MonoArrayBounds *bounds;
4965         MonoVTable *vtable;
4966         int i;
4967
4968         if (!array_class->inited)
4969                 mono_class_init (array_class);
4970
4971         len = 1;
4972
4973         /* A single dimensional array with a 0 lower bound is the same as an szarray */
4974         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4975                 len = lengths [0];
4976                 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4977                         arith_overflow ();
4978                 bounds_size = 0;
4979         } else {
4980                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4981
4982                 for (i = 0; i < array_class->rank; ++i) {
4983                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4984                                 arith_overflow ();
4985                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4986                                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4987                         len *= lengths [i];
4988                 }
4989         }
4990
4991         if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4992                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4993
4994         if (bounds_size) {
4995                 /* align */
4996                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4997                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4998                 byte_len = (byte_len + 3) & ~3;
4999                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
5000                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
5001                 byte_len += bounds_size;
5002         }
5003         /* 
5004          * Following three lines almost taken from mono_object_new ():
5005          * they need to be kept in sync.
5006          */
5007         vtable = mono_class_vtable_full (domain, array_class, TRUE);
5008         if (bounds_size)
5009                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5010         else
5011                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5012
5013         if (G_UNLIKELY (!o))
5014                 mono_gc_out_of_memory (byte_len);
5015
5016         array = (MonoArray*)o;
5017
5018         bounds = array->bounds;
5019
5020         if (bounds_size) {
5021                 for (i = 0; i < array_class->rank; ++i) {
5022                         bounds [i].length = lengths [i];
5023                         if (lower_bounds)
5024                                 bounds [i].lower_bound = lower_bounds [i];
5025                 }
5026         }
5027
5028         return array;
5029 }
5030
5031 /**
5032  * mono_array_new:
5033  * @domain: domain where the object is created
5034  * @eclass: element class
5035  * @n: number of array elements
5036  *
5037  * This routine creates a new szarray with @n elements of type @eclass.
5038  */
5039 MonoArray *
5040 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5041 {
5042         MONO_REQ_GC_UNSAFE_MODE;
5043
5044         MonoClass *ac;
5045
5046         ac = mono_array_class_get (eclass, 1);
5047         g_assert (ac);
5048
5049         return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
5050 }
5051
5052 /**
5053  * mono_array_new_specific:
5054  * @vtable: a vtable in the appropriate domain for an initialized class
5055  * @n: number of array elements
5056  *
5057  * This routine is a fast alternative to mono_array_new() for code which
5058  * can be sure about the domain it operates in.
5059  */
5060 MonoArray *
5061 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5062 {
5063         MONO_REQ_GC_UNSAFE_MODE;
5064
5065         MonoObject *o;
5066         uintptr_t byte_len;
5067
5068         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5069                 arith_overflow ();
5070                 return NULL;
5071         }
5072
5073         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5074                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
5075                 return NULL;
5076         }
5077         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5078
5079         if (G_UNLIKELY (!o))
5080                 mono_gc_out_of_memory (byte_len);
5081
5082         return (MonoArray*)o;
5083 }
5084
5085 /**
5086  * mono_string_new_utf16:
5087  * @text: a pointer to an utf16 string
5088  * @len: the length of the string
5089  *
5090  * Returns: A newly created string object which contains @text.
5091  */
5092 MonoString *
5093 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5094 {
5095         MONO_REQ_GC_UNSAFE_MODE;
5096
5097         MonoString *s;
5098         
5099         s = mono_string_new_size (domain, len);
5100         g_assert (s != NULL);
5101
5102         memcpy (mono_string_chars (s), text, len * 2);
5103
5104         return s;
5105 }
5106
5107 /**
5108  * mono_string_new_utf32:
5109  * @text: a pointer to an utf32 string
5110  * @len: the length of the string
5111  *
5112  * Returns: A newly created string object which contains @text.
5113  */
5114 MonoString *
5115 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5116 {
5117         MONO_REQ_GC_UNSAFE_MODE;
5118
5119         MonoString *s;
5120         mono_unichar2 *utf16_output = NULL;
5121         gint32 utf16_len = 0;
5122         GError *error = NULL;
5123         glong items_written;
5124         
5125         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5126         
5127         if (error)
5128                 g_error_free (error);
5129
5130         while (utf16_output [utf16_len]) utf16_len++;
5131         
5132         s = mono_string_new_size (domain, utf16_len);
5133         g_assert (s != NULL);
5134
5135         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5136
5137         g_free (utf16_output);
5138         
5139         return s;
5140 }
5141
5142 /**
5143  * mono_string_new_size:
5144  * @text: a pointer to an utf16 string
5145  * @len: the length of the string
5146  *
5147  * Returns: A newly created string object of @len
5148  */
5149 MonoString *
5150 mono_string_new_size (MonoDomain *domain, gint32 len)
5151 {
5152         MONO_REQ_GC_UNSAFE_MODE;
5153
5154         MonoString *s;
5155         MonoVTable *vtable;
5156         size_t size;
5157
5158         /* check for overflow */
5159         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5160                 mono_gc_out_of_memory (-1);
5161
5162         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5163         g_assert (size > 0);
5164
5165         vtable = mono_class_vtable (domain, mono_defaults.string_class);
5166         g_assert (vtable);
5167
5168         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5169
5170         if (G_UNLIKELY (!s))
5171                 mono_gc_out_of_memory (size);
5172
5173         return s;
5174 }
5175
5176 /**
5177  * mono_string_new_len:
5178  * @text: a pointer to an utf8 string
5179  * @length: number of bytes in @text to consider
5180  *
5181  * Returns: A newly created string object which contains @text.
5182  */
5183 MonoString*
5184 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5185 {
5186         MONO_REQ_GC_UNSAFE_MODE;
5187
5188         GError *error = NULL;
5189         MonoString *o = NULL;
5190         guint16 *ut;
5191         glong items_written;
5192
5193         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5194
5195         if (!error)
5196                 o = mono_string_new_utf16 (domain, ut, items_written);
5197         else 
5198                 g_error_free (error);
5199
5200         g_free (ut);
5201
5202         return o;
5203 }
5204
5205 /**
5206  * mono_string_new:
5207  * @text: a pointer to an utf8 string
5208  *
5209  * Returns: A newly created string object which contains @text.
5210  */
5211 MonoString*
5212 mono_string_new (MonoDomain *domain, const char *text)
5213 {
5214         MONO_REQ_GC_UNSAFE_MODE;
5215
5216     GError *error = NULL;
5217     MonoString *o = NULL;
5218     guint16 *ut;
5219     glong items_written;
5220     int l;
5221
5222     l = strlen (text);
5223    
5224     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5225
5226     if (!error)
5227         o = mono_string_new_utf16 (domain, ut, items_written);
5228     else
5229         g_error_free (error);
5230
5231     g_free (ut);
5232 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5233 #if 0
5234         gunichar2 *str;
5235         const gchar *end;
5236         int len;
5237         MonoString *o = NULL;
5238
5239         if (!g_utf8_validate (text, -1, &end))
5240                 return NULL;
5241
5242         len = g_utf8_strlen (text, -1);
5243         o = mono_string_new_size (domain, len);
5244         str = mono_string_chars (o);
5245
5246         while (text < end) {
5247                 *str++ = g_utf8_get_char (text);
5248                 text = g_utf8_next_char (text);
5249         }
5250 #endif
5251         return o;
5252 }
5253
5254 /**
5255  * mono_string_new_wrapper:
5256  * @text: pointer to utf8 characters.
5257  *
5258  * Helper function to create a string object from @text in the current domain.
5259  */
5260 MonoString*
5261 mono_string_new_wrapper (const char *text)
5262 {
5263         MONO_REQ_GC_UNSAFE_MODE;
5264
5265         MonoDomain *domain = mono_domain_get ();
5266
5267         if (text)
5268                 return mono_string_new (domain, text);
5269
5270         return NULL;
5271 }
5272
5273 /**
5274  * mono_value_box:
5275  * @class: the class of the value
5276  * @value: a pointer to the unboxed data
5277  *
5278  * Returns: A newly created object which contains @value.
5279  */
5280 MonoObject *
5281 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5282 {
5283         MONO_REQ_GC_UNSAFE_MODE;
5284
5285         MonoError error;
5286         MonoObject *res;
5287         int size;
5288         MonoVTable *vtable;
5289
5290         g_assert (klass->valuetype);
5291         if (mono_class_is_nullable (klass))
5292                 return mono_nullable_box ((guint8 *)value, klass);
5293
5294         vtable = mono_class_vtable (domain, klass);
5295         if (!vtable)
5296                 return NULL;
5297         size = mono_class_instance_size (klass);
5298         res = mono_object_new_alloc_specific_checked (vtable, &error);
5299         mono_error_raise_exception (&error); /* FIXME don't raise here */
5300
5301         size = size - sizeof (MonoObject);
5302
5303 #ifdef HAVE_SGEN_GC
5304         g_assert (size == mono_class_value_size (klass, NULL));
5305         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5306 #else
5307 #if NO_UNALIGNED_ACCESS
5308         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5309 #else
5310         switch (size) {
5311         case 1:
5312                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5313                 break;
5314         case 2:
5315                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5316                 break;
5317         case 4:
5318                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5319                 break;
5320         case 8:
5321                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5322                 break;
5323         default:
5324                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5325         }
5326 #endif
5327 #endif
5328         if (klass->has_finalize)
5329                 mono_object_register_finalizer (res);
5330         return res;
5331 }
5332
5333 /*
5334  * mono_value_copy:
5335  * @dest: destination pointer
5336  * @src: source pointer
5337  * @klass: a valuetype class
5338  *
5339  * Copy a valuetype from @src to @dest. This function must be used
5340  * when @klass contains references fields.
5341  */
5342 void
5343 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5344 {
5345         MONO_REQ_GC_UNSAFE_MODE;
5346
5347         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5348 }
5349
5350 /*
5351  * mono_value_copy_array:
5352  * @dest: destination array
5353  * @dest_idx: index in the @dest array
5354  * @src: source pointer
5355  * @count: number of items
5356  *
5357  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
5358  * This function must be used when @klass contains references fields.
5359  * Overlap is handled.
5360  */
5361 void
5362 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5363 {
5364         MONO_REQ_GC_UNSAFE_MODE;
5365
5366         int size = mono_array_element_size (dest->obj.vtable->klass);
5367         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5368         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5369         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5370 }
5371
5372 /**
5373  * mono_object_get_domain:
5374  * @obj: object to query
5375  * 
5376  * Returns: the MonoDomain where the object is hosted
5377  */
5378 MonoDomain*
5379 mono_object_get_domain (MonoObject *obj)
5380 {
5381         MONO_REQ_GC_UNSAFE_MODE;
5382
5383         return mono_object_domain (obj);
5384 }
5385
5386 /**
5387  * mono_object_get_class:
5388  * @obj: object to query
5389  * 
5390  * Returns: the MonOClass of the object.
5391  */
5392 MonoClass*
5393 mono_object_get_class (MonoObject *obj)
5394 {
5395         MONO_REQ_GC_UNSAFE_MODE;
5396
5397         return mono_object_class (obj);
5398 }
5399 /**
5400  * mono_object_get_size:
5401  * @o: object to query
5402  * 
5403  * Returns: the size, in bytes, of @o
5404  */
5405 guint
5406 mono_object_get_size (MonoObject* o)
5407 {
5408         MONO_REQ_GC_UNSAFE_MODE;
5409
5410         MonoClass* klass = mono_object_class (o);
5411         if (klass == mono_defaults.string_class) {
5412                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5413         } else if (o->vtable->rank) {
5414                 MonoArray *array = (MonoArray*)o;
5415                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5416                 if (array->bounds) {
5417                         size += 3;
5418                         size &= ~3;
5419                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
5420                 }
5421                 return size;
5422         } else {
5423                 return mono_class_instance_size (klass);
5424         }
5425 }
5426
5427 /**
5428  * mono_object_unbox:
5429  * @obj: object to unbox
5430  * 
5431  * Returns: a pointer to the start of the valuetype boxed in this
5432  * object.
5433  *
5434  * This method will assert if the object passed is not a valuetype.
5435  */
5436 gpointer
5437 mono_object_unbox (MonoObject *obj)
5438 {
5439         MONO_REQ_GC_UNSAFE_MODE;
5440
5441         /* add assert for valuetypes? */
5442         g_assert (obj->vtable->klass->valuetype);
5443         return ((char*)obj) + sizeof (MonoObject);
5444 }
5445
5446 /**
5447  * mono_object_isinst:
5448  * @obj: an object
5449  * @klass: a pointer to a class 
5450  *
5451  * Returns: @obj if @obj is derived from @klass
5452  */
5453 MonoObject *
5454 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5455 {
5456         MONO_REQ_GC_UNSAFE_MODE;
5457
5458         if (!klass->inited)
5459                 mono_class_init (klass);
5460
5461         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5462                 return mono_object_isinst_mbyref (obj, klass);
5463
5464         if (!obj)
5465                 return NULL;
5466
5467         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5468 }
5469
5470 MonoObject *
5471 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5472 {
5473         MONO_REQ_GC_UNSAFE_MODE;
5474
5475         MonoVTable *vt;
5476
5477         if (!obj)
5478                 return NULL;
5479
5480         vt = obj->vtable;
5481         
5482         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5483                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5484                         return obj;
5485                 }
5486
5487                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5488                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5489                         return obj;
5490         } else {
5491                 MonoClass *oklass = vt->klass;
5492                 if (mono_class_is_transparent_proxy (oklass))
5493                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5494
5495                 mono_class_setup_supertypes (klass);    
5496                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5497                         return obj;
5498         }
5499 #ifndef DISABLE_REMOTING
5500         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5501         {
5502                 MonoDomain *domain = mono_domain_get ();
5503                 MonoObject *res;
5504                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5505                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5506                 MonoMethod *im = NULL;
5507                 gpointer pa [2];
5508
5509                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5510                 if (!im)
5511                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5512                 im = mono_object_get_virtual_method (rp, im);
5513                 g_assert (im);
5514         
5515                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5516                 pa [1] = obj;
5517
5518                 res = mono_runtime_invoke (im, rp, pa, NULL);
5519         
5520                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5521                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5522                         mono_upgrade_remote_class (domain, obj, klass);
5523                         return obj;
5524                 }
5525         }
5526 #endif /* DISABLE_REMOTING */
5527         return NULL;
5528 }
5529
5530 /**
5531  * mono_object_castclass_mbyref:
5532  * @obj: an object
5533  * @klass: a pointer to a class 
5534  *
5535  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5536  */
5537 MonoObject *
5538 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5539 {
5540         MONO_REQ_GC_UNSAFE_MODE;
5541
5542         if (!obj) return NULL;
5543         if (mono_object_isinst_mbyref (obj, klass)) return obj;
5544                 
5545         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5546                                                         "System",
5547                                                         "InvalidCastException"));
5548         return NULL;
5549 }
5550
5551 typedef struct {
5552         MonoDomain *orig_domain;
5553         MonoString *ins;
5554         MonoString *res;
5555 } LDStrInfo;
5556
5557 static void
5558 str_lookup (MonoDomain *domain, gpointer user_data)
5559 {
5560         MONO_REQ_GC_UNSAFE_MODE;
5561
5562         LDStrInfo *info = (LDStrInfo *)user_data;
5563         if (info->res || domain == info->orig_domain)
5564                 return;
5565         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5566 }
5567
5568 static MonoString*
5569 mono_string_get_pinned (MonoString *str, MonoError *error)
5570 {
5571         MONO_REQ_GC_UNSAFE_MODE;
5572
5573         mono_error_init (error);
5574
5575         /* We only need to make a pinned version of a string if this is a moving GC */
5576         if (!mono_gc_is_moving ())
5577                 return str;
5578         int size;
5579         MonoString *news;
5580         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5581         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5582         if (news) {
5583                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5584                 news->length = mono_string_length (str);
5585         } else {
5586                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5587         }
5588         return news;
5589 }
5590
5591 static MonoString*
5592 mono_string_is_interned_lookup (MonoString *str, int insert)
5593 {
5594         MONO_REQ_GC_UNSAFE_MODE;
5595
5596         MonoError error;
5597         MonoGHashTable *ldstr_table;
5598         MonoString *s, *res;
5599         MonoDomain *domain;
5600         
5601         domain = ((MonoObject *)str)->vtable->domain;
5602         ldstr_table = domain->ldstr_table;
5603         ldstr_lock ();
5604         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5605         if (res) {
5606                 ldstr_unlock ();
5607                 return res;
5608         }
5609         if (insert) {
5610                 /* Allocate outside the lock */
5611                 ldstr_unlock ();
5612                 s = mono_string_get_pinned (str, &error);
5613                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5614                 if (s) {
5615                         ldstr_lock ();
5616                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5617                         if (res) {
5618                                 ldstr_unlock ();
5619                                 return res;
5620                         }
5621                         mono_g_hash_table_insert (ldstr_table, s, s);
5622                         ldstr_unlock ();
5623                 }
5624                 return s;
5625         } else {
5626                 LDStrInfo ldstr_info;
5627                 ldstr_info.orig_domain = domain;
5628                 ldstr_info.ins = str;
5629                 ldstr_info.res = NULL;
5630
5631                 mono_domain_foreach (str_lookup, &ldstr_info);
5632                 if (ldstr_info.res) {
5633                         /* 
5634                          * the string was already interned in some other domain:
5635                          * intern it in the current one as well.
5636                          */
5637                         mono_g_hash_table_insert (ldstr_table, str, str);
5638                         ldstr_unlock ();
5639                         return str;
5640                 }
5641         }
5642         ldstr_unlock ();
5643         return NULL;
5644 }
5645
5646 /**
5647  * mono_string_is_interned:
5648  * @o: String to probe
5649  *
5650  * Returns whether the string has been interned.
5651  */
5652 MonoString*
5653 mono_string_is_interned (MonoString *o)
5654 {
5655         MONO_REQ_GC_UNSAFE_MODE;
5656
5657         return mono_string_is_interned_lookup (o, FALSE);
5658 }
5659
5660 /**
5661  * mono_string_intern:
5662  * @o: String to intern
5663  *
5664  * Interns the string passed.  
5665  * Returns: The interned string.
5666  */
5667 MonoString*
5668 mono_string_intern (MonoString *str)
5669 {
5670         MONO_REQ_GC_UNSAFE_MODE;
5671
5672         return mono_string_is_interned_lookup (str, TRUE);
5673 }
5674
5675 /**
5676  * mono_ldstr:
5677  * @domain: the domain where the string will be used.
5678  * @image: a metadata context
5679  * @idx: index into the user string table.
5680  * 
5681  * Implementation for the ldstr opcode.
5682  * Returns: a loaded string from the @image/@idx combination.
5683  */
5684 MonoString*
5685 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5686 {
5687         MONO_REQ_GC_UNSAFE_MODE;
5688
5689         if (image->dynamic) {
5690                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5691                 return str;
5692         } else {
5693                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5694                         return NULL; /*FIXME we should probably be raising an exception here*/
5695                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5696         }
5697 }
5698
5699 /**
5700  * mono_ldstr_metadata_sig
5701  * @domain: the domain for the string
5702  * @sig: the signature of a metadata string
5703  *
5704  * Returns: a MonoString for a string stored in the metadata
5705  */
5706 static MonoString*
5707 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5708 {
5709         MONO_REQ_GC_UNSAFE_MODE;
5710
5711         MonoError error;
5712         const char *str = sig;
5713         MonoString *o, *interned;
5714         size_t len2;
5715
5716         len2 = mono_metadata_decode_blob_size (str, &str);
5717         len2 >>= 1;
5718
5719         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5720 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5721         {
5722                 int i;
5723                 guint16 *p2 = (guint16*)mono_string_chars (o);
5724                 for (i = 0; i < len2; ++i) {
5725                         *p2 = GUINT16_FROM_LE (*p2);
5726                         ++p2;
5727                 }
5728         }
5729 #endif
5730         ldstr_lock ();
5731         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5732         ldstr_unlock ();
5733         if (interned)
5734                 return interned; /* o will get garbage collected */
5735
5736         o = mono_string_get_pinned (o, &error);
5737         mono_error_raise_exception (&error); /* FIXME don't raise here */
5738         if (o) {
5739                 ldstr_lock ();
5740                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5741                 if (!interned) {
5742                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
5743                         interned = o;
5744                 }
5745                 ldstr_unlock ();
5746         }
5747
5748         return interned;
5749 }
5750
5751 /**
5752  * mono_string_to_utf8:
5753  * @s: a System.String
5754  *
5755  * Returns the UTF8 representation for @s.
5756  * The resulting buffer needs to be freed with mono_free().
5757  *
5758  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5759  */
5760 char *
5761 mono_string_to_utf8 (MonoString *s)
5762 {
5763         MONO_REQ_GC_UNSAFE_MODE;
5764
5765         MonoError error;
5766         char *result = mono_string_to_utf8_checked (s, &error);
5767         
5768         if (!mono_error_ok (&error))
5769                 mono_error_raise_exception (&error);
5770         return result;
5771 }
5772
5773 /**
5774  * mono_string_to_utf8_checked:
5775  * @s: a System.String
5776  * @error: a MonoError.
5777  * 
5778  * Converts a MonoString to its UTF8 representation. May fail; check 
5779  * @error to determine whether the conversion was successful.
5780  * The resulting buffer should be freed with mono_free().
5781  */
5782 char *
5783 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5784 {
5785         MONO_REQ_GC_UNSAFE_MODE;
5786
5787         long written = 0;
5788         char *as;
5789         GError *gerror = NULL;
5790
5791         mono_error_init (error);
5792
5793         if (s == NULL)
5794                 return NULL;
5795
5796         if (!s->length)
5797                 return g_strdup ("");
5798
5799         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5800         if (gerror) {
5801                 mono_error_set_argument (error, "string", "%s", gerror->message);
5802                 g_error_free (gerror);
5803                 return NULL;
5804         }
5805         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5806         if (s->length > written) {
5807                 /* allocate the total length and copy the part of the string that has been converted */
5808                 char *as2 = (char *)g_malloc0 (s->length);
5809                 memcpy (as2, as, written);
5810                 g_free (as);
5811                 as = as2;
5812         }
5813
5814         return as;
5815 }
5816
5817 /**
5818  * mono_string_to_utf8_ignore:
5819  * @s: a MonoString
5820  *
5821  * Converts a MonoString to its UTF8 representation. Will ignore
5822  * invalid surrogate pairs.
5823  * The resulting buffer should be freed with mono_free().
5824  * 
5825  */
5826 char *
5827 mono_string_to_utf8_ignore (MonoString *s)
5828 {
5829         MONO_REQ_GC_UNSAFE_MODE;
5830
5831         long written = 0;
5832         char *as;
5833
5834         if (s == NULL)
5835                 return NULL;
5836
5837         if (!s->length)
5838                 return g_strdup ("");
5839
5840         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5841
5842         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5843         if (s->length > written) {
5844                 /* allocate the total length and copy the part of the string that has been converted */
5845                 char *as2 = (char *)g_malloc0 (s->length);
5846                 memcpy (as2, as, written);
5847                 g_free (as);
5848                 as = as2;
5849         }
5850
5851         return as;
5852 }
5853
5854 /**
5855  * mono_string_to_utf8_image_ignore:
5856  * @s: a System.String
5857  *
5858  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5859  */
5860 char *
5861 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5862 {
5863         MONO_REQ_GC_UNSAFE_MODE;
5864
5865         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5866 }
5867
5868 /**
5869  * mono_string_to_utf8_mp_ignore:
5870  * @s: a System.String
5871  *
5872  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5873  */
5874 char *
5875 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5876 {
5877         MONO_REQ_GC_UNSAFE_MODE;
5878
5879         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5880 }
5881
5882
5883 /**
5884  * mono_string_to_utf16:
5885  * @s: a MonoString
5886  *
5887  * Return an null-terminated array of the utf-16 chars
5888  * contained in @s. The result must be freed with g_free().
5889  * This is a temporary helper until our string implementation
5890  * is reworked to always include the null terminating char.
5891  */
5892 mono_unichar2*
5893 mono_string_to_utf16 (MonoString *s)
5894 {
5895         MONO_REQ_GC_UNSAFE_MODE;
5896
5897         char *as;
5898
5899         if (s == NULL)
5900                 return NULL;
5901
5902         as = (char *)g_malloc ((s->length * 2) + 2);
5903         as [(s->length * 2)] = '\0';
5904         as [(s->length * 2) + 1] = '\0';
5905
5906         if (!s->length) {
5907                 return (gunichar2 *)(as);
5908         }
5909         
5910         memcpy (as, mono_string_chars(s), s->length * 2);
5911         return (gunichar2 *)(as);
5912 }
5913
5914 /**
5915  * mono_string_to_utf32:
5916  * @s: a MonoString
5917  *
5918  * Return an null-terminated array of the UTF-32 (UCS-4) chars
5919  * contained in @s. The result must be freed with g_free().
5920  */
5921 mono_unichar4*
5922 mono_string_to_utf32 (MonoString *s)
5923 {
5924         MONO_REQ_GC_UNSAFE_MODE;
5925
5926         mono_unichar4 *utf32_output = NULL; 
5927         GError *error = NULL;
5928         glong items_written;
5929         
5930         if (s == NULL)
5931                 return NULL;
5932                 
5933         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5934         
5935         if (error)
5936                 g_error_free (error);
5937
5938         return utf32_output;
5939 }
5940
5941 /**
5942  * mono_string_from_utf16:
5943  * @data: the UTF16 string (LPWSTR) to convert
5944  *
5945  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5946  *
5947  * Returns: a MonoString.
5948  */
5949 MonoString *
5950 mono_string_from_utf16 (gunichar2 *data)
5951 {
5952         MONO_REQ_GC_UNSAFE_MODE;
5953
5954         MonoDomain *domain = mono_domain_get ();
5955         int len = 0;
5956
5957         if (!data)
5958                 return NULL;
5959
5960         while (data [len]) len++;
5961
5962         return mono_string_new_utf16 (domain, data, len);
5963 }
5964
5965 /**
5966  * mono_string_from_utf32:
5967  * @data: the UTF32 string (LPWSTR) to convert
5968  *
5969  * Converts a UTF32 (UCS-4)to a MonoString.
5970  *
5971  * Returns: a MonoString.
5972  */
5973 MonoString *
5974 mono_string_from_utf32 (mono_unichar4 *data)
5975 {
5976         MONO_REQ_GC_UNSAFE_MODE;
5977
5978         MonoString* result = NULL;
5979         mono_unichar2 *utf16_output = NULL;
5980         GError *error = NULL;
5981         glong items_written;
5982         int len = 0;
5983
5984         if (!data)
5985                 return NULL;
5986
5987         while (data [len]) len++;
5988
5989         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5990
5991         if (error)
5992                 g_error_free (error);
5993
5994         result = mono_string_from_utf16 (utf16_output);
5995         g_free (utf16_output);
5996         return result;
5997 }
5998
5999 static char *
6000 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6001 {
6002         MONO_REQ_GC_UNSAFE_MODE;
6003
6004         char *r;
6005         char *mp_s;
6006         int len;
6007
6008         if (ignore_error) {
6009                 r = mono_string_to_utf8_ignore (s);
6010         } else {
6011                 r = mono_string_to_utf8_checked (s, error);
6012                 if (!mono_error_ok (error))
6013                         return NULL;
6014         }
6015
6016         if (!mp && !image)
6017                 return r;
6018
6019         len = strlen (r) + 1;
6020         if (mp)
6021                 mp_s = (char *)mono_mempool_alloc (mp, len);
6022         else
6023                 mp_s = (char *)mono_image_alloc (image, len);
6024
6025         memcpy (mp_s, r, len);
6026
6027         g_free (r);
6028
6029         return mp_s;
6030 }
6031
6032 /**
6033  * mono_string_to_utf8_image:
6034  * @s: a System.String
6035  *
6036  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6037  */
6038 char *
6039 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6040 {
6041         MONO_REQ_GC_UNSAFE_MODE;
6042
6043         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6044 }
6045
6046 /**
6047  * mono_string_to_utf8_mp:
6048  * @s: a System.String
6049  *
6050  * Same as mono_string_to_utf8, but allocate the string from a mempool.
6051  */
6052 char *
6053 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6054 {
6055         MONO_REQ_GC_UNSAFE_MODE;
6056
6057         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6058 }
6059
6060
6061 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6062
6063 void
6064 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6065 {
6066         eh_callbacks = *cbs;
6067 }
6068
6069 MonoRuntimeExceptionHandlingCallbacks *
6070 mono_get_eh_callbacks (void)
6071 {
6072         return &eh_callbacks;
6073 }
6074
6075 /**
6076  * mono_raise_exception:
6077  * @ex: exception object
6078  *
6079  * Signal the runtime that the exception @ex has been raised in unmanaged code.
6080  */
6081 void
6082 mono_raise_exception (MonoException *ex) 
6083 {
6084         MONO_REQ_GC_UNSAFE_MODE;
6085
6086         /*
6087          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6088          * that will cause gcc to omit the function epilog, causing problems when
6089          * the JIT tries to walk the stack, since the return address on the stack
6090          * will point into the next function in the executable, not this one.
6091          */     
6092         eh_callbacks.mono_raise_exception (ex);
6093 }
6094
6095 void
6096 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
6097 {
6098         MONO_REQ_GC_UNSAFE_MODE;
6099
6100         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6101 }
6102
6103 /**
6104  * mono_wait_handle_new:
6105  * @domain: Domain where the object will be created
6106  * @handle: Handle for the wait handle
6107  *
6108  * Returns: A new MonoWaitHandle created in the given domain for the given handle
6109  */
6110 MonoWaitHandle *
6111 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6112 {
6113         MONO_REQ_GC_UNSAFE_MODE;
6114
6115         MonoWaitHandle *res;
6116         gpointer params [1];
6117         static MonoMethod *handle_set;
6118
6119         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
6120
6121         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
6122         if (!handle_set)
6123                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6124
6125         params [0] = &handle;
6126         mono_runtime_invoke (handle_set, res, params, NULL);
6127
6128         return res;
6129 }
6130
6131 HANDLE
6132 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6133 {
6134         MONO_REQ_GC_UNSAFE_MODE;
6135
6136         static MonoClassField *f_os_handle;
6137         static MonoClassField *f_safe_handle;
6138
6139         if (!f_os_handle && !f_safe_handle) {
6140                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6141                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6142         }
6143
6144         if (f_os_handle) {
6145                 HANDLE retval;
6146                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6147                 return retval;
6148         } else {
6149                 MonoSafeHandle *sh;
6150                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6151                 return sh->handle;
6152         }
6153 }
6154
6155
6156 static MonoObject*
6157 mono_runtime_capture_context (MonoDomain *domain)
6158 {
6159         MONO_REQ_GC_UNSAFE_MODE;
6160
6161         RuntimeInvokeFunction runtime_invoke;
6162
6163         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6164                 MonoMethod *method = mono_get_context_capture_method ();
6165                 MonoMethod *wrapper;
6166                 if (!method)
6167                         return NULL;
6168                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6169                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6170                 domain->capture_context_method = mono_compile_method (method);
6171         }
6172
6173         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6174
6175         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6176 }
6177 /**
6178  * mono_async_result_new:
6179  * @domain:domain where the object will be created.
6180  * @handle: wait handle.
6181  * @state: state to pass to AsyncResult
6182  * @data: C closure data.
6183  *
6184  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6185  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6186  *
6187  */
6188 MonoAsyncResult *
6189 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6190 {
6191         MONO_REQ_GC_UNSAFE_MODE;
6192
6193         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6194         MonoObject *context = mono_runtime_capture_context (domain);
6195         /* we must capture the execution context from the original thread */
6196         if (context) {
6197                 MONO_OBJECT_SETREF (res, execution_context, context);
6198                 /* note: result may be null if the flow is suppressed */
6199         }
6200
6201         res->data = (void **)data;
6202         MONO_OBJECT_SETREF (res, object_data, object_data);
6203         MONO_OBJECT_SETREF (res, async_state, state);
6204         if (handle != NULL)
6205                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6206
6207         res->sync_completed = FALSE;
6208         res->completed = FALSE;
6209
6210         return res;
6211 }
6212
6213 MonoObject *
6214 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6215 {
6216         MONO_REQ_GC_UNSAFE_MODE;
6217
6218         MonoAsyncCall *ac;
6219         MonoObject *res;
6220
6221         g_assert (ares);
6222         g_assert (ares->async_delegate);
6223
6224         ac = (MonoAsyncCall*) ares->object_data;
6225         if (!ac) {
6226                 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6227         } else {
6228                 gpointer wait_event = NULL;
6229
6230                 ac->msg->exc = NULL;
6231                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6232                 MONO_OBJECT_SETREF (ac, res, res);
6233
6234                 mono_monitor_enter ((MonoObject*) ares);
6235                 ares->completed = 1;
6236                 if (ares->handle)
6237                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6238                 mono_monitor_exit ((MonoObject*) ares);
6239
6240                 if (wait_event != NULL)
6241                         SetEvent (wait_event);
6242
6243                 if (ac->cb_method) {
6244                         /* we swallow the excepton as it is the behavior on .NET */
6245                         MonoObject *exc = NULL;
6246                         mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6247                         if (exc)
6248                                 mono_unhandled_exception (exc);
6249                 }
6250         }
6251
6252         return res;
6253 }
6254
6255 void
6256 mono_message_init (MonoDomain *domain,
6257                    MonoMethodMessage *this_obj, 
6258                    MonoReflectionMethod *method,
6259                    MonoArray *out_args)
6260 {
6261         MONO_REQ_GC_UNSAFE_MODE;
6262
6263         static MonoClass *object_array_klass;
6264         static MonoClass *byte_array_klass;
6265         static MonoClass *string_array_klass;
6266         MonoMethodSignature *sig = mono_method_signature (method->method);
6267         MonoString *name;
6268         int i, j;
6269         char **names;
6270         guint8 arg_type;
6271
6272         if (!object_array_klass) {
6273                 MonoClass *klass;
6274
6275                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6276                 g_assert (klass);
6277                 byte_array_klass = klass;
6278
6279                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6280                 g_assert (klass);
6281                 string_array_klass = klass;
6282
6283                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6284                 g_assert (klass);
6285
6286                 mono_atomic_store_release (&object_array_klass, klass);
6287         }
6288
6289         MONO_OBJECT_SETREF (this_obj, method, method);
6290
6291         MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6292         MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6293         this_obj->async_result = NULL;
6294         this_obj->call_type = CallType_Sync;
6295
6296         names = g_new (char *, sig->param_count);
6297         mono_method_get_param_names (method->method, (const char **) names);
6298         MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6299         
6300         for (i = 0; i < sig->param_count; i++) {
6301                 name = mono_string_new (domain, names [i]);
6302                 mono_array_setref (this_obj->names, i, name);   
6303         }
6304
6305         g_free (names);
6306         for (i = 0, j = 0; i < sig->param_count; i++) {
6307                 if (sig->params [i]->byref) {
6308                         if (out_args) {
6309                                 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6310                                 mono_array_setref (this_obj->args, i, arg);
6311                                 j++;
6312                         }
6313                         arg_type = 2;
6314                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6315                                 arg_type |= 1;
6316                 } else {
6317                         arg_type = 1;
6318                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6319                                 arg_type |= 4;
6320                 }
6321                 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6322         }
6323 }
6324
6325 #ifndef DISABLE_REMOTING
6326 /**
6327  * mono_remoting_invoke:
6328  * @real_proxy: pointer to a RealProxy object
6329  * @msg: The MonoMethodMessage to execute
6330  * @exc: used to store exceptions
6331  * @out_args: used to store output arguments
6332  *
6333  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6334  * IMessage interface and it is not trivial to extract results from there. So
6335  * we call an helper method PrivateInvoke instead of calling
6336  * RealProxy::Invoke() directly.
6337  *
6338  * Returns: the result object.
6339  */
6340 MonoObject *
6341 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
6342                       MonoObject **exc, MonoArray **out_args)
6343 {
6344         MONO_REQ_GC_UNSAFE_MODE;
6345
6346         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6347         gpointer pa [4];
6348
6349         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6350
6351         if (!im) {
6352                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6353                 if (!im)
6354                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6355                 real_proxy->vtable->domain->private_invoke_method = im;
6356         }
6357
6358         pa [0] = real_proxy;
6359         pa [1] = msg;
6360         pa [2] = exc;
6361         pa [3] = out_args;
6362
6363         return mono_runtime_invoke (im, NULL, pa, exc);
6364 }
6365 #endif
6366
6367 MonoObject *
6368 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6369                      MonoObject **exc, MonoArray **out_args) 
6370 {
6371         MONO_REQ_GC_UNSAFE_MODE;
6372
6373         static MonoClass *object_array_klass;
6374         MonoDomain *domain; 
6375         MonoMethod *method;
6376         MonoMethodSignature *sig;
6377         MonoObject *ret;
6378         int i, j, outarg_count = 0;
6379
6380 #ifndef DISABLE_REMOTING
6381         if (target && mono_object_is_transparent_proxy (target)) {
6382                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6383                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6384                         target = tp->rp->unwrapped_server;
6385                 } else {
6386                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6387                 }
6388         }
6389 #endif
6390
6391         domain = mono_domain_get (); 
6392         method = msg->method->method;
6393         sig = mono_method_signature (method);
6394
6395         for (i = 0; i < sig->param_count; i++) {
6396                 if (sig->params [i]->byref) 
6397                         outarg_count++;
6398         }
6399
6400         if (!object_array_klass) {
6401                 MonoClass *klass;
6402
6403                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6404                 g_assert (klass);
6405
6406                 mono_memory_barrier ();
6407                 object_array_klass = klass;
6408         }
6409
6410         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
6411         *exc = NULL;
6412
6413         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6414
6415         for (i = 0, j = 0; i < sig->param_count; i++) {
6416                 if (sig->params [i]->byref) {
6417                         MonoObject* arg;
6418                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6419                         mono_array_setref (*out_args, j, arg);
6420                         j++;
6421                 }
6422         }
6423
6424         return ret;
6425 }
6426
6427 /**
6428  * mono_object_to_string:
6429  * @obj: The object
6430  * @exc: Any exception thrown by ToString (). May be NULL.
6431  *
6432  * Returns: the result of calling ToString () on an object.
6433  */
6434 MonoString *
6435 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6436 {
6437         MONO_REQ_GC_UNSAFE_MODE;
6438
6439         static MonoMethod *to_string = NULL;
6440         MonoMethod *method;
6441         void *target = obj;
6442
6443         g_assert (obj);
6444
6445         if (!to_string)
6446                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6447
6448         method = mono_object_get_virtual_method (obj, to_string);
6449
6450         // Unbox value type if needed
6451         if (mono_class_is_valuetype (mono_method_get_class (method))) {
6452                 target = mono_object_unbox (obj);
6453         }
6454
6455         return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6456 }
6457
6458 /**
6459  * mono_print_unhandled_exception:
6460  * @exc: The exception
6461  *
6462  * Prints the unhandled exception.
6463  */
6464 void
6465 mono_print_unhandled_exception (MonoObject *exc)
6466 {
6467         MONO_REQ_GC_UNSAFE_MODE;
6468
6469         MonoString * str;
6470         char *message = (char*)"";
6471         gboolean free_message = FALSE;
6472         MonoError error;
6473
6474         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6475                 message = g_strdup ("OutOfMemoryException");
6476                 free_message = TRUE;
6477         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6478                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6479                 free_message = TRUE;
6480         } else {
6481                 
6482                 if (((MonoException*)exc)->native_trace_ips) {
6483                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
6484                         free_message = TRUE;
6485                 } else {
6486                         MonoObject *other_exc = NULL;
6487                         str = mono_object_to_string (exc, &other_exc);
6488                         if (other_exc) {
6489                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6490                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6491                                 
6492                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6493                                         original_backtrace, nested_backtrace);
6494
6495                                 g_free (original_backtrace);
6496                                 g_free (nested_backtrace);
6497                                 free_message = TRUE;
6498                         } else if (str) {
6499                                 message = mono_string_to_utf8_checked (str, &error);
6500                                 if (!mono_error_ok (&error)) {
6501                                         mono_error_cleanup (&error);
6502                                         message = (char *) "";
6503                                 } else {
6504                                         free_message = TRUE;
6505                                 }
6506                         }
6507                 }
6508         }
6509
6510         /*
6511          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
6512          *         exc->vtable->klass->name, message);
6513          */
6514         g_printerr ("\nUnhandled Exception:\n%s\n", message);
6515         
6516         if (free_message)
6517                 g_free (message);
6518 }
6519
6520 /**
6521  * mono_delegate_ctor:
6522  * @this: pointer to an uninitialized delegate object
6523  * @target: target object
6524  * @addr: pointer to native code
6525  * @method: method
6526  *
6527  * Initialize a delegate and sets a specific method, not the one
6528  * associated with addr.  This is useful when sharing generic code.
6529  * In that case addr will most probably not be associated with the
6530  * correct instantiation of the method.
6531  */
6532 void
6533 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6534 {
6535         MONO_REQ_GC_UNSAFE_MODE;
6536
6537         MonoDelegate *delegate = (MonoDelegate *)this_obj;
6538
6539         g_assert (this_obj);
6540         g_assert (addr);
6541
6542         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6543
6544         if (method)
6545                 delegate->method = method;
6546
6547         mono_stats.delegate_creations++;
6548
6549 #ifndef DISABLE_REMOTING
6550         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6551                 g_assert (method);
6552                 method = mono_marshal_get_remoting_invoke (method);
6553                 delegate->method_ptr = mono_compile_method (method);
6554                 MONO_OBJECT_SETREF (delegate, target, target);
6555         } else
6556 #endif
6557         {
6558                 delegate->method_ptr = addr;
6559                 MONO_OBJECT_SETREF (delegate, target, target);
6560         }
6561
6562         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6563         if (callbacks.init_delegate)
6564                 callbacks.init_delegate (delegate);
6565 }
6566
6567 /**
6568  * mono_delegate_ctor:
6569  * @this: pointer to an uninitialized delegate object
6570  * @target: target object
6571  * @addr: pointer to native code
6572  *
6573  * This is used to initialize a delegate.
6574  */
6575 void
6576 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6577 {
6578         MONO_REQ_GC_UNSAFE_MODE;
6579
6580         MonoDomain *domain = mono_domain_get ();
6581         MonoJitInfo *ji;
6582         MonoMethod *method = NULL;
6583
6584         g_assert (addr);
6585
6586         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6587         /* Shared code */
6588         if (!ji && domain != mono_get_root_domain ())
6589                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6590         if (ji) {
6591                 method = mono_jit_info_get_method (ji);
6592                 g_assert (!method->klass->generic_container);
6593         }
6594
6595         mono_delegate_ctor_with_method (this_obj, target, addr, method);
6596 }
6597
6598 /**
6599  * mono_method_call_message_new:
6600  * @method: method to encapsulate
6601  * @params: parameters to the method
6602  * @invoke: optional, delegate invoke.
6603  * @cb: async callback delegate.
6604  * @state: state passed to the async callback.
6605  *
6606  * Translates arguments pointers into a MonoMethodMessage.
6607  */
6608 MonoMethodMessage *
6609 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
6610                               MonoDelegate **cb, MonoObject **state)
6611 {
6612         MONO_REQ_GC_UNSAFE_MODE;
6613
6614         MonoDomain *domain = mono_domain_get ();
6615         MonoMethodSignature *sig = mono_method_signature (method);
6616         MonoMethodMessage *msg;
6617         int i, count;
6618
6619         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
6620         
6621         if (invoke) {
6622                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6623                 count =  sig->param_count - 2;
6624         } else {
6625                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6626                 count =  sig->param_count;
6627         }
6628
6629         for (i = 0; i < count; i++) {
6630                 gpointer vpos;
6631                 MonoClass *klass;
6632                 MonoObject *arg;
6633
6634                 if (sig->params [i]->byref)
6635                         vpos = *((gpointer *)params [i]);
6636                 else 
6637                         vpos = params [i];
6638
6639                 klass = mono_class_from_mono_type (sig->params [i]);
6640
6641                 if (klass->valuetype)
6642                         arg = mono_value_box (domain, klass, vpos);
6643                 else 
6644                         arg = *((MonoObject **)vpos);
6645                       
6646                 mono_array_setref (msg->args, i, arg);
6647         }
6648
6649         if (cb != NULL && state != NULL) {
6650                 *cb = *((MonoDelegate **)params [i]);
6651                 i++;
6652                 *state = *((MonoObject **)params [i]);
6653         }
6654
6655         return msg;
6656 }
6657
6658 /**
6659  * mono_method_return_message_restore:
6660  *
6661  * Restore results from message based processing back to arguments pointers
6662  */
6663 void
6664 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6665 {
6666         MONO_REQ_GC_UNSAFE_MODE;
6667
6668         MonoMethodSignature *sig = mono_method_signature (method);
6669         int i, j, type, size, out_len;
6670         
6671         if (out_args == NULL)
6672                 return;
6673         out_len = mono_array_length (out_args);
6674         if (out_len == 0)
6675                 return;
6676
6677         for (i = 0, j = 0; i < sig->param_count; i++) {
6678                 MonoType *pt = sig->params [i];
6679
6680                 if (pt->byref) {
6681                         char *arg;
6682                         if (j >= out_len)
6683                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6684
6685                         arg = (char *)mono_array_get (out_args, gpointer, j);
6686                         type = pt->type;
6687
6688                         g_assert (type != MONO_TYPE_VOID);
6689
6690                         if (MONO_TYPE_IS_REFERENCE (pt)) {
6691                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6692                         } else {
6693                                 if (arg) {
6694                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6695                                         size = mono_class_value_size (klass, NULL);
6696                                         if (klass->has_references)
6697                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6698                                         else
6699                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6700                                 } else {
6701                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6702                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6703                                 }
6704                         }
6705
6706                         j++;
6707                 }
6708         }
6709 }
6710
6711 #ifndef DISABLE_REMOTING
6712
6713 /**
6714  * mono_load_remote_field:
6715  * @this: pointer to an object
6716  * @klass: klass of the object containing @field
6717  * @field: the field to load
6718  * @res: a storage to store the result
6719  *
6720  * This method is called by the runtime on attempts to load fields of
6721  * transparent proxy objects. @this points to such TP, @klass is the class of
6722  * the object containing @field. @res is a storage location which can be
6723  * used to store the result.
6724  *
6725  * Returns: an address pointing to the value of field.
6726  */
6727 gpointer
6728 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6729 {
6730         MONO_REQ_GC_UNSAFE_MODE;
6731
6732         static MonoMethod *getter = NULL;
6733         MonoDomain *domain = mono_domain_get ();
6734         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6735         MonoClass *field_class;
6736         MonoMethodMessage *msg;
6737         MonoArray *out_args;
6738         MonoObject *exc;
6739         char* full_name;
6740
6741         g_assert (mono_object_is_transparent_proxy (this_obj));
6742         g_assert (res != NULL);
6743
6744         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6745                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6746                 return res;
6747         }
6748         
6749         if (!getter) {
6750                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6751                 if (!getter)
6752                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6753         }
6754         
6755         field_class = mono_class_from_mono_type (field->type);
6756
6757         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6758         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6759         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6760
6761         full_name = mono_type_get_full_name (klass);
6762         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6763         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6764         g_free (full_name);
6765
6766         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6767
6768         if (exc) mono_raise_exception ((MonoException *)exc);
6769
6770         if (mono_array_length (out_args) == 0)
6771                 return NULL;
6772
6773         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6774
6775         if (field_class->valuetype) {
6776                 return ((char *)*res) + sizeof (MonoObject);
6777         } else
6778                 return res;
6779 }
6780
6781 /**
6782  * mono_load_remote_field_new:
6783  * @this: 
6784  * @klass: 
6785  * @field:
6786  *
6787  * Missing documentation.
6788  */
6789 MonoObject *
6790 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6791 {
6792         MONO_REQ_GC_UNSAFE_MODE;
6793
6794         static MonoMethod *getter = NULL;
6795         MonoDomain *domain = mono_domain_get ();
6796         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6797         MonoClass *field_class;
6798         MonoMethodMessage *msg;
6799         MonoArray *out_args;
6800         MonoObject *exc, *res;
6801         char* full_name;
6802
6803         g_assert (mono_object_is_transparent_proxy (this_obj));
6804
6805         field_class = mono_class_from_mono_type (field->type);
6806
6807         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6808                 gpointer val;
6809                 if (field_class->valuetype) {
6810                         res = mono_object_new (domain, field_class);
6811                         val = ((gchar *) res) + sizeof (MonoObject);
6812                 } else {
6813                         val = &res;
6814                 }
6815                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6816                 return res;
6817         }
6818
6819         if (!getter) {
6820                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6821                 if (!getter)
6822                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6823         }
6824         
6825         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6826         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6827
6828         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6829
6830         full_name = mono_type_get_full_name (klass);
6831         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6832         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6833         g_free (full_name);
6834
6835         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6836
6837         if (exc) mono_raise_exception ((MonoException *)exc);
6838
6839         if (mono_array_length (out_args) == 0)
6840                 res = NULL;
6841         else
6842                 res = mono_array_get (out_args, MonoObject *, 0);
6843
6844         return res;
6845 }
6846
6847 /**
6848  * mono_store_remote_field:
6849  * @this_obj: pointer to an object
6850  * @klass: klass of the object containing @field
6851  * @field: the field to load
6852  * @val: the value/object to store
6853  *
6854  * This method is called by the runtime on attempts to store fields of
6855  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6856  * the object containing @field. @val is the new value to store in @field.
6857  */
6858 void
6859 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6860 {
6861         MONO_REQ_GC_UNSAFE_MODE;
6862
6863         static MonoMethod *setter = NULL;
6864         MonoDomain *domain = mono_domain_get ();
6865         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6866         MonoClass *field_class;
6867         MonoMethodMessage *msg;
6868         MonoArray *out_args;
6869         MonoObject *exc;
6870         MonoObject *arg;
6871         char* full_name;
6872
6873         g_assert (mono_object_is_transparent_proxy (this_obj));
6874
6875         field_class = mono_class_from_mono_type (field->type);
6876
6877         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6878                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6879                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6880                 return;
6881         }
6882
6883         if (!setter) {
6884                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6885                 if (!setter)
6886                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6887         }
6888
6889         if (field_class->valuetype)
6890                 arg = mono_value_box (domain, field_class, val);
6891         else 
6892                 arg = *((MonoObject **)val);
6893                 
6894
6895         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6896         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6897
6898         full_name = mono_type_get_full_name (klass);
6899         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6900         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6901         mono_array_setref (msg->args, 2, arg);
6902         g_free (full_name);
6903
6904         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6905
6906         if (exc) mono_raise_exception ((MonoException *)exc);
6907 }
6908
6909 /**
6910  * mono_store_remote_field_new:
6911  * @this_obj:
6912  * @klass:
6913  * @field:
6914  * @arg:
6915  *
6916  * Missing documentation
6917  */
6918 void
6919 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6920 {
6921         MONO_REQ_GC_UNSAFE_MODE;
6922
6923         static MonoMethod *setter = NULL;
6924         MonoDomain *domain = mono_domain_get ();
6925         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6926         MonoClass *field_class;
6927         MonoMethodMessage *msg;
6928         MonoArray *out_args;
6929         MonoObject *exc;
6930         char* full_name;
6931
6932         g_assert (mono_object_is_transparent_proxy (this_obj));
6933
6934         field_class = mono_class_from_mono_type (field->type);
6935
6936         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6937                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6938                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6939                 return;
6940         }
6941
6942         if (!setter) {
6943                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6944                 if (!setter)
6945                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6946         }
6947
6948         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6949         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6950
6951         full_name = mono_type_get_full_name (klass);
6952         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6953         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6954         mono_array_setref (msg->args, 2, arg);
6955         g_free (full_name);
6956
6957         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6958
6959         if (exc) mono_raise_exception ((MonoException *)exc);
6960 }
6961 #endif
6962
6963 /*
6964  * mono_create_ftnptr:
6965  *
6966  *   Given a function address, create a function descriptor for it.
6967  * This is only needed on some platforms.
6968  */
6969 gpointer
6970 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6971 {
6972         return callbacks.create_ftnptr (domain, addr);
6973 }
6974
6975 /*
6976  * mono_get_addr_from_ftnptr:
6977  *
6978  *   Given a pointer to a function descriptor, return the function address.
6979  * This is only needed on some platforms.
6980  */
6981 gpointer
6982 mono_get_addr_from_ftnptr (gpointer descr)
6983 {
6984         return callbacks.get_addr_from_ftnptr (descr);
6985 }       
6986
6987 /**
6988  * mono_string_chars:
6989  * @s: a MonoString
6990  *
6991  * Returns a pointer to the UCS16 characters stored in the MonoString
6992  */
6993 gunichar2 *
6994 mono_string_chars (MonoString *s)
6995 {
6996         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
6997
6998         return s->chars;
6999 }
7000
7001 /**
7002  * mono_string_length:
7003  * @s: MonoString
7004  *
7005  * Returns the lenght in characters of the string
7006  */
7007 int
7008 mono_string_length (MonoString *s)
7009 {
7010         MONO_REQ_GC_UNSAFE_MODE;
7011
7012         return s->length;
7013 }
7014
7015 /**
7016  * mono_array_length:
7017  * @array: a MonoArray*
7018  *
7019  * Returns the total number of elements in the array. This works for
7020  * both vectors and multidimensional arrays.
7021  */
7022 uintptr_t
7023 mono_array_length (MonoArray *array)
7024 {
7025         MONO_REQ_GC_UNSAFE_MODE;
7026
7027         return array->max_length;
7028 }
7029
7030 /**
7031  * mono_array_addr_with_size:
7032  * @array: a MonoArray*
7033  * @size: size of the array elements
7034  * @idx: index into the array
7035  *
7036  * Returns the address of the @idx element in the array.
7037  */
7038 char*
7039 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7040 {
7041         MONO_REQ_GC_UNSAFE_MODE;
7042
7043         return ((char*)(array)->vector) + size * idx;
7044 }
7045
7046
7047 MonoArray *
7048 mono_glist_to_array (GList *list, MonoClass *eclass) 
7049 {
7050         MonoDomain *domain = mono_domain_get ();
7051         MonoArray *res;
7052         int len, i;
7053
7054         if (!list)
7055                 return NULL;
7056
7057         len = g_list_length (list);
7058         res = mono_array_new (domain, eclass, len);
7059
7060         for (i = 0; list; list = list->next, i++)
7061                 mono_array_set (res, gpointer, i, list->data);
7062
7063         return res;
7064 }
7065