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