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