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