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