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