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