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