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