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