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