Merge pull request #2522 from ludovic-henry/test-socketresponder-task
[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)
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         MonoObject *result;
2900
2901         if (mono_runtime_get_no_exec ())
2902                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2903
2904         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2905                 mono_profiler_method_start_invoke (method);
2906
2907         result = do_runtime_invoke (method, obj, params, exc);
2908
2909         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2910                 mono_profiler_method_end_invoke (method);
2911
2912         return result;
2913 }
2914
2915 /**
2916  * mono_method_get_unmanaged_thunk:
2917  * @method: method to generate a thunk for.
2918  *
2919  * Returns an unmanaged->managed thunk that can be used to call
2920  * a managed method directly from C.
2921  *
2922  * The thunk's C signature closely matches the managed signature:
2923  *
2924  * C#: public bool Equals (object obj);
2925  * C:  typedef MonoBoolean (*Equals)(MonoObject*,
2926  *             MonoObject*, MonoException**);
2927  *
2928  * The 1st ("this") parameter must not be used with static methods:
2929  *
2930  * C#: public static bool ReferenceEquals (object a, object b);
2931  * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2932  *             MonoException**);
2933  *
2934  * The last argument must be a non-null pointer of a MonoException* pointer.
2935  * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2936  * exception has been thrown in managed code. Otherwise it will point
2937  * to the MonoException* caught by the thunk. In this case, the result of
2938  * the thunk is undefined:
2939  *
2940  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2941  * MonoException *ex = NULL;
2942  * Equals func = mono_method_get_unmanaged_thunk (method);
2943  * MonoBoolean res = func (thisObj, objToCompare, &ex);
2944  * if (ex) {
2945  *    // handle exception
2946  * }
2947  *
2948  * The calling convention of the thunk matches the platform's default
2949  * convention. This means that under Windows, C declarations must
2950  * contain the __stdcall attribute:
2951  *
2952  * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2953  *             MonoObject*, MonoException**);
2954  *
2955  * LIMITATIONS
2956  *
2957  * Value type arguments and return values are treated as they were objects:
2958  *
2959  * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2960  * C:  typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2961  *
2962  * Arguments must be properly boxed upon trunk's invocation, while return
2963  * values must be unboxed.
2964  */
2965 gpointer
2966 mono_method_get_unmanaged_thunk (MonoMethod *method)
2967 {
2968         MONO_REQ_GC_NEUTRAL_MODE;
2969         MONO_REQ_API_ENTRYPOINT;
2970
2971         gpointer res;
2972
2973         MONO_PREPARE_RESET_BLOCKING;
2974         method = mono_marshal_get_thunk_invoke_wrapper (method);
2975         res = mono_compile_method (method);
2976         MONO_FINISH_RESET_BLOCKING;
2977
2978         return res;
2979 }
2980
2981 void
2982 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2983 {
2984         MONO_REQ_GC_UNSAFE_MODE;
2985
2986         int t;
2987         if (type->byref) {
2988                 /* object fields cannot be byref, so we don't need a
2989                    wbarrier here */
2990                 gpointer *p = (gpointer*)dest;
2991                 *p = value;
2992                 return;
2993         }
2994         t = type->type;
2995 handle_enum:
2996         switch (t) {
2997         case MONO_TYPE_BOOLEAN:
2998         case MONO_TYPE_I1:
2999         case MONO_TYPE_U1: {
3000                 guint8 *p = (guint8*)dest;
3001                 *p = value ? *(guint8*)value : 0;
3002                 return;
3003         }
3004         case MONO_TYPE_I2:
3005         case MONO_TYPE_U2:
3006         case MONO_TYPE_CHAR: {
3007                 guint16 *p = (guint16*)dest;
3008                 *p = value ? *(guint16*)value : 0;
3009                 return;
3010         }
3011 #if SIZEOF_VOID_P == 4
3012         case MONO_TYPE_I:
3013         case MONO_TYPE_U:
3014 #endif
3015         case MONO_TYPE_I4:
3016         case MONO_TYPE_U4: {
3017                 gint32 *p = (gint32*)dest;
3018                 *p = value ? *(gint32*)value : 0;
3019                 return;
3020         }
3021 #if SIZEOF_VOID_P == 8
3022         case MONO_TYPE_I:
3023         case MONO_TYPE_U:
3024 #endif
3025         case MONO_TYPE_I8:
3026         case MONO_TYPE_U8: {
3027                 gint64 *p = (gint64*)dest;
3028                 *p = value ? *(gint64*)value : 0;
3029                 return;
3030         }
3031         case MONO_TYPE_R4: {
3032                 float *p = (float*)dest;
3033                 *p = value ? *(float*)value : 0;
3034                 return;
3035         }
3036         case MONO_TYPE_R8: {
3037                 double *p = (double*)dest;
3038                 *p = value ? *(double*)value : 0;
3039                 return;
3040         }
3041         case MONO_TYPE_STRING:
3042         case MONO_TYPE_SZARRAY:
3043         case MONO_TYPE_CLASS:
3044         case MONO_TYPE_OBJECT:
3045         case MONO_TYPE_ARRAY:
3046                 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3047                 return;
3048         case MONO_TYPE_FNPTR:
3049         case MONO_TYPE_PTR: {
3050                 gpointer *p = (gpointer*)dest;
3051                 *p = deref_pointer? *(gpointer*)value: value;
3052                 return;
3053         }
3054         case MONO_TYPE_VALUETYPE:
3055                 /* note that 't' and 'type->type' can be different */
3056                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3057                         t = mono_class_enum_basetype (type->data.klass)->type;
3058                         goto handle_enum;
3059                 } else {
3060                         MonoClass *klass = mono_class_from_mono_type (type);
3061                         int size = mono_class_value_size (klass, NULL);
3062                         if (value == NULL)
3063                                 mono_gc_bzero_atomic (dest, size);
3064                         else
3065                                 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3066                 }
3067                 return;
3068         case MONO_TYPE_GENERICINST:
3069                 t = type->data.generic_class->container_class->byval_arg.type;
3070                 goto handle_enum;
3071         default:
3072                 g_error ("got type %x", type->type);
3073         }
3074 }
3075
3076 /**
3077  * mono_field_set_value:
3078  * @obj: Instance object
3079  * @field: MonoClassField describing the field to set
3080  * @value: The value to be set
3081  *
3082  * Sets the value of the field described by @field in the object instance @obj
3083  * to the value passed in @value.   This method should only be used for instance
3084  * fields.   For static fields, use mono_field_static_set_value.
3085  *
3086  * The value must be on the native format of the field type. 
3087  */
3088 void
3089 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3090 {
3091         MONO_REQ_GC_UNSAFE_MODE;
3092
3093         void *dest;
3094
3095         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3096
3097         dest = (char*)obj + field->offset;
3098         mono_copy_value (field->type, dest, value, FALSE);
3099 }
3100
3101 /**
3102  * mono_field_static_set_value:
3103  * @field: MonoClassField describing the field to set
3104  * @value: The value to be set
3105  *
3106  * Sets the value of the static field described by @field
3107  * to the value passed in @value.
3108  *
3109  * The value must be on the native format of the field type. 
3110  */
3111 void
3112 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3113 {
3114         MONO_REQ_GC_UNSAFE_MODE;
3115
3116         void *dest;
3117
3118         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3119         /* you cant set a constant! */
3120         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3121
3122         if (field->offset == -1) {
3123                 /* Special static */
3124                 gpointer addr;
3125
3126                 mono_domain_lock (vt->domain);
3127                 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3128                 mono_domain_unlock (vt->domain);
3129                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3130         } else {
3131                 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3132         }
3133         mono_copy_value (field->type, dest, value, FALSE);
3134 }
3135
3136 /**
3137  * mono_vtable_get_static_field_data:
3138  *
3139  * Internal use function: return a pointer to the memory holding the static fields
3140  * for a class or NULL if there are no static fields.
3141  * This is exported only for use by the debugger.
3142  */
3143 void *
3144 mono_vtable_get_static_field_data (MonoVTable *vt)
3145 {
3146         MONO_REQ_GC_NEUTRAL_MODE
3147
3148         if (!vt->has_static_fields)
3149                 return NULL;
3150         return vt->vtable [vt->klass->vtable_size];
3151 }
3152
3153 static guint8*
3154 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3155 {
3156         MONO_REQ_GC_UNSAFE_MODE;
3157
3158         guint8 *src;
3159
3160         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3161                 if (field->offset == -1) {
3162                         /* Special static */
3163                         gpointer addr;
3164
3165                         mono_domain_lock (vt->domain);
3166                         addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3167                         mono_domain_unlock (vt->domain);
3168                         src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3169                 } else {
3170                         src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3171                 }
3172         } else {
3173                 src = (guint8*)obj + field->offset;
3174         }
3175
3176         return src;
3177 }
3178
3179 /**
3180  * mono_field_get_value:
3181  * @obj: Object instance
3182  * @field: MonoClassField describing the field to fetch information from
3183  * @value: pointer to the location where the value will be stored
3184  *
3185  * Use this routine to get the value of the field @field in the object
3186  * passed.
3187  *
3188  * The pointer provided by value must be of the field type, for reference
3189  * types this is a MonoObject*, for value types its the actual pointer to
3190  * the value type.
3191  *
3192  * For example:
3193  *     int i;
3194  *     mono_field_get_value (obj, int_field, &i);
3195  */
3196 void
3197 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3198 {
3199         MONO_REQ_GC_UNSAFE_MODE;
3200
3201         void *src;
3202
3203         g_assert (obj);
3204
3205         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3206
3207         src = (char*)obj + field->offset;
3208         mono_copy_value (field->type, value, src, TRUE);
3209 }
3210
3211 /**
3212  * mono_field_get_value_object:
3213  * @domain: domain where the object will be created (if boxing)
3214  * @field: MonoClassField describing the field to fetch information from
3215  * @obj: The object instance for the field.
3216  *
3217  * Returns: a new MonoObject with the value from the given field.  If the
3218  * field represents a value type, the value is boxed.
3219  *
3220  */
3221 MonoObject *
3222 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3223 {       
3224         MONO_REQ_GC_UNSAFE_MODE;
3225
3226         MonoError error;
3227         MonoObject *o;
3228         MonoClass *klass;
3229         MonoVTable *vtable = NULL;
3230         gchar *v;
3231         gboolean is_static = FALSE;
3232         gboolean is_ref = FALSE;
3233         gboolean is_literal = FALSE;
3234         gboolean is_ptr = FALSE;
3235         MonoType *type = mono_field_get_type_checked (field, &error);
3236
3237         if (!mono_error_ok (&error))
3238                 mono_error_raise_exception (&error);
3239
3240         switch (type->type) {
3241         case MONO_TYPE_STRING:
3242         case MONO_TYPE_OBJECT:
3243         case MONO_TYPE_CLASS:
3244         case MONO_TYPE_ARRAY:
3245         case MONO_TYPE_SZARRAY:
3246                 is_ref = TRUE;
3247                 break;
3248         case MONO_TYPE_U1:
3249         case MONO_TYPE_I1:
3250         case MONO_TYPE_BOOLEAN:
3251         case MONO_TYPE_U2:
3252         case MONO_TYPE_I2:
3253         case MONO_TYPE_CHAR:
3254         case MONO_TYPE_U:
3255         case MONO_TYPE_I:
3256         case MONO_TYPE_U4:
3257         case MONO_TYPE_I4:
3258         case MONO_TYPE_R4:
3259         case MONO_TYPE_U8:
3260         case MONO_TYPE_I8:
3261         case MONO_TYPE_R8:
3262         case MONO_TYPE_VALUETYPE:
3263                 is_ref = type->byref;
3264                 break;
3265         case MONO_TYPE_GENERICINST:
3266                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3267                 break;
3268         case MONO_TYPE_PTR:
3269                 is_ptr = TRUE;
3270                 break;
3271         default:
3272                 g_error ("type 0x%x not handled in "
3273                          "mono_field_get_value_object", type->type);
3274                 return NULL;
3275         }
3276
3277         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3278                 is_literal = TRUE;
3279
3280         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3281                 is_static = TRUE;
3282
3283                 if (!is_literal) {
3284                         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3285                         if (!vtable->initialized)
3286                                 mono_runtime_class_init (vtable);
3287                 }
3288         } else {
3289                 g_assert (obj);
3290         }
3291         
3292         if (is_ref) {
3293                 if (is_literal) {
3294                         get_default_field_value (domain, field, &o);
3295                 } else if (is_static) {
3296                         mono_field_static_get_value (vtable, field, &o);
3297                 } else {
3298                         mono_field_get_value (obj, field, &o);
3299                 }
3300                 return o;
3301         }
3302
3303         if (is_ptr) {
3304                 static MonoMethod *m;
3305                 gpointer args [2];
3306                 gpointer *ptr;
3307                 gpointer v;
3308
3309                 if (!m) {
3310                         MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3311                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3312                         g_assert (m);
3313                 }
3314
3315                 v = &ptr;
3316                 if (is_literal) {
3317                         get_default_field_value (domain, field, v);
3318                 } else if (is_static) {
3319                         mono_field_static_get_value (vtable, field, v);
3320                 } else {
3321                         mono_field_get_value (obj, field, v);
3322                 }
3323
3324                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3325                 args [0] = ptr ? *ptr : NULL;
3326                 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3327                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3328
3329                 return mono_runtime_invoke (m, NULL, args, NULL);
3330         }
3331
3332         /* boxed value type */
3333         klass = mono_class_from_mono_type (type);
3334
3335         if (mono_class_is_nullable (klass))
3336                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3337
3338         o = mono_object_new (domain, klass);
3339         v = ((gchar *) o) + sizeof (MonoObject);
3340
3341         if (is_literal) {
3342                 get_default_field_value (domain, field, v);
3343         } else if (is_static) {
3344                 mono_field_static_get_value (vtable, field, v);
3345         } else {
3346                 mono_field_get_value (obj, field, v);
3347         }
3348
3349         return o;
3350 }
3351
3352 int
3353 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3354 {
3355         MONO_REQ_GC_UNSAFE_MODE;
3356
3357         int retval = 0;
3358         const char *p = blob;
3359         mono_metadata_decode_blob_size (p, &p);
3360
3361         switch (type) {
3362         case MONO_TYPE_BOOLEAN:
3363         case MONO_TYPE_U1:
3364         case MONO_TYPE_I1:
3365                 *(guint8 *) value = *p;
3366                 break;
3367         case MONO_TYPE_CHAR:
3368         case MONO_TYPE_U2:
3369         case MONO_TYPE_I2:
3370                 *(guint16*) value = read16 (p);
3371                 break;
3372         case MONO_TYPE_U4:
3373         case MONO_TYPE_I4:
3374                 *(guint32*) value = read32 (p);
3375                 break;
3376         case MONO_TYPE_U8:
3377         case MONO_TYPE_I8:
3378                 *(guint64*) value = read64 (p);
3379                 break;
3380         case MONO_TYPE_R4:
3381                 readr4 (p, (float*) value);
3382                 break;
3383         case MONO_TYPE_R8:
3384                 readr8 (p, (double*) value);
3385                 break;
3386         case MONO_TYPE_STRING:
3387                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3388                 break;
3389         case MONO_TYPE_CLASS:
3390                 *(gpointer*) value = NULL;
3391                 break;
3392         default:
3393                 retval = -1;
3394                 g_warning ("type 0x%02x should not be in constant table", type);
3395         }
3396         return retval;
3397 }
3398
3399 static void
3400 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3401 {
3402         MONO_REQ_GC_NEUTRAL_MODE;
3403
3404         MonoTypeEnum def_type;
3405         const char* data;
3406         
3407         data = mono_class_get_field_default_value (field, &def_type);
3408         mono_get_constant_value_from_blob (domain, def_type, data, value);
3409 }
3410
3411 void
3412 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3413 {
3414         MONO_REQ_GC_UNSAFE_MODE;
3415
3416         void *src;
3417
3418         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3419         
3420         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3421                 get_default_field_value (vt->domain, field, value);
3422                 return;
3423         }
3424
3425         if (field->offset == -1) {
3426                 /* Special static */
3427                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3428                 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3429         } else {
3430                 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3431         }
3432         mono_copy_value (field->type, value, src, TRUE);
3433 }
3434
3435 /**
3436  * mono_field_static_get_value:
3437  * @vt: vtable to the object
3438  * @field: MonoClassField describing the field to fetch information from
3439  * @value: where the value is returned
3440  *
3441  * Use this routine to get the value of the static field @field value.
3442  *
3443  * The pointer provided by value must be of the field type, for reference
3444  * types this is a MonoObject*, for value types its the actual pointer to
3445  * the value type.
3446  *
3447  * For example:
3448  *     int i;
3449  *     mono_field_static_get_value (vt, int_field, &i);
3450  */
3451 void
3452 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3453 {
3454         MONO_REQ_GC_NEUTRAL_MODE;
3455
3456         mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3457 }
3458
3459 /**
3460  * mono_property_set_value:
3461  * @prop: MonoProperty to set
3462  * @obj: instance object on which to act
3463  * @params: parameters to pass to the propery
3464  * @exc: optional exception
3465  *
3466  * Invokes the property's set method with the given arguments on the
3467  * object instance obj (or NULL for static properties). 
3468  * 
3469  * You can pass NULL as the exc argument if you don't want to
3470  * catch exceptions, otherwise, *exc will be set to the exception
3471  * thrown, if any.  if an exception is thrown, you can't use the
3472  * MonoObject* result from the function.
3473  */
3474 void
3475 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3476 {
3477         MONO_REQ_GC_UNSAFE_MODE;
3478
3479         do_runtime_invoke (prop->set, obj, params, exc);
3480 }
3481
3482 /**
3483  * mono_property_get_value:
3484  * @prop: MonoProperty to fetch
3485  * @obj: instance object on which to act
3486  * @params: parameters to pass to the propery
3487  * @exc: optional exception
3488  *
3489  * Invokes the property's get method with the given arguments on the
3490  * object instance obj (or NULL for static properties). 
3491  * 
3492  * You can pass NULL as the exc argument if you don't want to
3493  * catch exceptions, otherwise, *exc will be set to the exception
3494  * thrown, if any.  if an exception is thrown, you can't use the
3495  * MonoObject* result from the function.
3496  *
3497  * Returns: the value from invoking the get method on the property.
3498  */
3499 MonoObject*
3500 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3501 {
3502         MONO_REQ_GC_UNSAFE_MODE;
3503
3504         return do_runtime_invoke (prop->get, obj, params, exc);
3505 }
3506
3507 /*
3508  * mono_nullable_init:
3509  * @buf: The nullable structure to initialize.
3510  * @value: the value to initialize from
3511  * @klass: the type for the object
3512  *
3513  * Initialize the nullable structure pointed to by @buf from @value which
3514  * should be a boxed value type.   The size of @buf should be able to hold
3515  * as much data as the @klass->instance_size (which is the number of bytes
3516  * that will be copies).
3517  *
3518  * Since Nullables have variable structure, we can not define a C
3519  * structure for them.
3520  */
3521 void
3522 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3523 {
3524         MONO_REQ_GC_UNSAFE_MODE;
3525
3526         MonoClass *param_class = klass->cast_class;
3527
3528         mono_class_setup_fields_locking (klass);
3529         g_assert (klass->fields_inited);
3530                                 
3531         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3532         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3533
3534         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3535         if (value) {
3536                 if (param_class->has_references)
3537                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3538                 else
3539                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3540         } else {
3541                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3542         }
3543 }
3544
3545 /**
3546  * mono_nullable_box:
3547  * @buf: The buffer representing the data to be boxed
3548  * @klass: the type to box it as.
3549  *
3550  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3551  * @buf.
3552  */
3553 MonoObject*
3554 mono_nullable_box (guint8 *buf, MonoClass *klass)
3555 {
3556         MONO_REQ_GC_UNSAFE_MODE;
3557
3558         MonoClass *param_class = klass->cast_class;
3559
3560         mono_class_setup_fields_locking (klass);
3561         g_assert (klass->fields_inited);
3562
3563         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3564         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3565
3566         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3567                 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3568                 if (param_class->has_references)
3569                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3570                 else
3571                         mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3572                 return o;
3573         }
3574         else
3575                 return NULL;
3576 }
3577
3578 /**
3579  * mono_get_delegate_invoke:
3580  * @klass: The delegate class
3581  *
3582  * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3583  */
3584 MonoMethod *
3585 mono_get_delegate_invoke (MonoClass *klass)
3586 {
3587         MONO_REQ_GC_NEUTRAL_MODE;
3588
3589         MonoMethod *im;
3590
3591         /* This is called at runtime, so avoid the slower search in metadata */
3592         mono_class_setup_methods (klass);
3593         if (klass->exception_type)
3594                 return NULL;
3595         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3596         return im;
3597 }
3598
3599 /**
3600  * mono_get_delegate_begin_invoke:
3601  * @klass: The delegate class
3602  *
3603  * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3604  */
3605 MonoMethod *
3606 mono_get_delegate_begin_invoke (MonoClass *klass)
3607 {
3608         MONO_REQ_GC_NEUTRAL_MODE;
3609
3610         MonoMethod *im;
3611
3612         /* This is called at runtime, so avoid the slower search in metadata */
3613         mono_class_setup_methods (klass);
3614         if (klass->exception_type)
3615                 return NULL;
3616         im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3617         return im;
3618 }
3619
3620 /**
3621  * mono_get_delegate_end_invoke:
3622  * @klass: The delegate class
3623  *
3624  * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3625  */
3626 MonoMethod *
3627 mono_get_delegate_end_invoke (MonoClass *klass)
3628 {
3629         MONO_REQ_GC_NEUTRAL_MODE;
3630
3631         MonoMethod *im;
3632
3633         /* This is called at runtime, so avoid the slower search in metadata */
3634         mono_class_setup_methods (klass);
3635         if (klass->exception_type)
3636                 return NULL;
3637         im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3638         return im;
3639 }
3640
3641 /**
3642  * mono_runtime_delegate_invoke:
3643  * @delegate: pointer to a delegate object.
3644  * @params: parameters for the delegate.
3645  * @exc: Pointer to the exception result.
3646  *
3647  * Invokes the delegate method @delegate with the parameters provided.
3648  *
3649  * You can pass NULL as the exc argument if you don't want to
3650  * catch exceptions, otherwise, *exc will be set to the exception
3651  * thrown, if any.  if an exception is thrown, you can't use the
3652  * MonoObject* result from the function.
3653  */
3654 MonoObject*
3655 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3656 {
3657         MONO_REQ_GC_UNSAFE_MODE;
3658
3659         MonoMethod *im;
3660         MonoClass *klass = delegate->vtable->klass;
3661
3662         im = mono_get_delegate_invoke (klass);
3663         if (!im)
3664                 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3665
3666         return mono_runtime_invoke (im, delegate, params, exc);
3667 }
3668
3669 static char **main_args = NULL;
3670 static int num_main_args = 0;
3671
3672 /**
3673  * mono_runtime_get_main_args:
3674  *
3675  * Returns: a MonoArray with the arguments passed to the main program
3676  */
3677 MonoArray*
3678 mono_runtime_get_main_args (void)
3679 {
3680         MONO_REQ_GC_UNSAFE_MODE;
3681
3682         MonoArray *res;
3683         int i;
3684         MonoDomain *domain = mono_domain_get ();
3685
3686         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3687
3688         for (i = 0; i < num_main_args; ++i)
3689                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3690
3691         return res;
3692 }
3693
3694 static void
3695 free_main_args (void)
3696 {
3697         MONO_REQ_GC_NEUTRAL_MODE;
3698
3699         int i;
3700
3701         for (i = 0; i < num_main_args; ++i)
3702                 g_free (main_args [i]);
3703         g_free (main_args);
3704         num_main_args = 0;
3705         main_args = NULL;
3706 }
3707
3708 /**
3709  * mono_runtime_set_main_args:
3710  * @argc: number of arguments from the command line
3711  * @argv: array of strings from the command line
3712  *
3713  * Set the command line arguments from an embedding application that doesn't otherwise call
3714  * mono_runtime_run_main ().
3715  */
3716 int
3717 mono_runtime_set_main_args (int argc, char* argv[])
3718 {
3719         MONO_REQ_GC_NEUTRAL_MODE;
3720
3721         int i;
3722
3723         free_main_args ();
3724         main_args = g_new0 (char*, argc);
3725         num_main_args = argc;
3726
3727         for (i = 0; i < argc; ++i) {
3728                 gchar *utf8_arg;
3729
3730                 utf8_arg = mono_utf8_from_external (argv[i]);
3731                 if (utf8_arg == NULL) {
3732                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3733                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3734                         exit (-1);
3735                 }
3736
3737                 main_args [i] = utf8_arg;
3738         }
3739
3740         return 0;
3741 }
3742
3743 /**
3744  * mono_runtime_run_main:
3745  * @method: the method to start the application with (usually Main)
3746  * @argc: number of arguments from the command line
3747  * @argv: array of strings from the command line
3748  * @exc: excetption results
3749  *
3750  * Execute a standard Main() method (argc/argv contains the
3751  * executable name). This method also sets the command line argument value
3752  * needed by System.Environment.
3753  *
3754  * 
3755  */
3756 int
3757 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3758                        MonoObject **exc)
3759 {
3760         MONO_REQ_GC_UNSAFE_MODE;
3761
3762         int i;
3763         MonoArray *args = NULL;
3764         MonoDomain *domain = mono_domain_get ();
3765         gchar *utf8_fullpath;
3766         MonoMethodSignature *sig;
3767
3768         g_assert (method != NULL);
3769         
3770         mono_thread_set_main (mono_thread_current ());
3771
3772         main_args = g_new0 (char*, argc);
3773         num_main_args = argc;
3774
3775         if (!g_path_is_absolute (argv [0])) {
3776                 gchar *basename = g_path_get_basename (argv [0]);
3777                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3778                                                     basename,
3779                                                     NULL);
3780
3781                 utf8_fullpath = mono_utf8_from_external (fullpath);
3782                 if(utf8_fullpath == NULL) {
3783                         /* Printing the arg text will cause glib to
3784                          * whinge about "Invalid UTF-8", but at least
3785                          * its relevant, and shows the problem text
3786                          * string.
3787                          */
3788                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3789                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3790                         exit (-1);
3791                 }
3792
3793                 g_free (fullpath);
3794                 g_free (basename);
3795         } else {
3796                 utf8_fullpath = mono_utf8_from_external (argv[0]);
3797                 if(utf8_fullpath == NULL) {
3798                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3799                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3800                         exit (-1);
3801                 }
3802         }
3803
3804         main_args [0] = utf8_fullpath;
3805
3806         for (i = 1; i < argc; ++i) {
3807                 gchar *utf8_arg;
3808
3809                 utf8_arg=mono_utf8_from_external (argv[i]);
3810                 if(utf8_arg==NULL) {
3811                         /* Ditto the comment about Invalid UTF-8 here */
3812                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3813                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3814                         exit (-1);
3815                 }
3816
3817                 main_args [i] = utf8_arg;
3818         }
3819         argc--;
3820         argv++;
3821
3822         sig = mono_method_signature (method);
3823         if (!sig) {
3824                 g_print ("Unable to load Main method.\n");
3825                 exit (-1);
3826         }
3827
3828         if (sig->param_count) {
3829                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3830                 for (i = 0; i < argc; ++i) {
3831                         /* The encodings should all work, given that
3832                          * we've checked all these args for the
3833                          * main_args array.
3834                          */
3835                         gchar *str = mono_utf8_from_external (argv [i]);
3836                         MonoString *arg = mono_string_new (domain, str);
3837                         mono_array_setref (args, i, arg);
3838                         g_free (str);
3839                 }
3840         } else {
3841                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3842         }
3843         
3844         mono_assembly_set_main (method->klass->image->assembly);
3845
3846         return mono_runtime_exec_main (method, args, exc);
3847 }
3848
3849 static MonoObject*
3850 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3851 {
3852         static MonoMethod *serialize_method;
3853
3854         void *params [1];
3855         MonoObject *array;
3856
3857         if (!serialize_method) {
3858                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3859                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3860         }
3861
3862         if (!serialize_method) {
3863                 *failure = TRUE;
3864                 return NULL;
3865         }
3866
3867         g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3868
3869         params [0] = obj;
3870         *exc = NULL;
3871         array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3872         if (*exc)
3873                 *failure = TRUE;
3874
3875         return array;
3876 }
3877
3878 static MonoObject*
3879 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3880 {
3881         MONO_REQ_GC_UNSAFE_MODE;
3882
3883         static MonoMethod *deserialize_method;
3884
3885         void *params [1];
3886         MonoObject *result;
3887
3888         if (!deserialize_method) {
3889                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3890                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3891         }
3892         if (!deserialize_method) {
3893                 *failure = TRUE;
3894                 return NULL;
3895         }
3896
3897         params [0] = obj;
3898         *exc = NULL;
3899         result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3900         if (*exc)
3901                 *failure = TRUE;
3902
3903         return result;
3904 }
3905
3906 #ifndef DISABLE_REMOTING
3907 static MonoObject*
3908 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3909 {
3910         MONO_REQ_GC_UNSAFE_MODE;
3911
3912         static MonoMethod *get_proxy_method;
3913
3914         MonoError error;
3915         MonoDomain *domain = mono_domain_get ();
3916         MonoRealProxy *real_proxy;
3917         MonoReflectionType *reflection_type;
3918         MonoTransparentProxy *transparent_proxy;
3919
3920         if (!get_proxy_method)
3921                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3922
3923         g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3924
3925         real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3926         reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
3927         mono_error_raise_exception (&error); /* FIXME don't raise here */
3928
3929         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3930         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3931
3932         *exc = NULL;
3933         transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3934         if (*exc)
3935                 *failure = TRUE;
3936
3937         return (MonoObject*) transparent_proxy;
3938 }
3939 #endif /* DISABLE_REMOTING */
3940
3941 /**
3942  * mono_object_xdomain_representation
3943  * @obj: an object
3944  * @target_domain: a domain
3945  * @exc: pointer to a MonoObject*
3946  *
3947  * Creates a representation of obj in the domain target_domain.  This
3948  * is either a copy of obj arrived through via serialization and
3949  * deserialization or a proxy, depending on whether the object is
3950  * serializable or marshal by ref.  obj must not be in target_domain.
3951  *
3952  * If the object cannot be represented in target_domain, NULL is
3953  * returned and *exc is set to an appropriate exception.
3954  */
3955 MonoObject*
3956 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3957 {
3958         MONO_REQ_GC_UNSAFE_MODE;
3959
3960         MonoObject *deserialized = NULL;
3961         gboolean failure = FALSE;
3962
3963         *exc = NULL;
3964
3965 #ifndef DISABLE_REMOTING
3966         if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3967                 deserialized = make_transparent_proxy (obj, &failure, exc);
3968         } 
3969         else
3970 #endif
3971         {
3972                 MonoDomain *domain = mono_domain_get ();
3973                 MonoObject *serialized;
3974
3975                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3976                 serialized = serialize_object (obj, &failure, exc);
3977                 mono_domain_set_internal_with_options (target_domain, FALSE);
3978                 if (!failure)
3979                         deserialized = deserialize_object (serialized, &failure, exc);
3980                 if (domain != target_domain)
3981                         mono_domain_set_internal_with_options (domain, FALSE);
3982         }
3983
3984         return deserialized;
3985 }
3986
3987 /* Used in call_unhandled_exception_delegate */
3988 static MonoObject *
3989 create_unhandled_exception_eventargs (MonoObject *exc)
3990 {
3991         MONO_REQ_GC_UNSAFE_MODE;
3992
3993         MonoClass *klass;
3994         gpointer args [2];
3995         MonoMethod *method = NULL;
3996         MonoBoolean is_terminating = TRUE;
3997         MonoObject *obj;
3998
3999         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
4000         g_assert (klass);
4001
4002         mono_class_init (klass);
4003
4004         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4005         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4006         g_assert (method);
4007
4008         args [0] = exc;
4009         args [1] = &is_terminating;
4010
4011         obj = mono_object_new (mono_domain_get (), klass);
4012         mono_runtime_invoke (method, obj, args, NULL);
4013
4014         return obj;
4015 }
4016
4017 /* Used in mono_unhandled_exception */
4018 static void
4019 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4020         MONO_REQ_GC_UNSAFE_MODE;
4021
4022         MonoObject *e = NULL;
4023         gpointer pa [2];
4024         MonoDomain *current_domain = mono_domain_get ();
4025
4026         if (domain != current_domain)
4027                 mono_domain_set_internal_with_options (domain, FALSE);
4028
4029         g_assert (domain == mono_object_domain (domain->domain));
4030
4031         if (mono_object_domain (exc) != domain) {
4032                 MonoObject *serialization_exc;
4033
4034                 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4035                 if (!exc) {
4036                         if (serialization_exc) {
4037                                 MonoObject *dummy;
4038                                 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4039                                 g_assert (exc);
4040                         } else {
4041                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4042                                                 "System.Runtime.Serialization", "SerializationException",
4043                                                 "Could not serialize unhandled exception.");
4044                         }
4045                 }
4046         }
4047         g_assert (mono_object_domain (exc) == domain);
4048
4049         pa [0] = domain->domain;
4050         pa [1] = create_unhandled_exception_eventargs (exc);
4051         mono_runtime_delegate_invoke (delegate, pa, &e);
4052
4053         if (domain != current_domain)
4054                 mono_domain_set_internal_with_options (current_domain, FALSE);
4055
4056         if (e) {
4057                 MonoError error;
4058                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4059                 if (!mono_error_ok (&error)) {
4060                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4061                         mono_error_cleanup (&error);
4062                 } else {
4063                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
4064                         g_free (msg);
4065                 }
4066         }
4067 }
4068
4069 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4070
4071 /**
4072  * mono_runtime_unhandled_exception_policy_set:
4073  * @policy: the new policy
4074  * 
4075  * This is a VM internal routine.
4076  *
4077  * Sets the runtime policy for handling unhandled exceptions.
4078  */
4079 void
4080 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4081         runtime_unhandled_exception_policy = policy;
4082 }
4083
4084 /**
4085  * mono_runtime_unhandled_exception_policy_get:
4086  *
4087  * This is a VM internal routine.
4088  *
4089  * Gets the runtime policy for handling unhandled exceptions.
4090  */
4091 MonoRuntimeUnhandledExceptionPolicy
4092 mono_runtime_unhandled_exception_policy_get (void) {
4093         return runtime_unhandled_exception_policy;
4094 }
4095
4096 /**
4097  * mono_unhandled_exception:
4098  * @exc: exception thrown
4099  *
4100  * This is a VM internal routine.
4101  *
4102  * We call this function when we detect an unhandled exception
4103  * in the default domain.
4104  *
4105  * It invokes the * UnhandledException event in AppDomain or prints
4106  * a warning to the console 
4107  */
4108 void
4109 mono_unhandled_exception (MonoObject *exc)
4110 {
4111         MONO_REQ_GC_UNSAFE_MODE;
4112
4113         MonoClassField *field;
4114         MonoDomain *current_domain, *root_domain;
4115         MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4116
4117         if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4118                 return;
4119
4120         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4121         g_assert (field);
4122
4123         current_domain = mono_domain_get ();
4124         root_domain = mono_get_root_domain ();
4125
4126         root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4127         if (current_domain != root_domain)
4128                 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4129
4130         /* set exitcode only if we will abort the process */
4131         if (!current_appdomain_delegate && !root_appdomain_delegate) {
4132                 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4133                      || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4134                 {
4135                         mono_environment_exitcode_set (1);
4136                 }
4137
4138                 mono_print_unhandled_exception (exc);
4139         } else {
4140                 if (root_appdomain_delegate)
4141                         call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4142                 if (current_appdomain_delegate)
4143                         call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4144         }
4145 }
4146
4147 /**
4148  * mono_runtime_exec_managed_code:
4149  * @domain: Application domain
4150  * @main_func: function to invoke from the execution thread
4151  * @main_args: parameter to the main_func
4152  *
4153  * Launch a new thread to execute a function
4154  *
4155  * main_func is called back from the thread with main_args as the
4156  * parameter.  The callback function is expected to start Main()
4157  * eventually.  This function then waits for all managed threads to
4158  * finish.
4159  * It is not necesseray anymore to execute managed code in a subthread,
4160  * so this function should not be used anymore by default: just
4161  * execute the code and then call mono_thread_manage ().
4162  */
4163 void
4164 mono_runtime_exec_managed_code (MonoDomain *domain,
4165                                 MonoMainThreadFunc main_func,
4166                                 gpointer main_args)
4167 {
4168         mono_thread_create (domain, main_func, main_args);
4169
4170         mono_thread_manage ();
4171 }
4172
4173 /*
4174  * Execute a standard Main() method (args doesn't contain the
4175  * executable name).
4176  */
4177 int
4178 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4179 {
4180         MONO_REQ_GC_UNSAFE_MODE;
4181
4182         MonoDomain *domain;
4183         gpointer pa [1];
4184         int rval;
4185         MonoCustomAttrInfo* cinfo;
4186         gboolean has_stathread_attribute;
4187         MonoInternalThread* thread = mono_thread_internal_current ();
4188
4189         g_assert (args);
4190
4191         pa [0] = args;
4192
4193         domain = mono_object_domain (args);
4194         if (!domain->entry_assembly) {
4195                 gchar *str;
4196                 MonoAssembly *assembly;
4197
4198                 assembly = method->klass->image->assembly;
4199                 domain->entry_assembly = assembly;
4200                 /* Domains created from another domain already have application_base and configuration_file set */
4201                 if (domain->setup->application_base == NULL) {
4202                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4203                 }
4204
4205                 if (domain->setup->configuration_file == NULL) {
4206                         str = g_strconcat (assembly->image->name, ".config", NULL);
4207                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4208                         g_free (str);
4209                         mono_domain_set_options_from_config (domain);
4210                 }
4211         }
4212
4213         cinfo = mono_custom_attrs_from_method (method);
4214         if (cinfo) {
4215                 static MonoClass *stathread_attribute = NULL;
4216                 if (!stathread_attribute)
4217                         stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4218                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4219                 if (!cinfo->cached)
4220                         mono_custom_attrs_free (cinfo);
4221         } else {
4222                 has_stathread_attribute = FALSE;
4223         }
4224         if (has_stathread_attribute) {
4225                 thread->apartment_state = ThreadApartmentState_STA;
4226         } else {
4227                 thread->apartment_state = ThreadApartmentState_MTA;
4228         }
4229         mono_thread_init_apartment_state ();
4230
4231         /* FIXME: check signature of method */
4232         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4233                 MonoObject *res;
4234                 res = mono_runtime_invoke (method, NULL, pa, exc);
4235                 if (!exc || !*exc)
4236                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4237                 else
4238                         rval = -1;
4239
4240                 mono_environment_exitcode_set (rval);
4241         } else {
4242                 mono_runtime_invoke (method, NULL, pa, exc);
4243                 if (!exc || !*exc)
4244                         rval = 0;
4245                 else {
4246                         /* If the return type of Main is void, only
4247                          * set the exitcode if an exception was thrown
4248                          * (we don't want to blow away an
4249                          * explicitly-set exit code)
4250                          */
4251                         rval = -1;
4252                         mono_environment_exitcode_set (rval);
4253                 }
4254         }
4255
4256         return rval;
4257 }
4258
4259 /**
4260  * mono_runtime_invoke_array:
4261  * @method: method to invoke
4262  * @obJ: object instance
4263  * @params: arguments to the method
4264  * @exc: exception information.
4265  *
4266  * Invokes the method represented by @method on the object @obj.
4267  *
4268  * obj is the 'this' pointer, it should be NULL for static
4269  * methods, a MonoObject* for object instances and a pointer to
4270  * the value type for value types.
4271  *
4272  * The params array contains the arguments to the method with the
4273  * same convention: MonoObject* pointers for object instances and
4274  * pointers to the value type otherwise. The _invoke_array
4275  * variant takes a C# object[] as the params argument (MonoArray
4276  * *params): in this case the value types are boxed inside the
4277  * respective reference representation.
4278  * 
4279  * From unmanaged code you'll usually use the
4280  * mono_runtime_invoke() variant.
4281  *
4282  * Note that this function doesn't handle virtual methods for
4283  * you, it will exec the exact method you pass: we still need to
4284  * expose a function to lookup the derived class implementation
4285  * of a virtual method (there are examples of this in the code,
4286  * though).
4287  * 
4288  * You can pass NULL as the exc argument if you don't want to
4289  * catch exceptions, otherwise, *exc will be set to the exception
4290  * thrown, if any.  if an exception is thrown, you can't use the
4291  * MonoObject* result from the function.
4292  * 
4293  * If the method returns a value type, it is boxed in an object
4294  * reference.
4295  */
4296 MonoObject*
4297 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4298                            MonoObject **exc)
4299 {
4300         MONO_REQ_GC_UNSAFE_MODE;
4301
4302         MonoError error;
4303         MonoMethodSignature *sig = mono_method_signature (method);
4304         gpointer *pa = NULL;
4305         MonoObject *res;
4306         int i;
4307         gboolean has_byref_nullables = FALSE;
4308
4309         if (NULL != params) {
4310                 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4311                 for (i = 0; i < mono_array_length (params); i++) {
4312                         MonoType *t = sig->params [i];
4313
4314                 again:
4315                         switch (t->type) {
4316                         case MONO_TYPE_U1:
4317                         case MONO_TYPE_I1:
4318                         case MONO_TYPE_BOOLEAN:
4319                         case MONO_TYPE_U2:
4320                         case MONO_TYPE_I2:
4321                         case MONO_TYPE_CHAR:
4322                         case MONO_TYPE_U:
4323                         case MONO_TYPE_I:
4324                         case MONO_TYPE_U4:
4325                         case MONO_TYPE_I4:
4326                         case MONO_TYPE_U8:
4327                         case MONO_TYPE_I8:
4328                         case MONO_TYPE_R4:
4329                         case MONO_TYPE_R8:
4330                         case MONO_TYPE_VALUETYPE:
4331                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4332                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4333                                         pa [i] = mono_array_get (params, MonoObject*, i);
4334                                         if (t->byref)
4335                                                 has_byref_nullables = TRUE;
4336                                 } else {
4337                                         /* MS seems to create the objects if a null is passed in */
4338                                         if (!mono_array_get (params, MonoObject*, i))
4339                                                 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
4340
4341                                         if (t->byref) {
4342                                                 /*
4343                                                  * We can't pass the unboxed vtype byref to the callee, since
4344                                                  * that would mean the callee would be able to modify boxed
4345                                                  * primitive types. So we (and MS) make a copy of the boxed
4346                                                  * object, pass that to the callee, and replace the original
4347                                                  * boxed object in the arg array with the copy.
4348                                                  */
4349                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4350                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4351                                                 mono_array_setref (params, i, copy);
4352                                         }
4353                                                 
4354                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4355                                 }
4356                                 break;
4357                         case MONO_TYPE_STRING:
4358                         case MONO_TYPE_OBJECT:
4359                         case MONO_TYPE_CLASS:
4360                         case MONO_TYPE_ARRAY:
4361                         case MONO_TYPE_SZARRAY:
4362                                 if (t->byref)
4363                                         pa [i] = mono_array_addr (params, MonoObject*, i);
4364                                         // FIXME: I need to check this code path
4365                                 else
4366                                         pa [i] = mono_array_get (params, MonoObject*, i);
4367                                 break;
4368                         case MONO_TYPE_GENERICINST:
4369                                 if (t->byref)
4370                                         t = &t->data.generic_class->container_class->this_arg;
4371                                 else
4372                                         t = &t->data.generic_class->container_class->byval_arg;
4373                                 goto again;
4374                         case MONO_TYPE_PTR: {
4375                                 MonoObject *arg;
4376
4377                                 /* The argument should be an IntPtr */
4378                                 arg = mono_array_get (params, MonoObject*, i);
4379                                 if (arg == NULL) {
4380                                         pa [i] = NULL;
4381                                 } else {
4382                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4383                                         pa [i] = ((MonoIntPtr*)arg)->m_value;
4384                                 }
4385                                 break;
4386                         }
4387                         default:
4388                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4389                         }
4390                 }
4391         }
4392
4393         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4394                 void *o = obj;
4395
4396                 if (mono_class_is_nullable (method->klass)) {
4397                         /* Need to create a boxed vtype instead */
4398                         g_assert (!obj);
4399
4400                         if (!params)
4401                                 return NULL;
4402                         else
4403                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4404                 }
4405
4406                 if (!obj) {
4407                         obj = mono_object_new (mono_domain_get (), method->klass);
4408                         g_assert (obj); /*maybe we should raise a TLE instead?*/
4409 #ifndef DISABLE_REMOTING
4410                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4411                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4412                         }
4413 #endif
4414                         if (method->klass->valuetype)
4415                                 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4416                         else
4417                                 o = obj;
4418                 } else if (method->klass->valuetype) {
4419                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
4420                 }
4421
4422                 mono_runtime_invoke (method, o, pa, exc);
4423                 return (MonoObject *)obj;
4424         } else {
4425                 if (mono_class_is_nullable (method->klass)) {
4426                         MonoObject *nullable;
4427
4428                         /* Convert the unboxed vtype into a Nullable structure */
4429                         nullable = mono_object_new (mono_domain_get (), method->klass);
4430
4431                         mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4432                         obj = mono_object_unbox (nullable);
4433                 }
4434
4435                 /* obj must be already unboxed if needed */
4436                 res = mono_runtime_invoke (method, obj, pa, exc);
4437
4438                 if (sig->ret->type == MONO_TYPE_PTR) {
4439                         MonoClass *pointer_class;
4440                         static MonoMethod *box_method;
4441                         void *box_args [2];
4442                         MonoObject *box_exc;
4443
4444                         /* 
4445                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
4446                          * convert it to a Pointer object.
4447                          */
4448                         pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4449                         if (!box_method)
4450                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4451
4452                         g_assert (res->vtable->klass == mono_defaults.int_class);
4453                         box_args [0] = ((MonoIntPtr*)res)->m_value;
4454                         box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4455                         mono_error_raise_exception (&error); /* FIXME don't raise here */
4456
4457                         res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4458                         g_assert (!box_exc);
4459                 }
4460
4461                 if (has_byref_nullables) {
4462                         /* 
4463                          * The runtime invoke wrapper already converted byref nullables back,
4464                          * and stored them in pa, we just need to copy them back to the
4465                          * managed array.
4466                          */
4467                         for (i = 0; i < mono_array_length (params); i++) {
4468                                 MonoType *t = sig->params [i];
4469
4470                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4471                                         mono_array_setref (params, i, pa [i]);
4472                         }
4473                 }
4474
4475                 return res;
4476         }
4477 }
4478
4479 /**
4480  * mono_object_new:
4481  * @klass: the class of the object that we want to create
4482  *
4483  * Returns: a newly created object whose definition is
4484  * looked up using @klass.   This will not invoke any constructors, 
4485  * so the consumer of this routine has to invoke any constructors on
4486  * its own to initialize the object.
4487  * 
4488  * It returns NULL on failure.
4489  */
4490 MonoObject *
4491 mono_object_new (MonoDomain *domain, MonoClass *klass)
4492 {
4493         MONO_REQ_GC_UNSAFE_MODE;
4494
4495         MonoVTable *vtable;
4496
4497         vtable = mono_class_vtable (domain, klass);
4498         if (!vtable)
4499                 return NULL;
4500
4501         MonoError error;
4502         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4503         mono_error_raise_exception (&error); /* FIXME don't raise here */
4504
4505         return o;
4506 }
4507
4508 /**
4509  * mono_object_new_pinned:
4510  *
4511  *   Same as mono_object_new, but the returned object will be pinned.
4512  * For SGEN, these objects will only be freed at appdomain unload.
4513  */
4514 MonoObject *
4515 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4516 {
4517         MONO_REQ_GC_UNSAFE_MODE;
4518
4519         MonoVTable *vtable;
4520
4521         mono_error_init (error);
4522
4523         vtable = mono_class_vtable (domain, klass);
4524         g_assert (vtable); /* FIXME don't swallow the error */
4525
4526         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4527
4528         if (G_UNLIKELY (!o))
4529                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4530         else if (G_UNLIKELY (vtable->klass->has_finalize))
4531                 mono_object_register_finalizer (o);
4532
4533         return o;
4534 }
4535
4536 /**
4537  * mono_object_new_specific:
4538  * @vtable: the vtable of the object that we want to create
4539  *
4540  * Returns: A newly created object with class and domain specified
4541  * by @vtable
4542  */
4543 MonoObject *
4544 mono_object_new_specific (MonoVTable *vtable)
4545 {
4546         MonoError error;
4547         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4548         mono_error_raise_exception (&error);
4549
4550         return o;
4551 }
4552
4553 MonoObject *
4554 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4555 {
4556         MONO_REQ_GC_UNSAFE_MODE;
4557
4558         MonoObject *o;
4559
4560         mono_error_init (error);
4561
4562         /* check for is_com_object for COM Interop */
4563         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4564         {
4565                 gpointer pa [1];
4566                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4567
4568                 if (im == NULL) {
4569                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4570
4571                         if (!klass->inited)
4572                                 mono_class_init (klass);
4573
4574                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4575                         if (!im) {
4576                                 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4577                                 return NULL;
4578                         }
4579                         vtable->domain->create_proxy_for_type_method = im;
4580                 }
4581         
4582                 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4583                 if (!mono_error_ok (error))
4584                         return NULL;
4585
4586                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
4587                 if (o != NULL) return o;
4588         }
4589
4590         return mono_object_new_alloc_specific_checked (vtable, error);
4591 }
4592
4593 MonoObject *
4594 ves_icall_object_new_specific (MonoVTable *vtable)
4595 {
4596         MonoError error;
4597         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4598         mono_error_raise_exception (&error);
4599
4600         return o;
4601 }
4602
4603 MonoObject *
4604 mono_object_new_alloc_specific (MonoVTable *vtable)
4605 {
4606         MonoError error;
4607         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4608         mono_error_raise_exception (&error);
4609
4610         return o;
4611 }
4612
4613 MonoObject *
4614 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4615 {
4616         MONO_REQ_GC_UNSAFE_MODE;
4617
4618         MonoObject *o;
4619
4620         mono_error_init (error);
4621
4622         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4623
4624         if (G_UNLIKELY (!o))
4625                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4626         else if (G_UNLIKELY (vtable->klass->has_finalize))
4627                 mono_object_register_finalizer (o);
4628
4629         return o;
4630 }
4631
4632 MonoObject*
4633 mono_object_new_fast (MonoVTable *vtable)
4634 {
4635         MonoError error;
4636         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4637         mono_error_raise_exception (&error);
4638
4639         return o;
4640 }
4641
4642 MonoObject*
4643 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4644 {
4645         MONO_REQ_GC_UNSAFE_MODE;
4646
4647         MonoObject *o;
4648
4649         mono_error_init (error);
4650
4651         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4652
4653         if (G_UNLIKELY (!o))
4654                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4655
4656         return o;
4657 }
4658
4659 MonoObject *
4660 ves_icall_object_new_fast (MonoVTable *vtable)
4661 {
4662         MonoError error;
4663         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4664         mono_error_raise_exception (&error);
4665
4666         return o;
4667 }
4668
4669 MonoObject*
4670 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4671 {
4672         MONO_REQ_GC_UNSAFE_MODE;
4673
4674         MonoObject *o;
4675
4676         mono_error_init (error);
4677
4678         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4679
4680         if (G_UNLIKELY (!o))
4681                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4682         else if (G_UNLIKELY (vtable->klass->has_finalize))
4683                 mono_object_register_finalizer (o);
4684
4685         return o;
4686 }
4687
4688 /**
4689  * mono_class_get_allocation_ftn:
4690  * @vtable: vtable
4691  * @for_box: the object will be used for boxing
4692  * @pass_size_in_words: 
4693  *
4694  * Return the allocation function appropriate for the given class.
4695  */
4696
4697 void*
4698 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4699 {
4700         MONO_REQ_GC_NEUTRAL_MODE;
4701
4702         *pass_size_in_words = FALSE;
4703
4704         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4705                 return ves_icall_object_new_specific;
4706
4707         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4708
4709                 return ves_icall_object_new_fast;
4710
4711                 /* 
4712                  * FIXME: This is actually slower than ves_icall_object_new_fast, because
4713                  * of the overhead of parameter passing.
4714                  */
4715                 /*
4716                 *pass_size_in_words = TRUE;
4717 #ifdef GC_REDIRECT_TO_LOCAL
4718                 return GC_local_gcj_fast_malloc;
4719 #else
4720                 return GC_gcj_fast_malloc;
4721 #endif
4722                 */
4723         }
4724
4725         return ves_icall_object_new_specific;
4726 }
4727
4728 /**
4729  * mono_object_new_from_token:
4730  * @image: Context where the type_token is hosted
4731  * @token: a token of the type that we want to create
4732  *
4733  * Returns: A newly created object whose definition is
4734  * looked up using @token in the @image image
4735  */
4736 MonoObject *
4737 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
4738 {
4739         MONO_REQ_GC_UNSAFE_MODE;
4740
4741         MonoError error;
4742         MonoClass *klass;
4743
4744         klass = mono_class_get_checked (image, token, &error);
4745         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4746
4747         return mono_object_new (domain, klass);
4748 }
4749
4750
4751 /**
4752  * mono_object_clone:
4753  * @obj: the object to clone
4754  *
4755  * Returns: A newly created object who is a shallow copy of @obj
4756  */
4757 MonoObject *
4758 mono_object_clone (MonoObject *obj)
4759 {
4760         MonoError error;
4761         MonoObject *o = mono_object_clone_checked (obj, &error);
4762         mono_error_raise_exception (&error);
4763
4764         return o;
4765 }
4766
4767 MonoObject *
4768 mono_object_clone_checked (MonoObject *obj, MonoError *error)
4769 {
4770         MONO_REQ_GC_UNSAFE_MODE;
4771
4772         MonoObject *o;
4773         int size;
4774
4775         mono_error_init (error);
4776
4777         size = obj->vtable->klass->instance_size;
4778
4779         if (obj->vtable->klass->rank)
4780                 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4781
4782         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4783
4784         if (G_UNLIKELY (!o)) {
4785                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
4786                 return NULL;
4787         }
4788
4789         /* If the object doesn't contain references this will do a simple memmove. */
4790         mono_gc_wbarrier_object_copy (o, obj);
4791
4792         if (obj->vtable->klass->has_finalize)
4793                 mono_object_register_finalizer (o);
4794         return o;
4795 }
4796
4797 /**
4798  * mono_array_full_copy:
4799  * @src: source array to copy
4800  * @dest: destination array
4801  *
4802  * Copies the content of one array to another with exactly the same type and size.
4803  */
4804 void
4805 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4806 {
4807         MONO_REQ_GC_UNSAFE_MODE;
4808
4809         uintptr_t size;
4810         MonoClass *klass = src->obj.vtable->klass;
4811
4812         g_assert (klass == dest->obj.vtable->klass);
4813
4814         size = mono_array_length (src);
4815         g_assert (size == mono_array_length (dest));
4816         size *= mono_array_element_size (klass);
4817 #ifdef HAVE_SGEN_GC
4818         if (klass->element_class->valuetype) {
4819                 if (klass->element_class->has_references)
4820                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4821                 else
4822                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4823         } else {
4824                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4825         }
4826 #else
4827         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4828 #endif
4829 }
4830
4831 /**
4832  * mono_array_clone_in_domain:
4833  * @domain: the domain in which the array will be cloned into
4834  * @array: the array to clone
4835  *
4836  * This routine returns a copy of the array that is hosted on the
4837  * specified MonoDomain.
4838  */
4839 MonoArray*
4840 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4841 {
4842         MONO_REQ_GC_UNSAFE_MODE;
4843
4844         MonoError error;
4845         MonoArray *o;
4846         uintptr_t size, i;
4847         uintptr_t *sizes;
4848         MonoClass *klass = array->obj.vtable->klass;
4849
4850         if (array->bounds == NULL) {
4851                 size = mono_array_length (array);
4852                 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
4853                 mono_error_raise_exception (&error); /* FIXME don't raise here */
4854
4855                 size *= mono_array_element_size (klass);
4856 #ifdef HAVE_SGEN_GC
4857                 if (klass->element_class->valuetype) {
4858                         if (klass->element_class->has_references)
4859                                 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4860                         else
4861                                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4862                 } else {
4863                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4864                 }
4865 #else
4866                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4867 #endif
4868                 return o;
4869         }
4870         
4871         sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4872         size = mono_array_element_size (klass);
4873         for (i = 0; i < klass->rank; ++i) {
4874                 sizes [i] = array->bounds [i].length;
4875                 size *= array->bounds [i].length;
4876                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4877         }
4878         o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
4879         mono_error_raise_exception (&error); /* FIXME don't raise here */
4880 #ifdef HAVE_SGEN_GC
4881         if (klass->element_class->valuetype) {
4882                 if (klass->element_class->has_references)
4883                         mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4884                 else
4885                         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4886         } else {
4887                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4888         }
4889 #else
4890         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4891 #endif
4892
4893         return o;
4894 }
4895
4896 /**
4897  * mono_array_clone:
4898  * @array: the array to clone
4899  *
4900  * Returns: A newly created array who is a shallow copy of @array
4901  */
4902 MonoArray*
4903 mono_array_clone (MonoArray *array)
4904 {
4905         MONO_REQ_GC_UNSAFE_MODE;
4906
4907         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4908 }
4909
4910 /* helper macros to check for overflow when calculating the size of arrays */
4911 #ifdef MONO_BIG_ARRAYS
4912 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4913 #define MYGUINT_MAX MYGUINT64_MAX
4914 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4915             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4916 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4917             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
4918                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4919 #else
4920 #define MYGUINT32_MAX 4294967295U
4921 #define MYGUINT_MAX MYGUINT32_MAX
4922 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4923             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4924 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4925             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
4926                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4927 #endif
4928
4929 gboolean
4930 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4931 {
4932         MONO_REQ_GC_NEUTRAL_MODE;
4933
4934         uintptr_t byte_len;
4935
4936         byte_len = mono_array_element_size (klass);
4937         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4938                 return FALSE;
4939         byte_len *= len;
4940         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4941                 return FALSE;
4942         byte_len += MONO_SIZEOF_MONO_ARRAY;
4943
4944         *res = byte_len;
4945
4946         return TRUE;
4947 }
4948
4949 /**
4950  * mono_array_new_full:
4951  * @domain: domain where the object is created
4952  * @array_class: array class
4953  * @lengths: lengths for each dimension in the array
4954  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4955  *
4956  * This routine creates a new array objects with the given dimensions,
4957  * lower bounds and type.
4958  */
4959 MonoArray*
4960 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4961 {
4962         MonoError error;
4963         MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
4964         mono_error_raise_exception (&error);
4965
4966         return array;
4967 }
4968
4969 MonoArray*
4970 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
4971 {
4972         MONO_REQ_GC_UNSAFE_MODE;
4973
4974         uintptr_t byte_len = 0, len, bounds_size;
4975         MonoObject *o;
4976         MonoArray *array;
4977         MonoArrayBounds *bounds;
4978         MonoVTable *vtable;
4979         int i;
4980
4981         mono_error_init (error);
4982
4983         if (!array_class->inited)
4984                 mono_class_init (array_class);
4985
4986         len = 1;
4987
4988         /* A single dimensional array with a 0 lower bound is the same as an szarray */
4989         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4990                 len = lengths [0];
4991                 if (len > MONO_ARRAY_MAX_INDEX) {
4992                         mono_error_set_generic_error (error, "System", "OverflowException", "");
4993                         return NULL;
4994                 }
4995                 bounds_size = 0;
4996         } else {
4997                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4998
4999                 for (i = 0; i < array_class->rank; ++i) {
5000                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5001                                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5002                                 return NULL;
5003                         }
5004                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5005                                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5006                                 return NULL;
5007                         }
5008                         len *= lengths [i];
5009                 }
5010         }
5011
5012         if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5013                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5014                 return NULL;
5015         }
5016
5017         if (bounds_size) {
5018                 /* align */
5019                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5020                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5021                         return NULL;
5022                 }
5023                 byte_len = (byte_len + 3) & ~3;
5024                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5025                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5026                         return NULL;
5027                 }
5028                 byte_len += bounds_size;
5029         }
5030         /* 
5031          * Following three lines almost taken from mono_object_new ():
5032          * they need to be kept in sync.
5033          */
5034         vtable = mono_class_vtable_full (domain, array_class, TRUE);
5035         if (bounds_size)
5036                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5037         else
5038                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5039
5040         if (G_UNLIKELY (!o)) {
5041                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5042                 return NULL;
5043         }
5044
5045         array = (MonoArray*)o;
5046
5047         bounds = array->bounds;
5048
5049         if (bounds_size) {
5050                 for (i = 0; i < array_class->rank; ++i) {
5051                         bounds [i].length = lengths [i];
5052                         if (lower_bounds)
5053                                 bounds [i].lower_bound = lower_bounds [i];
5054                 }
5055         }
5056
5057         return array;
5058 }
5059
5060 /**
5061  * mono_array_new:
5062  * @domain: domain where the object is created
5063  * @eclass: element class
5064  * @n: number of array elements
5065  *
5066  * This routine creates a new szarray with @n elements of type @eclass.
5067  */
5068 MonoArray *
5069 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5070 {
5071         MONO_REQ_GC_UNSAFE_MODE;
5072
5073         MonoError error;
5074         MonoClass *ac;
5075         MonoArray *arr;
5076
5077         ac = mono_array_class_get (eclass, 1);
5078         g_assert (ac);
5079
5080         arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5081         mono_error_raise_exception (&error); /* FIXME don't raise here */
5082
5083         return arr;
5084 }
5085
5086 /**
5087  * mono_array_new_specific:
5088  * @vtable: a vtable in the appropriate domain for an initialized class
5089  * @n: number of array elements
5090  *
5091  * This routine is a fast alternative to mono_array_new() for code which
5092  * can be sure about the domain it operates in.
5093  */
5094 MonoArray *
5095 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5096 {
5097         MonoError error;
5098         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5099         mono_error_raise_exception (&error); /* FIXME don't raise here */
5100
5101         return arr;
5102 }
5103
5104 MonoArray*
5105 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5106 {
5107         MONO_REQ_GC_UNSAFE_MODE;
5108
5109         MonoObject *o;
5110         uintptr_t byte_len;
5111
5112         mono_error_init (error);
5113
5114         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5115                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5116                 return NULL;
5117         }
5118
5119         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5120                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5121                 return NULL;
5122         }
5123         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5124
5125         if (G_UNLIKELY (!o)) {
5126                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5127                 return NULL;
5128         }
5129
5130         return (MonoArray*)o;
5131 }
5132
5133 MonoArray*
5134 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5135 {
5136         MonoError error;
5137         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5138         mono_error_raise_exception (&error);
5139
5140         return arr;
5141 }
5142
5143 /**
5144  * mono_string_new_utf16:
5145  * @text: a pointer to an utf16 string
5146  * @len: the length of the string
5147  *
5148  * Returns: A newly created string object which contains @text.
5149  */
5150 MonoString *
5151 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5152 {
5153         MONO_REQ_GC_UNSAFE_MODE;
5154
5155         MonoError error;
5156         MonoString *s;
5157         
5158         s = mono_string_new_size_checked (domain, len, &error);
5159         mono_error_raise_exception (&error); /* FIXME don't raise here */
5160
5161         memcpy (mono_string_chars (s), text, len * 2);
5162
5163         return s;
5164 }
5165
5166 /**
5167  * mono_string_new_utf32:
5168  * @text: a pointer to an utf32 string
5169  * @len: the length of the string
5170  *
5171  * Returns: A newly created string object which contains @text.
5172  */
5173 MonoString *
5174 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5175 {
5176         MONO_REQ_GC_UNSAFE_MODE;
5177
5178         MonoError error;
5179         MonoString *s;
5180         mono_unichar2 *utf16_output = NULL;
5181         gint32 utf16_len = 0;
5182         GError *gerror = NULL;
5183         glong items_written;
5184         
5185         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5186         
5187         if (gerror)
5188                 g_error_free (gerror);
5189
5190         while (utf16_output [utf16_len]) utf16_len++;
5191         
5192         s = mono_string_new_size_checked (domain, utf16_len, &error);
5193         mono_error_raise_exception (&error); /* FIXME don't raise here */
5194
5195         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5196
5197         g_free (utf16_output);
5198         
5199         return s;
5200 }
5201
5202 /**
5203  * mono_string_new_size:
5204  * @text: a pointer to an utf16 string
5205  * @len: the length of the string
5206  *
5207  * Returns: A newly created string object of @len
5208  */
5209 MonoString *
5210 mono_string_new_size (MonoDomain *domain, gint32 len)
5211 {
5212         MonoError error;
5213         MonoString *str = mono_string_new_size_checked (domain, len, &error);
5214         mono_error_raise_exception (&error);
5215
5216         return str;
5217 }
5218
5219 MonoString *
5220 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5221 {
5222         MONO_REQ_GC_UNSAFE_MODE;
5223
5224         MonoString *s;
5225         MonoVTable *vtable;
5226         size_t size;
5227
5228         mono_error_init (error);
5229
5230         /* check for overflow */
5231         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5232                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5233                 return NULL;
5234         }
5235
5236         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5237         g_assert (size > 0);
5238
5239         vtable = mono_class_vtable (domain, mono_defaults.string_class);
5240         g_assert (vtable);
5241
5242         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5243
5244         if (G_UNLIKELY (!s)) {
5245                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5246                 return NULL;
5247         }
5248
5249         return s;
5250 }
5251
5252 /**
5253  * mono_string_new_len:
5254  * @text: a pointer to an utf8 string
5255  * @length: number of bytes in @text to consider
5256  *
5257  * Returns: A newly created string object which contains @text.
5258  */
5259 MonoString*
5260 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5261 {
5262         MONO_REQ_GC_UNSAFE_MODE;
5263
5264         GError *error = NULL;
5265         MonoString *o = NULL;
5266         guint16 *ut;
5267         glong items_written;
5268
5269         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5270
5271         if (!error)
5272                 o = mono_string_new_utf16 (domain, ut, items_written);
5273         else 
5274                 g_error_free (error);
5275
5276         g_free (ut);
5277
5278         return o;
5279 }
5280
5281 /**
5282  * mono_string_new:
5283  * @text: a pointer to an utf8 string
5284  *
5285  * Returns: A newly created string object which contains @text.
5286  */
5287 MonoString*
5288 mono_string_new (MonoDomain *domain, const char *text)
5289 {
5290         MONO_REQ_GC_UNSAFE_MODE;
5291
5292     GError *error = NULL;
5293     MonoString *o = NULL;
5294     guint16 *ut;
5295     glong items_written;
5296     int l;
5297
5298     l = strlen (text);
5299    
5300     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5301
5302     if (!error)
5303         o = mono_string_new_utf16 (domain, ut, items_written);
5304     else
5305         g_error_free (error);
5306
5307     g_free (ut);
5308 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5309 #if 0
5310         MonoError error;
5311         gunichar2 *str;
5312         const gchar *end;
5313         int len;
5314         MonoString *o = NULL;
5315
5316         if (!g_utf8_validate (text, -1, &end))
5317                 return NULL;
5318
5319         len = g_utf8_strlen (text, -1);
5320         o = mono_string_new_size_checked (domain, len, &error);
5321         mono_error_raise_exception (&error); /* FIXME don't raise here */
5322         str = mono_string_chars (o);
5323
5324         while (text < end) {
5325                 *str++ = g_utf8_get_char (text);
5326                 text = g_utf8_next_char (text);
5327         }
5328 #endif
5329         return o;
5330 }
5331
5332 /**
5333  * mono_string_new_wrapper:
5334  * @text: pointer to utf8 characters.
5335  *
5336  * Helper function to create a string object from @text in the current domain.
5337  */
5338 MonoString*
5339 mono_string_new_wrapper (const char *text)
5340 {
5341         MONO_REQ_GC_UNSAFE_MODE;
5342
5343         MonoDomain *domain = mono_domain_get ();
5344
5345         if (text)
5346                 return mono_string_new (domain, text);
5347
5348         return NULL;
5349 }
5350
5351 /**
5352  * mono_value_box:
5353  * @class: the class of the value
5354  * @value: a pointer to the unboxed data
5355  *
5356  * Returns: A newly created object which contains @value.
5357  */
5358 MonoObject *
5359 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5360 {
5361         MONO_REQ_GC_UNSAFE_MODE;
5362
5363         MonoError error;
5364         MonoObject *res;
5365         int size;
5366         MonoVTable *vtable;
5367
5368         g_assert (klass->valuetype);
5369         if (mono_class_is_nullable (klass))
5370                 return mono_nullable_box ((guint8 *)value, klass);
5371
5372         vtable = mono_class_vtable (domain, klass);
5373         if (!vtable)
5374                 return NULL;
5375         size = mono_class_instance_size (klass);
5376         res = mono_object_new_alloc_specific_checked (vtable, &error);
5377         mono_error_raise_exception (&error); /* FIXME don't raise here */
5378
5379         size = size - sizeof (MonoObject);
5380
5381 #ifdef HAVE_SGEN_GC
5382         g_assert (size == mono_class_value_size (klass, NULL));
5383         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5384 #else
5385 #if NO_UNALIGNED_ACCESS
5386         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5387 #else
5388         switch (size) {
5389         case 1:
5390                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5391                 break;
5392         case 2:
5393                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5394                 break;
5395         case 4:
5396                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5397                 break;
5398         case 8:
5399                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5400                 break;
5401         default:
5402                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5403         }
5404 #endif
5405 #endif
5406         if (klass->has_finalize)
5407                 mono_object_register_finalizer (res);
5408         return res;
5409 }
5410
5411 /*
5412  * mono_value_copy:
5413  * @dest: destination pointer
5414  * @src: source pointer
5415  * @klass: a valuetype class
5416  *
5417  * Copy a valuetype from @src to @dest. This function must be used
5418  * when @klass contains references fields.
5419  */
5420 void
5421 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5422 {
5423         MONO_REQ_GC_UNSAFE_MODE;
5424
5425         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5426 }
5427
5428 /*
5429  * mono_value_copy_array:
5430  * @dest: destination array
5431  * @dest_idx: index in the @dest array
5432  * @src: source pointer
5433  * @count: number of items
5434  *
5435  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
5436  * This function must be used when @klass contains references fields.
5437  * Overlap is handled.
5438  */
5439 void
5440 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5441 {
5442         MONO_REQ_GC_UNSAFE_MODE;
5443
5444         int size = mono_array_element_size (dest->obj.vtable->klass);
5445         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5446         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5447         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5448 }
5449
5450 /**
5451  * mono_object_get_domain:
5452  * @obj: object to query
5453  * 
5454  * Returns: the MonoDomain where the object is hosted
5455  */
5456 MonoDomain*
5457 mono_object_get_domain (MonoObject *obj)
5458 {
5459         MONO_REQ_GC_UNSAFE_MODE;
5460
5461         return mono_object_domain (obj);
5462 }
5463
5464 /**
5465  * mono_object_get_class:
5466  * @obj: object to query
5467  * 
5468  * Returns: the MonOClass of the object.
5469  */
5470 MonoClass*
5471 mono_object_get_class (MonoObject *obj)
5472 {
5473         MONO_REQ_GC_UNSAFE_MODE;
5474
5475         return mono_object_class (obj);
5476 }
5477 /**
5478  * mono_object_get_size:
5479  * @o: object to query
5480  * 
5481  * Returns: the size, in bytes, of @o
5482  */
5483 guint
5484 mono_object_get_size (MonoObject* o)
5485 {
5486         MONO_REQ_GC_UNSAFE_MODE;
5487
5488         MonoClass* klass = mono_object_class (o);
5489         if (klass == mono_defaults.string_class) {
5490                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5491         } else if (o->vtable->rank) {
5492                 MonoArray *array = (MonoArray*)o;
5493                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5494                 if (array->bounds) {
5495                         size += 3;
5496                         size &= ~3;
5497                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
5498                 }
5499                 return size;
5500         } else {
5501                 return mono_class_instance_size (klass);
5502         }
5503 }
5504
5505 /**
5506  * mono_object_unbox:
5507  * @obj: object to unbox
5508  * 
5509  * Returns: a pointer to the start of the valuetype boxed in this
5510  * object.
5511  *
5512  * This method will assert if the object passed is not a valuetype.
5513  */
5514 gpointer
5515 mono_object_unbox (MonoObject *obj)
5516 {
5517         MONO_REQ_GC_UNSAFE_MODE;
5518
5519         /* add assert for valuetypes? */
5520         g_assert (obj->vtable->klass->valuetype);
5521         return ((char*)obj) + sizeof (MonoObject);
5522 }
5523
5524 /**
5525  * mono_object_isinst:
5526  * @obj: an object
5527  * @klass: a pointer to a class 
5528  *
5529  * Returns: @obj if @obj is derived from @klass
5530  */
5531 MonoObject *
5532 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5533 {
5534         MONO_REQ_GC_UNSAFE_MODE;
5535
5536         if (!klass->inited)
5537                 mono_class_init (klass);
5538
5539         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5540                 return mono_object_isinst_mbyref (obj, klass);
5541
5542         if (!obj)
5543                 return NULL;
5544
5545         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5546 }
5547
5548 MonoObject *
5549 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5550 {
5551         MONO_REQ_GC_UNSAFE_MODE;
5552
5553         MonoError error;
5554         MonoVTable *vt;
5555
5556         if (!obj)
5557                 return NULL;
5558
5559         vt = obj->vtable;
5560         
5561         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5562                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5563                         return obj;
5564                 }
5565
5566                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5567                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5568                         return obj;
5569         } else {
5570                 MonoClass *oklass = vt->klass;
5571                 if (mono_class_is_transparent_proxy (oklass))
5572                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5573
5574                 mono_class_setup_supertypes (klass);    
5575                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5576                         return obj;
5577         }
5578 #ifndef DISABLE_REMOTING
5579         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5580         {
5581                 MonoDomain *domain = mono_domain_get ();
5582                 MonoObject *res;
5583                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5584                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5585                 MonoMethod *im = NULL;
5586                 gpointer pa [2];
5587
5588                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5589                 if (!im)
5590                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5591                 im = mono_object_get_virtual_method (rp, im);
5592                 g_assert (im);
5593         
5594                 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5595                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5596                 pa [1] = obj;
5597
5598                 res = mono_runtime_invoke (im, rp, pa, NULL);
5599         
5600                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5601                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5602                         mono_upgrade_remote_class (domain, obj, klass);
5603                         return obj;
5604                 }
5605         }
5606 #endif /* DISABLE_REMOTING */
5607         return NULL;
5608 }
5609
5610 /**
5611  * mono_object_castclass_mbyref:
5612  * @obj: an object
5613  * @klass: a pointer to a class 
5614  *
5615  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5616  */
5617 MonoObject *
5618 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5619 {
5620         MONO_REQ_GC_UNSAFE_MODE;
5621
5622         if (!obj) return NULL;
5623         if (mono_object_isinst_mbyref (obj, klass)) return obj;
5624                 
5625         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5626                                                         "System",
5627                                                         "InvalidCastException"));
5628         return NULL;
5629 }
5630
5631 typedef struct {
5632         MonoDomain *orig_domain;
5633         MonoString *ins;
5634         MonoString *res;
5635 } LDStrInfo;
5636
5637 static void
5638 str_lookup (MonoDomain *domain, gpointer user_data)
5639 {
5640         MONO_REQ_GC_UNSAFE_MODE;
5641
5642         LDStrInfo *info = (LDStrInfo *)user_data;
5643         if (info->res || domain == info->orig_domain)
5644                 return;
5645         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5646 }
5647
5648 static MonoString*
5649 mono_string_get_pinned (MonoString *str, MonoError *error)
5650 {
5651         MONO_REQ_GC_UNSAFE_MODE;
5652
5653         mono_error_init (error);
5654
5655         /* We only need to make a pinned version of a string if this is a moving GC */
5656         if (!mono_gc_is_moving ())
5657                 return str;
5658         int size;
5659         MonoString *news;
5660         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5661         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5662         if (news) {
5663                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5664                 news->length = mono_string_length (str);
5665         } else {
5666                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5667         }
5668         return news;
5669 }
5670
5671 static MonoString*
5672 mono_string_is_interned_lookup (MonoString *str, int insert)
5673 {
5674         MONO_REQ_GC_UNSAFE_MODE;
5675
5676         MonoError error;
5677         MonoGHashTable *ldstr_table;
5678         MonoString *s, *res;
5679         MonoDomain *domain;
5680         
5681         domain = ((MonoObject *)str)->vtable->domain;
5682         ldstr_table = domain->ldstr_table;
5683         ldstr_lock ();
5684         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5685         if (res) {
5686                 ldstr_unlock ();
5687                 return res;
5688         }
5689         if (insert) {
5690                 /* Allocate outside the lock */
5691                 ldstr_unlock ();
5692                 s = mono_string_get_pinned (str, &error);
5693                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5694                 if (s) {
5695                         ldstr_lock ();
5696                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5697                         if (res) {
5698                                 ldstr_unlock ();
5699                                 return res;
5700                         }
5701                         mono_g_hash_table_insert (ldstr_table, s, s);
5702                         ldstr_unlock ();
5703                 }
5704                 return s;
5705         } else {
5706                 LDStrInfo ldstr_info;
5707                 ldstr_info.orig_domain = domain;
5708                 ldstr_info.ins = str;
5709                 ldstr_info.res = NULL;
5710
5711                 mono_domain_foreach (str_lookup, &ldstr_info);
5712                 if (ldstr_info.res) {
5713                         /* 
5714                          * the string was already interned in some other domain:
5715                          * intern it in the current one as well.
5716                          */
5717                         mono_g_hash_table_insert (ldstr_table, str, str);
5718                         ldstr_unlock ();
5719                         return str;
5720                 }
5721         }
5722         ldstr_unlock ();
5723         return NULL;
5724 }
5725
5726 /**
5727  * mono_string_is_interned:
5728  * @o: String to probe
5729  *
5730  * Returns whether the string has been interned.
5731  */
5732 MonoString*
5733 mono_string_is_interned (MonoString *o)
5734 {
5735         MONO_REQ_GC_UNSAFE_MODE;
5736
5737         return mono_string_is_interned_lookup (o, FALSE);
5738 }
5739
5740 /**
5741  * mono_string_intern:
5742  * @o: String to intern
5743  *
5744  * Interns the string passed.  
5745  * Returns: The interned string.
5746  */
5747 MonoString*
5748 mono_string_intern (MonoString *str)
5749 {
5750         MONO_REQ_GC_UNSAFE_MODE;
5751
5752         return mono_string_is_interned_lookup (str, TRUE);
5753 }
5754
5755 /**
5756  * mono_ldstr:
5757  * @domain: the domain where the string will be used.
5758  * @image: a metadata context
5759  * @idx: index into the user string table.
5760  * 
5761  * Implementation for the ldstr opcode.
5762  * Returns: a loaded string from the @image/@idx combination.
5763  */
5764 MonoString*
5765 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5766 {
5767         MONO_REQ_GC_UNSAFE_MODE;
5768
5769         if (image->dynamic) {
5770                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5771                 return str;
5772         } else {
5773                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5774                         return NULL; /*FIXME we should probably be raising an exception here*/
5775                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5776         }
5777 }
5778
5779 /**
5780  * mono_ldstr_metadata_sig
5781  * @domain: the domain for the string
5782  * @sig: the signature of a metadata string
5783  *
5784  * Returns: a MonoString for a string stored in the metadata
5785  */
5786 static MonoString*
5787 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5788 {
5789         MONO_REQ_GC_UNSAFE_MODE;
5790
5791         MonoError error;
5792         const char *str = sig;
5793         MonoString *o, *interned;
5794         size_t len2;
5795
5796         len2 = mono_metadata_decode_blob_size (str, &str);
5797         len2 >>= 1;
5798
5799         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5800 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5801         {
5802                 int i;
5803                 guint16 *p2 = (guint16*)mono_string_chars (o);
5804                 for (i = 0; i < len2; ++i) {
5805                         *p2 = GUINT16_FROM_LE (*p2);
5806                         ++p2;
5807                 }
5808         }
5809 #endif
5810         ldstr_lock ();
5811         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5812         ldstr_unlock ();
5813         if (interned)
5814                 return interned; /* o will get garbage collected */
5815
5816         o = mono_string_get_pinned (o, &error);
5817         mono_error_raise_exception (&error); /* FIXME don't raise here */
5818         if (o) {
5819                 ldstr_lock ();
5820                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5821                 if (!interned) {
5822                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
5823                         interned = o;
5824                 }
5825                 ldstr_unlock ();
5826         }
5827
5828         return interned;
5829 }
5830
5831 /**
5832  * mono_string_to_utf8:
5833  * @s: a System.String
5834  *
5835  * Returns the UTF8 representation for @s.
5836  * The resulting buffer needs to be freed with mono_free().
5837  *
5838  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5839  */
5840 char *
5841 mono_string_to_utf8 (MonoString *s)
5842 {
5843         MONO_REQ_GC_UNSAFE_MODE;
5844
5845         MonoError error;
5846         char *result = mono_string_to_utf8_checked (s, &error);
5847         
5848         if (!mono_error_ok (&error))
5849                 mono_error_raise_exception (&error);
5850         return result;
5851 }
5852
5853 /**
5854  * mono_string_to_utf8_checked:
5855  * @s: a System.String
5856  * @error: a MonoError.
5857  * 
5858  * Converts a MonoString to its UTF8 representation. May fail; check 
5859  * @error to determine whether the conversion was successful.
5860  * The resulting buffer should be freed with mono_free().
5861  */
5862 char *
5863 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5864 {
5865         MONO_REQ_GC_UNSAFE_MODE;
5866
5867         long written = 0;
5868         char *as;
5869         GError *gerror = NULL;
5870
5871         mono_error_init (error);
5872
5873         if (s == NULL)
5874                 return NULL;
5875
5876         if (!s->length)
5877                 return g_strdup ("");
5878
5879         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5880         if (gerror) {
5881                 mono_error_set_argument (error, "string", "%s", gerror->message);
5882                 g_error_free (gerror);
5883                 return NULL;
5884         }
5885         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5886         if (s->length > written) {
5887                 /* allocate the total length and copy the part of the string that has been converted */
5888                 char *as2 = (char *)g_malloc0 (s->length);
5889                 memcpy (as2, as, written);
5890                 g_free (as);
5891                 as = as2;
5892         }
5893
5894         return as;
5895 }
5896
5897 /**
5898  * mono_string_to_utf8_ignore:
5899  * @s: a MonoString
5900  *
5901  * Converts a MonoString to its UTF8 representation. Will ignore
5902  * invalid surrogate pairs.
5903  * The resulting buffer should be freed with mono_free().
5904  * 
5905  */
5906 char *
5907 mono_string_to_utf8_ignore (MonoString *s)
5908 {
5909         MONO_REQ_GC_UNSAFE_MODE;
5910
5911         long written = 0;
5912         char *as;
5913
5914         if (s == NULL)
5915                 return NULL;
5916
5917         if (!s->length)
5918                 return g_strdup ("");
5919
5920         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5921
5922         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5923         if (s->length > written) {
5924                 /* allocate the total length and copy the part of the string that has been converted */
5925                 char *as2 = (char *)g_malloc0 (s->length);
5926                 memcpy (as2, as, written);
5927                 g_free (as);
5928                 as = as2;
5929         }
5930
5931         return as;
5932 }
5933
5934 /**
5935  * mono_string_to_utf8_image_ignore:
5936  * @s: a System.String
5937  *
5938  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5939  */
5940 char *
5941 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5942 {
5943         MONO_REQ_GC_UNSAFE_MODE;
5944
5945         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5946 }
5947
5948 /**
5949  * mono_string_to_utf8_mp_ignore:
5950  * @s: a System.String
5951  *
5952  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5953  */
5954 char *
5955 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5956 {
5957         MONO_REQ_GC_UNSAFE_MODE;
5958
5959         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5960 }
5961
5962
5963 /**
5964  * mono_string_to_utf16:
5965  * @s: a MonoString
5966  *
5967  * Return an null-terminated array of the utf-16 chars
5968  * contained in @s. The result must be freed with g_free().
5969  * This is a temporary helper until our string implementation
5970  * is reworked to always include the null terminating char.
5971  */
5972 mono_unichar2*
5973 mono_string_to_utf16 (MonoString *s)
5974 {
5975         MONO_REQ_GC_UNSAFE_MODE;
5976
5977         char *as;
5978
5979         if (s == NULL)
5980                 return NULL;
5981
5982         as = (char *)g_malloc ((s->length * 2) + 2);
5983         as [(s->length * 2)] = '\0';
5984         as [(s->length * 2) + 1] = '\0';
5985
5986         if (!s->length) {
5987                 return (gunichar2 *)(as);
5988         }
5989         
5990         memcpy (as, mono_string_chars(s), s->length * 2);
5991         return (gunichar2 *)(as);
5992 }
5993
5994 /**
5995  * mono_string_to_utf32:
5996  * @s: a MonoString
5997  *
5998  * Return an null-terminated array of the UTF-32 (UCS-4) chars
5999  * contained in @s. The result must be freed with g_free().
6000  */
6001 mono_unichar4*
6002 mono_string_to_utf32 (MonoString *s)
6003 {
6004         MONO_REQ_GC_UNSAFE_MODE;
6005
6006         mono_unichar4 *utf32_output = NULL; 
6007         GError *error = NULL;
6008         glong items_written;
6009         
6010         if (s == NULL)
6011                 return NULL;
6012                 
6013         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6014         
6015         if (error)
6016                 g_error_free (error);
6017
6018         return utf32_output;
6019 }
6020
6021 /**
6022  * mono_string_from_utf16:
6023  * @data: the UTF16 string (LPWSTR) to convert
6024  *
6025  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6026  *
6027  * Returns: a MonoString.
6028  */
6029 MonoString *
6030 mono_string_from_utf16 (gunichar2 *data)
6031 {
6032         MONO_REQ_GC_UNSAFE_MODE;
6033
6034         MonoDomain *domain = mono_domain_get ();
6035         int len = 0;
6036
6037         if (!data)
6038                 return NULL;
6039
6040         while (data [len]) len++;
6041
6042         return mono_string_new_utf16 (domain, data, len);
6043 }
6044
6045 /**
6046  * mono_string_from_utf32:
6047  * @data: the UTF32 string (LPWSTR) to convert
6048  *
6049  * Converts a UTF32 (UCS-4)to a MonoString.
6050  *
6051  * Returns: a MonoString.
6052  */
6053 MonoString *
6054 mono_string_from_utf32 (mono_unichar4 *data)
6055 {
6056         MONO_REQ_GC_UNSAFE_MODE;
6057
6058         MonoString* result = NULL;
6059         mono_unichar2 *utf16_output = NULL;
6060         GError *error = NULL;
6061         glong items_written;
6062         int len = 0;
6063
6064         if (!data)
6065                 return NULL;
6066
6067         while (data [len]) len++;
6068
6069         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6070
6071         if (error)
6072                 g_error_free (error);
6073
6074         result = mono_string_from_utf16 (utf16_output);
6075         g_free (utf16_output);
6076         return result;
6077 }
6078
6079 static char *
6080 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6081 {
6082         MONO_REQ_GC_UNSAFE_MODE;
6083
6084         char *r;
6085         char *mp_s;
6086         int len;
6087
6088         if (ignore_error) {
6089                 r = mono_string_to_utf8_ignore (s);
6090         } else {
6091                 r = mono_string_to_utf8_checked (s, error);
6092                 if (!mono_error_ok (error))
6093                         return NULL;
6094         }
6095
6096         if (!mp && !image)
6097                 return r;
6098
6099         len = strlen (r) + 1;
6100         if (mp)
6101                 mp_s = (char *)mono_mempool_alloc (mp, len);
6102         else
6103                 mp_s = (char *)mono_image_alloc (image, len);
6104
6105         memcpy (mp_s, r, len);
6106
6107         g_free (r);
6108
6109         return mp_s;
6110 }
6111
6112 /**
6113  * mono_string_to_utf8_image:
6114  * @s: a System.String
6115  *
6116  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6117  */
6118 char *
6119 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6120 {
6121         MONO_REQ_GC_UNSAFE_MODE;
6122
6123         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6124 }
6125
6126 /**
6127  * mono_string_to_utf8_mp:
6128  * @s: a System.String
6129  *
6130  * Same as mono_string_to_utf8, but allocate the string from a mempool.
6131  */
6132 char *
6133 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6134 {
6135         MONO_REQ_GC_UNSAFE_MODE;
6136
6137         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6138 }
6139
6140
6141 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6142
6143 void
6144 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6145 {
6146         eh_callbacks = *cbs;
6147 }
6148
6149 MonoRuntimeExceptionHandlingCallbacks *
6150 mono_get_eh_callbacks (void)
6151 {
6152         return &eh_callbacks;
6153 }
6154
6155 /**
6156  * mono_raise_exception:
6157  * @ex: exception object
6158  *
6159  * Signal the runtime that the exception @ex has been raised in unmanaged code.
6160  */
6161 void
6162 mono_raise_exception (MonoException *ex) 
6163 {
6164         MONO_REQ_GC_UNSAFE_MODE;
6165
6166         /*
6167          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6168          * that will cause gcc to omit the function epilog, causing problems when
6169          * the JIT tries to walk the stack, since the return address on the stack
6170          * will point into the next function in the executable, not this one.
6171          */     
6172         eh_callbacks.mono_raise_exception (ex);
6173 }
6174
6175 void
6176 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
6177 {
6178         MONO_REQ_GC_UNSAFE_MODE;
6179
6180         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6181 }
6182
6183 /**
6184  * mono_wait_handle_new:
6185  * @domain: Domain where the object will be created
6186  * @handle: Handle for the wait handle
6187  *
6188  * Returns: A new MonoWaitHandle created in the given domain for the given handle
6189  */
6190 MonoWaitHandle *
6191 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6192 {
6193         MONO_REQ_GC_UNSAFE_MODE;
6194
6195         MonoWaitHandle *res;
6196         gpointer params [1];
6197         static MonoMethod *handle_set;
6198
6199         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
6200
6201         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
6202         if (!handle_set)
6203                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6204
6205         params [0] = &handle;
6206         mono_runtime_invoke (handle_set, res, params, NULL);
6207
6208         return res;
6209 }
6210
6211 HANDLE
6212 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6213 {
6214         MONO_REQ_GC_UNSAFE_MODE;
6215
6216         static MonoClassField *f_os_handle;
6217         static MonoClassField *f_safe_handle;
6218
6219         if (!f_os_handle && !f_safe_handle) {
6220                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6221                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6222         }
6223
6224         if (f_os_handle) {
6225                 HANDLE retval;
6226                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6227                 return retval;
6228         } else {
6229                 MonoSafeHandle *sh;
6230                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6231                 return sh->handle;
6232         }
6233 }
6234
6235
6236 static MonoObject*
6237 mono_runtime_capture_context (MonoDomain *domain)
6238 {
6239         MONO_REQ_GC_UNSAFE_MODE;
6240
6241         RuntimeInvokeFunction runtime_invoke;
6242
6243         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6244                 MonoMethod *method = mono_get_context_capture_method ();
6245                 MonoMethod *wrapper;
6246                 if (!method)
6247                         return NULL;
6248                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6249                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6250                 domain->capture_context_method = mono_compile_method (method);
6251         }
6252
6253         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6254
6255         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6256 }
6257 /**
6258  * mono_async_result_new:
6259  * @domain:domain where the object will be created.
6260  * @handle: wait handle.
6261  * @state: state to pass to AsyncResult
6262  * @data: C closure data.
6263  *
6264  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6265  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6266  *
6267  */
6268 MonoAsyncResult *
6269 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6270 {
6271         MONO_REQ_GC_UNSAFE_MODE;
6272
6273         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6274         MonoObject *context = mono_runtime_capture_context (domain);
6275         /* we must capture the execution context from the original thread */
6276         if (context) {
6277                 MONO_OBJECT_SETREF (res, execution_context, context);
6278                 /* note: result may be null if the flow is suppressed */
6279         }
6280
6281         res->data = (void **)data;
6282         MONO_OBJECT_SETREF (res, object_data, object_data);
6283         MONO_OBJECT_SETREF (res, async_state, state);
6284         if (handle != NULL)
6285                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6286
6287         res->sync_completed = FALSE;
6288         res->completed = FALSE;
6289
6290         return res;
6291 }
6292
6293 MonoObject *
6294 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6295 {
6296         MONO_REQ_GC_UNSAFE_MODE;
6297
6298         MonoAsyncCall *ac;
6299         MonoObject *res;
6300
6301         g_assert (ares);
6302         g_assert (ares->async_delegate);
6303
6304         ac = (MonoAsyncCall*) ares->object_data;
6305         if (!ac) {
6306                 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6307         } else {
6308                 gpointer wait_event = NULL;
6309
6310                 ac->msg->exc = NULL;
6311                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6312                 MONO_OBJECT_SETREF (ac, res, res);
6313
6314                 mono_monitor_enter ((MonoObject*) ares);
6315                 ares->completed = 1;
6316                 if (ares->handle)
6317                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6318                 mono_monitor_exit ((MonoObject*) ares);
6319
6320                 if (wait_event != NULL)
6321                         SetEvent (wait_event);
6322
6323                 if (ac->cb_method) {
6324                         /* we swallow the excepton as it is the behavior on .NET */
6325                         MonoObject *exc = NULL;
6326                         mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6327                         if (exc)
6328                                 mono_unhandled_exception (exc);
6329                 }
6330         }
6331
6332         return res;
6333 }
6334
6335 void
6336 mono_message_init (MonoDomain *domain,
6337                    MonoMethodMessage *this_obj, 
6338                    MonoReflectionMethod *method,
6339                    MonoArray *out_args)
6340 {
6341         MONO_REQ_GC_UNSAFE_MODE;
6342
6343         static MonoClass *object_array_klass;
6344         static MonoClass *byte_array_klass;
6345         static MonoClass *string_array_klass;
6346         MonoError error;
6347         MonoMethodSignature *sig = mono_method_signature (method->method);
6348         MonoString *name;
6349         MonoArray *arr;
6350         int i, j;
6351         char **names;
6352         guint8 arg_type;
6353
6354         if (!object_array_klass) {
6355                 MonoClass *klass;
6356
6357                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6358                 g_assert (klass);
6359                 byte_array_klass = klass;
6360
6361                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6362                 g_assert (klass);
6363                 string_array_klass = klass;
6364
6365                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6366                 g_assert (klass);
6367
6368                 mono_atomic_store_release (&object_array_klass, klass);
6369         }
6370
6371         MONO_OBJECT_SETREF (this_obj, method, method);
6372
6373         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6374         mono_error_raise_exception (&error); /* FIXME don't raise here */
6375
6376         MONO_OBJECT_SETREF (this_obj, args, arr);
6377
6378         arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6379         mono_error_raise_exception (&error); /* FIXME don't raise here */
6380
6381         MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6382
6383         this_obj->async_result = NULL;
6384         this_obj->call_type = CallType_Sync;
6385
6386         names = g_new (char *, sig->param_count);
6387         mono_method_get_param_names (method->method, (const char **) names);
6388
6389         arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6390         mono_error_raise_exception (&error); /* FIXME don't raise here */
6391
6392         MONO_OBJECT_SETREF (this_obj, names, arr);
6393         
6394         for (i = 0; i < sig->param_count; i++) {
6395                 name = mono_string_new (domain, names [i]);
6396                 mono_array_setref (this_obj->names, i, name);   
6397         }
6398
6399         g_free (names);
6400         for (i = 0, j = 0; i < sig->param_count; i++) {
6401                 if (sig->params [i]->byref) {
6402                         if (out_args) {
6403                                 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6404                                 mono_array_setref (this_obj->args, i, arg);
6405                                 j++;
6406                         }
6407                         arg_type = 2;
6408                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6409                                 arg_type |= 1;
6410                 } else {
6411                         arg_type = 1;
6412                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6413                                 arg_type |= 4;
6414                 }
6415                 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6416         }
6417 }
6418
6419 #ifndef DISABLE_REMOTING
6420 /**
6421  * mono_remoting_invoke:
6422  * @real_proxy: pointer to a RealProxy object
6423  * @msg: The MonoMethodMessage to execute
6424  * @exc: used to store exceptions
6425  * @out_args: used to store output arguments
6426  *
6427  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6428  * IMessage interface and it is not trivial to extract results from there. So
6429  * we call an helper method PrivateInvoke instead of calling
6430  * RealProxy::Invoke() directly.
6431  *
6432  * Returns: the result object.
6433  */
6434 MonoObject *
6435 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
6436                       MonoObject **exc, MonoArray **out_args)
6437 {
6438         MONO_REQ_GC_UNSAFE_MODE;
6439
6440         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6441         gpointer pa [4];
6442
6443         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6444
6445         if (!im) {
6446                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6447                 if (!im)
6448                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6449                 real_proxy->vtable->domain->private_invoke_method = im;
6450         }
6451
6452         pa [0] = real_proxy;
6453         pa [1] = msg;
6454         pa [2] = exc;
6455         pa [3] = out_args;
6456
6457         return mono_runtime_invoke (im, NULL, pa, exc);
6458 }
6459 #endif
6460
6461 MonoObject *
6462 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6463                      MonoObject **exc, MonoArray **out_args) 
6464 {
6465         MONO_REQ_GC_UNSAFE_MODE;
6466
6467         static MonoClass *object_array_klass;
6468         MonoError error;
6469         MonoDomain *domain; 
6470         MonoMethod *method;
6471         MonoMethodSignature *sig;
6472         MonoObject *ret;
6473         MonoArray *arr;
6474         int i, j, outarg_count = 0;
6475
6476 #ifndef DISABLE_REMOTING
6477         if (target && mono_object_is_transparent_proxy (target)) {
6478                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6479                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6480                         target = tp->rp->unwrapped_server;
6481                 } else {
6482                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6483                 }
6484         }
6485 #endif
6486
6487         domain = mono_domain_get (); 
6488         method = msg->method->method;
6489         sig = mono_method_signature (method);
6490
6491         for (i = 0; i < sig->param_count; i++) {
6492                 if (sig->params [i]->byref) 
6493                         outarg_count++;
6494         }
6495
6496         if (!object_array_klass) {
6497                 MonoClass *klass;
6498
6499                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6500                 g_assert (klass);
6501
6502                 mono_memory_barrier ();
6503                 object_array_klass = klass;
6504         }
6505
6506         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6507         mono_error_raise_exception (&error); /* FIXME don't raise here */
6508
6509         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6510         *exc = NULL;
6511
6512         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6513
6514         for (i = 0, j = 0; i < sig->param_count; i++) {
6515                 if (sig->params [i]->byref) {
6516                         MonoObject* arg;
6517                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6518                         mono_array_setref (*out_args, j, arg);
6519                         j++;
6520                 }
6521         }
6522
6523         return ret;
6524 }
6525
6526 /**
6527  * mono_object_to_string:
6528  * @obj: The object
6529  * @exc: Any exception thrown by ToString (). May be NULL.
6530  *
6531  * Returns: the result of calling ToString () on an object.
6532  */
6533 MonoString *
6534 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6535 {
6536         MONO_REQ_GC_UNSAFE_MODE;
6537
6538         static MonoMethod *to_string = NULL;
6539         MonoMethod *method;
6540         void *target = obj;
6541
6542         g_assert (obj);
6543
6544         if (!to_string)
6545                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6546
6547         method = mono_object_get_virtual_method (obj, to_string);
6548
6549         // Unbox value type if needed
6550         if (mono_class_is_valuetype (mono_method_get_class (method))) {
6551                 target = mono_object_unbox (obj);
6552         }
6553
6554         return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6555 }
6556
6557 /**
6558  * mono_print_unhandled_exception:
6559  * @exc: The exception
6560  *
6561  * Prints the unhandled exception.
6562  */
6563 void
6564 mono_print_unhandled_exception (MonoObject *exc)
6565 {
6566         MONO_REQ_GC_UNSAFE_MODE;
6567
6568         MonoString * str;
6569         char *message = (char*)"";
6570         gboolean free_message = FALSE;
6571         MonoError error;
6572
6573         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6574                 message = g_strdup ("OutOfMemoryException");
6575                 free_message = TRUE;
6576         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6577                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6578                 free_message = TRUE;
6579         } else {
6580                 
6581                 if (((MonoException*)exc)->native_trace_ips) {
6582                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
6583                         free_message = TRUE;
6584                 } else {
6585                         MonoObject *other_exc = NULL;
6586                         str = mono_object_to_string (exc, &other_exc);
6587                         if (other_exc) {
6588                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6589                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6590                                 
6591                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6592                                         original_backtrace, nested_backtrace);
6593
6594                                 g_free (original_backtrace);
6595                                 g_free (nested_backtrace);
6596                                 free_message = TRUE;
6597                         } else if (str) {
6598                                 message = mono_string_to_utf8_checked (str, &error);
6599                                 if (!mono_error_ok (&error)) {
6600                                         mono_error_cleanup (&error);
6601                                         message = (char *) "";
6602                                 } else {
6603                                         free_message = TRUE;
6604                                 }
6605                         }
6606                 }
6607         }
6608
6609         /*
6610          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
6611          *         exc->vtable->klass->name, message);
6612          */
6613         g_printerr ("\nUnhandled Exception:\n%s\n", message);
6614         
6615         if (free_message)
6616                 g_free (message);
6617 }
6618
6619 /**
6620  * mono_delegate_ctor:
6621  * @this: pointer to an uninitialized delegate object
6622  * @target: target object
6623  * @addr: pointer to native code
6624  * @method: method
6625  *
6626  * Initialize a delegate and sets a specific method, not the one
6627  * associated with addr.  This is useful when sharing generic code.
6628  * In that case addr will most probably not be associated with the
6629  * correct instantiation of the method.
6630  */
6631 void
6632 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6633 {
6634         MONO_REQ_GC_UNSAFE_MODE;
6635
6636         MonoDelegate *delegate = (MonoDelegate *)this_obj;
6637
6638         g_assert (this_obj);
6639         g_assert (addr);
6640
6641         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6642
6643         if (method)
6644                 delegate->method = method;
6645
6646         mono_stats.delegate_creations++;
6647
6648 #ifndef DISABLE_REMOTING
6649         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6650                 g_assert (method);
6651                 method = mono_marshal_get_remoting_invoke (method);
6652                 delegate->method_ptr = mono_compile_method (method);
6653                 MONO_OBJECT_SETREF (delegate, target, target);
6654         } else
6655 #endif
6656         {
6657                 delegate->method_ptr = addr;
6658                 MONO_OBJECT_SETREF (delegate, target, target);
6659         }
6660
6661         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6662         if (callbacks.init_delegate)
6663                 callbacks.init_delegate (delegate);
6664 }
6665
6666 /**
6667  * mono_delegate_ctor:
6668  * @this: pointer to an uninitialized delegate object
6669  * @target: target object
6670  * @addr: pointer to native code
6671  *
6672  * This is used to initialize a delegate.
6673  */
6674 void
6675 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6676 {
6677         MONO_REQ_GC_UNSAFE_MODE;
6678
6679         MonoDomain *domain = mono_domain_get ();
6680         MonoJitInfo *ji;
6681         MonoMethod *method = NULL;
6682
6683         g_assert (addr);
6684
6685         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6686         /* Shared code */
6687         if (!ji && domain != mono_get_root_domain ())
6688                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6689         if (ji) {
6690                 method = mono_jit_info_get_method (ji);
6691                 g_assert (!method->klass->generic_container);
6692         }
6693
6694         mono_delegate_ctor_with_method (this_obj, target, addr, method);
6695 }
6696
6697 /**
6698  * mono_method_call_message_new:
6699  * @method: method to encapsulate
6700  * @params: parameters to the method
6701  * @invoke: optional, delegate invoke.
6702  * @cb: async callback delegate.
6703  * @state: state passed to the async callback.
6704  *
6705  * Translates arguments pointers into a MonoMethodMessage.
6706  */
6707 MonoMethodMessage *
6708 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
6709                               MonoDelegate **cb, MonoObject **state)
6710 {
6711         MONO_REQ_GC_UNSAFE_MODE;
6712
6713         MonoDomain *domain = mono_domain_get ();
6714         MonoMethodSignature *sig = mono_method_signature (method);
6715         MonoMethodMessage *msg;
6716         int i, count;
6717
6718         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
6719         
6720         if (invoke) {
6721                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6722                 count =  sig->param_count - 2;
6723         } else {
6724                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6725                 count =  sig->param_count;
6726         }
6727
6728         for (i = 0; i < count; i++) {
6729                 gpointer vpos;
6730                 MonoClass *klass;
6731                 MonoObject *arg;
6732
6733                 if (sig->params [i]->byref)
6734                         vpos = *((gpointer *)params [i]);
6735                 else 
6736                         vpos = params [i];
6737
6738                 klass = mono_class_from_mono_type (sig->params [i]);
6739
6740                 if (klass->valuetype)
6741                         arg = mono_value_box (domain, klass, vpos);
6742                 else 
6743                         arg = *((MonoObject **)vpos);
6744                       
6745                 mono_array_setref (msg->args, i, arg);
6746         }
6747
6748         if (cb != NULL && state != NULL) {
6749                 *cb = *((MonoDelegate **)params [i]);
6750                 i++;
6751                 *state = *((MonoObject **)params [i]);
6752         }
6753
6754         return msg;
6755 }
6756
6757 /**
6758  * mono_method_return_message_restore:
6759  *
6760  * Restore results from message based processing back to arguments pointers
6761  */
6762 void
6763 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6764 {
6765         MONO_REQ_GC_UNSAFE_MODE;
6766
6767         MonoMethodSignature *sig = mono_method_signature (method);
6768         int i, j, type, size, out_len;
6769         
6770         if (out_args == NULL)
6771                 return;
6772         out_len = mono_array_length (out_args);
6773         if (out_len == 0)
6774                 return;
6775
6776         for (i = 0, j = 0; i < sig->param_count; i++) {
6777                 MonoType *pt = sig->params [i];
6778
6779                 if (pt->byref) {
6780                         char *arg;
6781                         if (j >= out_len)
6782                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6783
6784                         arg = (char *)mono_array_get (out_args, gpointer, j);
6785                         type = pt->type;
6786
6787                         g_assert (type != MONO_TYPE_VOID);
6788
6789                         if (MONO_TYPE_IS_REFERENCE (pt)) {
6790                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6791                         } else {
6792                                 if (arg) {
6793                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6794                                         size = mono_class_value_size (klass, NULL);
6795                                         if (klass->has_references)
6796                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6797                                         else
6798                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6799                                 } else {
6800                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6801                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6802                                 }
6803                         }
6804
6805                         j++;
6806                 }
6807         }
6808 }
6809
6810 #ifndef DISABLE_REMOTING
6811
6812 /**
6813  * mono_load_remote_field:
6814  * @this: pointer to an object
6815  * @klass: klass of the object containing @field
6816  * @field: the field to load
6817  * @res: a storage to store the result
6818  *
6819  * This method is called by the runtime on attempts to load fields of
6820  * transparent proxy objects. @this points to such TP, @klass is the class of
6821  * the object containing @field. @res is a storage location which can be
6822  * used to store the result.
6823  *
6824  * Returns: an address pointing to the value of field.
6825  */
6826 gpointer
6827 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6828 {
6829         MONO_REQ_GC_UNSAFE_MODE;
6830
6831         static MonoMethod *getter = NULL;
6832         MonoDomain *domain = mono_domain_get ();
6833         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6834         MonoClass *field_class;
6835         MonoMethodMessage *msg;
6836         MonoArray *out_args;
6837         MonoObject *exc;
6838         char* full_name;
6839
6840         g_assert (mono_object_is_transparent_proxy (this_obj));
6841         g_assert (res != NULL);
6842
6843         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6844                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6845                 return res;
6846         }
6847         
6848         if (!getter) {
6849                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6850                 if (!getter)
6851                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6852         }
6853         
6854         field_class = mono_class_from_mono_type (field->type);
6855
6856         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6857         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6858         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6859
6860         full_name = mono_type_get_full_name (klass);
6861         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6862         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6863         g_free (full_name);
6864
6865         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6866
6867         if (exc) mono_raise_exception ((MonoException *)exc);
6868
6869         if (mono_array_length (out_args) == 0)
6870                 return NULL;
6871
6872         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6873
6874         if (field_class->valuetype) {
6875                 return ((char *)*res) + sizeof (MonoObject);
6876         } else
6877                 return res;
6878 }
6879
6880 /**
6881  * mono_load_remote_field_new:
6882  * @this: 
6883  * @klass: 
6884  * @field:
6885  *
6886  * Missing documentation.
6887  */
6888 MonoObject *
6889 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6890 {
6891         MONO_REQ_GC_UNSAFE_MODE;
6892
6893         static MonoMethod *getter = NULL;
6894         MonoDomain *domain = mono_domain_get ();
6895         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6896         MonoClass *field_class;
6897         MonoMethodMessage *msg;
6898         MonoArray *out_args;
6899         MonoObject *exc, *res;
6900         char* full_name;
6901
6902         g_assert (mono_object_is_transparent_proxy (this_obj));
6903
6904         field_class = mono_class_from_mono_type (field->type);
6905
6906         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6907                 gpointer val;
6908                 if (field_class->valuetype) {
6909                         res = mono_object_new (domain, field_class);
6910                         val = ((gchar *) res) + sizeof (MonoObject);
6911                 } else {
6912                         val = &res;
6913                 }
6914                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6915                 return res;
6916         }
6917
6918         if (!getter) {
6919                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6920                 if (!getter)
6921                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6922         }
6923         
6924         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6925         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6926
6927         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6928
6929         full_name = mono_type_get_full_name (klass);
6930         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6931         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6932         g_free (full_name);
6933
6934         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6935
6936         if (exc) mono_raise_exception ((MonoException *)exc);
6937
6938         if (mono_array_length (out_args) == 0)
6939                 res = NULL;
6940         else
6941                 res = mono_array_get (out_args, MonoObject *, 0);
6942
6943         return res;
6944 }
6945
6946 /**
6947  * mono_store_remote_field:
6948  * @this_obj: pointer to an object
6949  * @klass: klass of the object containing @field
6950  * @field: the field to load
6951  * @val: the value/object to store
6952  *
6953  * This method is called by the runtime on attempts to store fields of
6954  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6955  * the object containing @field. @val is the new value to store in @field.
6956  */
6957 void
6958 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6959 {
6960         MONO_REQ_GC_UNSAFE_MODE;
6961
6962         static MonoMethod *setter = NULL;
6963         MonoDomain *domain = mono_domain_get ();
6964         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6965         MonoClass *field_class;
6966         MonoMethodMessage *msg;
6967         MonoArray *out_args;
6968         MonoObject *exc;
6969         MonoObject *arg;
6970         char* full_name;
6971
6972         g_assert (mono_object_is_transparent_proxy (this_obj));
6973
6974         field_class = mono_class_from_mono_type (field->type);
6975
6976         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6977                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6978                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6979                 return;
6980         }
6981
6982         if (!setter) {
6983                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6984                 if (!setter)
6985                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6986         }
6987
6988         if (field_class->valuetype)
6989                 arg = mono_value_box (domain, field_class, val);
6990         else 
6991                 arg = *((MonoObject **)val);
6992                 
6993
6994         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6995         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6996
6997         full_name = mono_type_get_full_name (klass);
6998         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6999         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7000         mono_array_setref (msg->args, 2, arg);
7001         g_free (full_name);
7002
7003         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7004
7005         if (exc) mono_raise_exception ((MonoException *)exc);
7006 }
7007
7008 /**
7009  * mono_store_remote_field_new:
7010  * @this_obj:
7011  * @klass:
7012  * @field:
7013  * @arg:
7014  *
7015  * Missing documentation
7016  */
7017 void
7018 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7019 {
7020         MONO_REQ_GC_UNSAFE_MODE;
7021
7022         static MonoMethod *setter = NULL;
7023         MonoDomain *domain = mono_domain_get ();
7024         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7025         MonoClass *field_class;
7026         MonoMethodMessage *msg;
7027         MonoArray *out_args;
7028         MonoObject *exc;
7029         char* full_name;
7030
7031         g_assert (mono_object_is_transparent_proxy (this_obj));
7032
7033         field_class = mono_class_from_mono_type (field->type);
7034
7035         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7036                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7037                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7038                 return;
7039         }
7040
7041         if (!setter) {
7042                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7043                 if (!setter)
7044                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7045         }
7046
7047         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
7048         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
7049
7050         full_name = mono_type_get_full_name (klass);
7051         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7052         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7053         mono_array_setref (msg->args, 2, arg);
7054         g_free (full_name);
7055
7056         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7057
7058         if (exc) mono_raise_exception ((MonoException *)exc);
7059 }
7060 #endif
7061
7062 /*
7063  * mono_create_ftnptr:
7064  *
7065  *   Given a function address, create a function descriptor for it.
7066  * This is only needed on some platforms.
7067  */
7068 gpointer
7069 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7070 {
7071         return callbacks.create_ftnptr (domain, addr);
7072 }
7073
7074 /*
7075  * mono_get_addr_from_ftnptr:
7076  *
7077  *   Given a pointer to a function descriptor, return the function address.
7078  * This is only needed on some platforms.
7079  */
7080 gpointer
7081 mono_get_addr_from_ftnptr (gpointer descr)
7082 {
7083         return callbacks.get_addr_from_ftnptr (descr);
7084 }       
7085
7086 /**
7087  * mono_string_chars:
7088  * @s: a MonoString
7089  *
7090  * Returns a pointer to the UCS16 characters stored in the MonoString
7091  */
7092 gunichar2 *
7093 mono_string_chars (MonoString *s)
7094 {
7095         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7096
7097         return s->chars;
7098 }
7099
7100 /**
7101  * mono_string_length:
7102  * @s: MonoString
7103  *
7104  * Returns the lenght in characters of the string
7105  */
7106 int
7107 mono_string_length (MonoString *s)
7108 {
7109         MONO_REQ_GC_UNSAFE_MODE;
7110
7111         return s->length;
7112 }
7113
7114 /**
7115  * mono_array_length:
7116  * @array: a MonoArray*
7117  *
7118  * Returns the total number of elements in the array. This works for
7119  * both vectors and multidimensional arrays.
7120  */
7121 uintptr_t
7122 mono_array_length (MonoArray *array)
7123 {
7124         MONO_REQ_GC_UNSAFE_MODE;
7125
7126         return array->max_length;
7127 }
7128
7129 /**
7130  * mono_array_addr_with_size:
7131  * @array: a MonoArray*
7132  * @size: size of the array elements
7133  * @idx: index into the array
7134  *
7135  * Returns the address of the @idx element in the array.
7136  */
7137 char*
7138 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7139 {
7140         MONO_REQ_GC_UNSAFE_MODE;
7141
7142         return ((char*)(array)->vector) + size * idx;
7143 }
7144
7145
7146 MonoArray *
7147 mono_glist_to_array (GList *list, MonoClass *eclass) 
7148 {
7149         MonoDomain *domain = mono_domain_get ();
7150         MonoArray *res;
7151         int len, i;
7152
7153         if (!list)
7154                 return NULL;
7155
7156         len = g_list_length (list);
7157         res = mono_array_new (domain, eclass, len);
7158
7159         for (i = 0; list; list = list->next, i++)
7160                 mono_array_set (res, gpointer, i, list->data);
7161
7162         return res;
7163 }
7164