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