Merge pull request #2580 from ItsVeryWindy/master
[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 (!mono_error_ok (&error))
2165                                         mono_error_raise_exception (&error); /* FIXME: Don't raise here */
2166                         }
2167                 }
2168         }
2169
2170         if (imt_table_bytes) {
2171                 /* Now that the vtable is full, we can actually fill up the IMT */
2172                         for (i = 0; i < MONO_IMT_SIZE; ++i)
2173                                 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2174         }
2175
2176         /*
2177          * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2178          * re-acquire them and check if another thread has created the vtable in the meantime.
2179          */
2180         /* Special case System.MonoType to avoid infinite recursion */
2181         if (klass != mono_defaults.monotype_class) {
2182                 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2183                 if (!is_ok (error)) {
2184                         mono_domain_unlock (domain);
2185                         mono_loader_unlock ();
2186                         return NULL;
2187                 }
2188
2189                 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2190                         /* This is unregistered in
2191                            unregister_vtable_reflection_type() in
2192                            domain.c. */
2193                         MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2194         }
2195
2196         mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2197
2198         /*  class_vtable_array keeps an array of created vtables
2199          */
2200         g_ptr_array_add (domain->class_vtable_array, vt);
2201         /* klass->runtime_info is protected by the loader lock, both when
2202          * it it enlarged and when it is stored info.
2203          */
2204
2205         /*
2206          * Store the vtable in klass->runtime_info.
2207          * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2208          */
2209         mono_memory_barrier ();
2210
2211         old_info = klass->runtime_info;
2212         if (old_info && old_info->max_domain >= domain->domain_id) {
2213                 /* someone already created a large enough runtime info */
2214                 old_info->domain_vtables [domain->domain_id] = vt;
2215         } else {
2216                 int new_size = domain->domain_id;
2217                 if (old_info)
2218                         new_size = MAX (new_size, old_info->max_domain);
2219                 new_size++;
2220                 /* make the new size a power of two */
2221                 i = 2;
2222                 while (new_size > i)
2223                         i <<= 1;
2224                 new_size = i;
2225                 /* this is a bounded memory retention issue: may want to 
2226                  * handle it differently when we'll have a rcu-like system.
2227                  */
2228                 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2229                 runtime_info->max_domain = new_size - 1;
2230                 /* copy the stuff from the older info */
2231                 if (old_info) {
2232                         memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2233                 }
2234                 runtime_info->domain_vtables [domain->domain_id] = vt;
2235                 /* keep this last*/
2236                 mono_memory_barrier ();
2237                 klass->runtime_info = runtime_info;
2238         }
2239
2240         if (klass == mono_defaults.monotype_class) {
2241                 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2242                 if (!is_ok (error)) {
2243                         mono_domain_unlock (domain);
2244                         mono_loader_unlock ();
2245                         return NULL;
2246                 }
2247
2248                 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2249                         /* This is unregistered in
2250                            unregister_vtable_reflection_type() in
2251                            domain.c. */
2252                         MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2253         }
2254
2255         mono_domain_unlock (domain);
2256         mono_loader_unlock ();
2257
2258         /* make sure the parent is initialized */
2259         /*FIXME shouldn't this fail the current type?*/
2260         if (klass->parent)
2261                 mono_class_vtable_full (domain, klass->parent, error);
2262
2263         return vt;
2264 }
2265
2266 #ifndef DISABLE_REMOTING
2267 /**
2268  * mono_class_proxy_vtable:
2269  * @domain: the application domain
2270  * @remove_class: the remote class
2271  *
2272  * Creates a vtable for transparent proxies. It is basically
2273  * a copy of the real vtable of the class wrapped in @remote_class,
2274  * but all function pointers invoke the remoting functions, and
2275  * vtable->klass points to the transparent proxy class, and not to @class.
2276  */
2277 static MonoVTable *
2278 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2279 {
2280         MONO_REQ_GC_UNSAFE_MODE;
2281
2282         MonoError error;
2283         MonoVTable *vt, *pvt;
2284         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2285         MonoClass *k;
2286         GSList *extra_interfaces = NULL;
2287         MonoClass *klass = remote_class->proxy_class;
2288         gpointer *interface_offsets;
2289         uint8_t *bitmap;
2290         int bsize;
2291         size_t imt_table_bytes;
2292         
2293 #ifdef COMPRESSED_INTERFACE_BITMAP
2294         int bcsize;
2295 #endif
2296
2297         vt = mono_class_vtable (domain, klass);
2298         g_assert (vt); /*FIXME property handle failure*/
2299         max_interface_id = vt->max_interface_id;
2300         
2301         /* Calculate vtable space for extra interfaces */
2302         for (j = 0; j < remote_class->interface_count; j++) {
2303                 MonoClass* iclass = remote_class->interfaces[j];
2304                 GPtrArray *ifaces;
2305                 int method_count;
2306
2307                 /*FIXME test for interfaces with variant generic arguments*/
2308                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2309                         continue;       /* interface implemented by the class */
2310                 if (g_slist_find (extra_interfaces, iclass))
2311                         continue;
2312                         
2313                 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2314                 
2315                 method_count = mono_class_num_methods (iclass);
2316         
2317                 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2318                 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2319                 if (ifaces) {
2320                         for (i = 0; i < ifaces->len; ++i) {
2321                                 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2322                                 /*FIXME test for interfaces with variant generic arguments*/
2323                                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2324                                         continue;       /* interface implemented by the class */
2325                                 if (g_slist_find (extra_interfaces, ic))
2326                                         continue;
2327                                 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2328                                 method_count += mono_class_num_methods (ic);
2329                         }
2330                         g_ptr_array_free (ifaces, TRUE);
2331                 }
2332
2333                 extra_interface_vtsize += method_count * sizeof (gpointer);
2334                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2335         }
2336
2337         imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2338         mono_stats.imt_number_of_tables++;
2339         mono_stats.imt_tables_size += imt_table_bytes;
2340
2341         vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2342
2343         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2344
2345         interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2346         pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2347         g_assert (!((gsize)pvt & 7));
2348
2349         memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2350
2351         pvt->klass = mono_defaults.transparent_proxy_class;
2352         /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2353         pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2354
2355         /* initialize vtable */
2356         mono_class_setup_vtable (klass);
2357         for (i = 0; i < klass->vtable_size; ++i) {
2358                 MonoMethod *cm;
2359                     
2360                 if ((cm = klass->vtable [i]))
2361                         pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2362                 else
2363                         pvt->vtable [i] = NULL;
2364         }
2365
2366         if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2367                 /* create trampolines for abstract methods */
2368                 for (k = klass; k; k = k->parent) {
2369                         MonoMethod* m;
2370                         gpointer iter = NULL;
2371                         while ((m = mono_class_get_methods (k, &iter)))
2372                                 if (!pvt->vtable [m->slot])
2373                                         pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2374                 }
2375         }
2376
2377         pvt->max_interface_id = max_interface_id;
2378         bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2379 #ifdef COMPRESSED_INTERFACE_BITMAP
2380         bitmap = (uint8_t *)g_malloc0 (bsize);
2381 #else
2382         bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2383 #endif
2384
2385         for (i = 0; i < klass->interface_offsets_count; ++i) {
2386                 int interface_id = klass->interfaces_packed [i]->interface_id;
2387                 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2388         }
2389
2390         if (extra_interfaces) {
2391                 int slot = klass->vtable_size;
2392                 MonoClass* interf;
2393                 gpointer iter;
2394                 MonoMethod* cm;
2395                 GSList *list_item;
2396
2397                 /* Create trampolines for the methods of the interfaces */
2398                 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2399                         interf = (MonoClass *)list_item->data;
2400                         
2401                         bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2402
2403                         iter = NULL;
2404                         j = 0;
2405                         while ((cm = mono_class_get_methods (interf, &iter)))
2406                                 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2407                         
2408                         slot += mono_class_num_methods (interf);
2409                 }
2410         }
2411
2412         /* Now that the vtable is full, we can actually fill up the IMT */
2413         build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2414         if (extra_interfaces) {
2415                 g_slist_free (extra_interfaces);
2416         }
2417
2418 #ifdef COMPRESSED_INTERFACE_BITMAP
2419         bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2420         pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2421         mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2422         g_free (bitmap);
2423 #else
2424         pvt->interface_bitmap = bitmap;
2425 #endif
2426         return pvt;
2427 }
2428
2429 #endif /* DISABLE_REMOTING */
2430
2431 /**
2432  * mono_class_field_is_special_static:
2433  *
2434  *   Returns whether @field is a thread/context static field.
2435  */
2436 gboolean
2437 mono_class_field_is_special_static (MonoClassField *field)
2438 {
2439         MONO_REQ_GC_NEUTRAL_MODE
2440
2441         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2442                 return FALSE;
2443         if (mono_field_is_deleted (field))
2444                 return FALSE;
2445         if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2446                 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2447                         return TRUE;
2448         }
2449         return FALSE;
2450 }
2451
2452 /**
2453  * mono_class_field_get_special_static_type:
2454  * @field: The MonoClassField describing the field.
2455  *
2456  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2457  * SPECIAL_STATIC_NONE otherwise.
2458  */
2459 guint32
2460 mono_class_field_get_special_static_type (MonoClassField *field)
2461 {
2462         MONO_REQ_GC_NEUTRAL_MODE
2463
2464         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2465                 return SPECIAL_STATIC_NONE;
2466         if (mono_field_is_deleted (field))
2467                 return SPECIAL_STATIC_NONE;
2468         if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2469                 return field_is_special_static (field->parent, field);
2470         return SPECIAL_STATIC_NONE;
2471 }
2472
2473 /**
2474  * mono_class_has_special_static_fields:
2475  * 
2476  *   Returns whenever @klass has any thread/context static fields.
2477  */
2478 gboolean
2479 mono_class_has_special_static_fields (MonoClass *klass)
2480 {
2481         MONO_REQ_GC_NEUTRAL_MODE
2482
2483         MonoClassField *field;
2484         gpointer iter;
2485
2486         iter = NULL;
2487         while ((field = mono_class_get_fields (klass, &iter))) {
2488                 g_assert (field->parent == klass);
2489                 if (mono_class_field_is_special_static (field))
2490                         return TRUE;
2491         }
2492
2493         return FALSE;
2494 }
2495
2496 #ifndef DISABLE_REMOTING
2497 /**
2498  * create_remote_class_key:
2499  * Creates an array of pointers that can be used as a hash key for a remote class.
2500  * The first element of the array is the number of pointers.
2501  */
2502 static gpointer*
2503 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2504 {
2505         MONO_REQ_GC_NEUTRAL_MODE;
2506
2507         gpointer *key;
2508         int i, j;
2509         
2510         if (remote_class == NULL) {
2511                 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2512                         key = (void **)g_malloc (sizeof(gpointer) * 3);
2513                         key [0] = GINT_TO_POINTER (2);
2514                         key [1] = mono_defaults.marshalbyrefobject_class;
2515                         key [2] = extra_class;
2516                 } else {
2517                         key = (void **)g_malloc (sizeof(gpointer) * 2);
2518                         key [0] = GINT_TO_POINTER (1);
2519                         key [1] = extra_class;
2520                 }
2521         } else {
2522                 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2523                         key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2524                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2525                         key [1] = remote_class->proxy_class;
2526
2527                         // Keep the list of interfaces sorted
2528                         for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2529                                 if (extra_class && remote_class->interfaces [i] > extra_class) {
2530                                         key [j++] = extra_class;
2531                                         extra_class = NULL;
2532                                 }
2533                                 key [j] = remote_class->interfaces [i];
2534                         }
2535                         if (extra_class)
2536                                 key [j] = extra_class;
2537                 } else {
2538                         // Replace the old class. The interface list is the same
2539                         key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2540                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2541                         key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2542                         for (i = 0; i < remote_class->interface_count; i++)
2543                                 key [2 + i] = remote_class->interfaces [i];
2544                 }
2545         }
2546         
2547         return key;
2548 }
2549
2550 /**
2551  * copy_remote_class_key:
2552  *
2553  *   Make a copy of KEY in the domain and return the copy.
2554  */
2555 static gpointer*
2556 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2557 {
2558         MONO_REQ_GC_NEUTRAL_MODE
2559
2560         int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2561         gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2562
2563         memcpy (mp_key, key, key_size);
2564
2565         return mp_key;
2566 }
2567
2568 /**
2569  * mono_remote_class:
2570  * @domain: the application domain
2571  * @class_name: name of the remote class
2572  *
2573  * Creates and initializes a MonoRemoteClass object for a remote type. 
2574  *
2575  * Can raise an exception on failure. 
2576  */
2577 MonoRemoteClass*
2578 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2579 {
2580         MONO_REQ_GC_UNSAFE_MODE;
2581
2582         MonoError error;
2583         MonoRemoteClass *rc;
2584         gpointer* key, *mp_key;
2585         char *name;
2586         
2587         key = create_remote_class_key (NULL, proxy_class);
2588         
2589         mono_domain_lock (domain);
2590         rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2591
2592         if (rc) {
2593                 g_free (key);
2594                 mono_domain_unlock (domain);
2595                 return rc;
2596         }
2597
2598         name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2599         if (!mono_error_ok (&error)) {
2600                 g_free (key);
2601                 mono_domain_unlock (domain);
2602                 mono_error_raise_exception (&error);
2603         }
2604
2605         mp_key = copy_remote_class_key (domain, key);
2606         g_free (key);
2607         key = mp_key;
2608
2609         if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2610                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2611                 rc->interface_count = 1;
2612                 rc->interfaces [0] = proxy_class;
2613                 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2614         } else {
2615                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2616                 rc->interface_count = 0;
2617                 rc->proxy_class = proxy_class;
2618         }
2619         
2620         rc->default_vtable = NULL;
2621         rc->xdomain_vtable = NULL;
2622         rc->proxy_class_name = name;
2623 #ifndef DISABLE_PERFCOUNTERS
2624         mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2625 #endif
2626
2627         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2628
2629         mono_domain_unlock (domain);
2630         return rc;
2631 }
2632
2633 /**
2634  * clone_remote_class:
2635  * Creates a copy of the remote_class, adding the provided class or interface
2636  */
2637 static MonoRemoteClass*
2638 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2639 {
2640         MONO_REQ_GC_NEUTRAL_MODE;
2641
2642         MonoRemoteClass *rc;
2643         gpointer* key, *mp_key;
2644         
2645         key = create_remote_class_key (remote_class, extra_class);
2646         rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2647         if (rc != NULL) {
2648                 g_free (key);
2649                 return rc;
2650         }
2651
2652         mp_key = copy_remote_class_key (domain, key);
2653         g_free (key);
2654         key = mp_key;
2655
2656         if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2657                 int i,j;
2658                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2659                 rc->proxy_class = remote_class->proxy_class;
2660                 rc->interface_count = remote_class->interface_count + 1;
2661                 
2662                 // Keep the list of interfaces sorted, since the hash key of
2663                 // the remote class depends on this
2664                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2665                         if (remote_class->interfaces [i] > extra_class && i == j)
2666                                 rc->interfaces [j++] = extra_class;
2667                         rc->interfaces [j] = remote_class->interfaces [i];
2668                 }
2669                 if (i == j)
2670                         rc->interfaces [j] = extra_class;
2671         } else {
2672                 // Replace the old class. The interface array is the same
2673                 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2674                 rc->proxy_class = extra_class;
2675                 rc->interface_count = remote_class->interface_count;
2676                 if (rc->interface_count > 0)
2677                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2678         }
2679         
2680         rc->default_vtable = NULL;
2681         rc->xdomain_vtable = NULL;
2682         rc->proxy_class_name = remote_class->proxy_class_name;
2683
2684         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2685
2686         return rc;
2687 }
2688
2689 gpointer
2690 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2691 {
2692         MONO_REQ_GC_UNSAFE_MODE;
2693
2694         mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2695         mono_domain_lock (domain);
2696         if (rp->target_domain_id != -1) {
2697                 if (remote_class->xdomain_vtable == NULL)
2698                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2699                 mono_domain_unlock (domain);
2700                 mono_loader_unlock ();
2701                 return remote_class->xdomain_vtable;
2702         }
2703         if (remote_class->default_vtable == NULL) {
2704                 MonoType *type;
2705                 MonoClass *klass;
2706                 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2707                 klass = mono_class_from_mono_type (type);
2708 #ifndef DISABLE_COM
2709                 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)))
2710                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2711                 else
2712 #endif
2713                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2714         }
2715         
2716         mono_domain_unlock (domain);
2717         mono_loader_unlock ();
2718         return remote_class->default_vtable;
2719 }
2720
2721 /**
2722  * mono_upgrade_remote_class:
2723  * @domain: the application domain
2724  * @tproxy: the proxy whose remote class has to be upgraded.
2725  * @klass: class to which the remote class can be casted.
2726  *
2727  * Updates the vtable of the remote class by adding the necessary method slots
2728  * and interface offsets so it can be safely casted to klass. klass can be a
2729  * class or an interface.
2730  */
2731 void
2732 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2733 {
2734         MONO_REQ_GC_UNSAFE_MODE;
2735
2736         MonoTransparentProxy *tproxy;
2737         MonoRemoteClass *remote_class;
2738         gboolean redo_vtable;
2739
2740         mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2741         mono_domain_lock (domain);
2742
2743         tproxy = (MonoTransparentProxy*) proxy_object;
2744         remote_class = tproxy->remote_class;
2745         
2746         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2747                 int i;
2748                 redo_vtable = TRUE;
2749                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2750                         if (remote_class->interfaces [i] == klass)
2751                                 redo_vtable = FALSE;
2752         }
2753         else {
2754                 redo_vtable = (remote_class->proxy_class != klass);
2755         }
2756
2757         if (redo_vtable) {
2758                 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2759                 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2760         }
2761         
2762         mono_domain_unlock (domain);
2763         mono_loader_unlock ();
2764 }
2765 #endif /* DISABLE_REMOTING */
2766
2767
2768 /**
2769  * mono_object_get_virtual_method:
2770  * @obj: object to operate on.
2771  * @method: method 
2772  *
2773  * Retrieves the MonoMethod that would be called on obj if obj is passed as
2774  * the instance of a callvirt of method.
2775  */
2776 MonoMethod*
2777 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2778 {
2779         MONO_REQ_GC_UNSAFE_MODE;
2780
2781         MonoClass *klass;
2782         MonoMethod **vtable;
2783         gboolean is_proxy = FALSE;
2784         MonoMethod *res = NULL;
2785
2786         klass = mono_object_class (obj);
2787 #ifndef DISABLE_REMOTING
2788         if (klass == mono_defaults.transparent_proxy_class) {
2789                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2790                 is_proxy = TRUE;
2791         }
2792 #endif
2793
2794         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2795                         return method;
2796
2797         mono_class_setup_vtable (klass);
2798         vtable = klass->vtable;
2799
2800         if (method->slot == -1) {
2801                 /* method->slot might not be set for instances of generic methods */
2802                 if (method->is_inflated) {
2803                         g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2804                         method->slot = ((MonoMethodInflated*)method)->declaring->slot; 
2805                 } else {
2806                         if (!is_proxy)
2807                                 g_assert_not_reached ();
2808                 }
2809         }
2810
2811         /* check method->slot is a valid index: perform isinstance? */
2812         if (method->slot != -1) {
2813                 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2814                         if (!is_proxy) {
2815                                 gboolean variance_used = FALSE;
2816                                 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2817                                 g_assert (iface_offset > 0);
2818                                 res = vtable [iface_offset + method->slot];
2819                         }
2820                 } else {
2821                         res = vtable [method->slot];
2822                 }
2823     }
2824
2825 #ifndef DISABLE_REMOTING
2826         if (is_proxy) {
2827                 /* It may be an interface, abstract class method or generic method */
2828                 if (!res || mono_method_signature (res)->generic_param_count)
2829                         res = method;
2830
2831                 /* generic methods demand invoke_with_check */
2832                 if (mono_method_signature (res)->generic_param_count)
2833                         res = mono_marshal_get_remoting_invoke_with_check (res);
2834                 else {
2835 #ifndef DISABLE_COM
2836                         if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2837                                 res = mono_cominterop_get_invoke (res);
2838                         else
2839 #endif
2840                                 res = mono_marshal_get_remoting_invoke (res);
2841                 }
2842         } else
2843 #endif
2844         {
2845                 if (method->is_inflated) {
2846                         MonoError error;
2847                         /* Have to inflate the result */
2848                         res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2849                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2850                 }
2851         }
2852
2853         g_assert (res);
2854         
2855         return res;
2856 }
2857
2858 static MonoObject*
2859 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2860 {
2861         MONO_REQ_GC_UNSAFE_MODE;
2862
2863         MonoObject *result = NULL;
2864
2865         g_assert (callbacks.runtime_invoke);
2866
2867         mono_error_init (error);
2868         
2869         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2870                 mono_profiler_method_start_invoke (method);
2871
2872         MONO_PREPARE_RESET_BLOCKING;
2873
2874         result = callbacks.runtime_invoke (method, obj, params, exc, error);
2875
2876         MONO_FINISH_RESET_BLOCKING;
2877
2878         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2879                 mono_profiler_method_end_invoke (method);
2880
2881         if (!mono_error_ok (error))
2882                 return NULL;
2883
2884         return result;
2885 }
2886
2887 /**
2888  * mono_runtime_invoke:
2889  * @method: method to invoke
2890  * @obJ: object instance
2891  * @params: arguments to the method
2892  * @exc: exception information.
2893  *
2894  * Invokes the method represented by @method on the object @obj.
2895  *
2896  * obj is the 'this' pointer, it should be NULL for static
2897  * methods, a MonoObject* for object instances and a pointer to
2898  * the value type for value types.
2899  *
2900  * The params array contains the arguments to the method with the
2901  * same convention: MonoObject* pointers for object instances and
2902  * pointers to the value type otherwise. 
2903  * 
2904  * From unmanaged code you'll usually use the
2905  * mono_runtime_invoke() variant.
2906  *
2907  * Note that this function doesn't handle virtual methods for
2908  * you, it will exec the exact method you pass: we still need to
2909  * expose a function to lookup the derived class implementation
2910  * of a virtual method (there are examples of this in the code,
2911  * though).
2912  * 
2913  * You can pass NULL as the exc argument if you don't want to
2914  * catch exceptions, otherwise, *exc will be set to the exception
2915  * thrown, if any.  if an exception is thrown, you can't use the
2916  * MonoObject* result from the function.
2917  * 
2918  * If the method returns a value type, it is boxed in an object
2919  * reference.
2920  */
2921 MonoObject*
2922 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2923 {
2924         MonoError error;
2925         MonoObject *res;
2926         if (exc) {
2927                 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2928                 if (*exc == NULL && !mono_error_ok(&error)) {
2929                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2930                 } else
2931                         mono_error_cleanup (&error);
2932         } else {
2933                 res = mono_runtime_invoke_checked (method, obj, params, &error);
2934                 mono_error_raise_exception (&error);
2935         }
2936         return res;
2937 }
2938
2939 /**
2940  * mono_runtime_try_invoke:
2941  * @method: method to invoke
2942  * @obJ: object instance
2943  * @params: arguments to the method
2944  * @exc: exception information.
2945  * @error: set on error
2946  *
2947  * Invokes the method represented by @method on the object @obj.
2948  *
2949  * obj is the 'this' pointer, it should be NULL for static
2950  * methods, a MonoObject* for object instances and a pointer to
2951  * the value type for value types.
2952  *
2953  * The params array contains the arguments to the method with the
2954  * same convention: MonoObject* pointers for object instances and
2955  * pointers to the value type otherwise. 
2956  * 
2957  * From unmanaged code you'll usually use the
2958  * mono_runtime_invoke() variant.
2959  *
2960  * Note that this function doesn't handle virtual methods for
2961  * you, it will exec the exact method you pass: we still need to
2962  * expose a function to lookup the derived class implementation
2963  * of a virtual method (there are examples of this in the code,
2964  * though).
2965  * 
2966  * For this function, you must not pass NULL as the exc argument if
2967  * you don't want to catch exceptions, use
2968  * mono_runtime_invoke_checked().  If an exception is thrown, you
2969  * can't use the MonoObject* result from the function.
2970  * 
2971  * If this method cannot be invoked, @error will be set and @exc and
2972  * the return value must not be used.
2973  *
2974  * If the method returns a value type, it is boxed in an object
2975  * reference.
2976  */
2977 MonoObject*
2978 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2979 {
2980         MONO_REQ_GC_UNSAFE_MODE;
2981
2982         g_assert (exc != NULL);
2983
2984         if (mono_runtime_get_no_exec ())
2985                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2986
2987         return do_runtime_invoke (method, obj, params, exc, error);
2988 }
2989
2990 /**
2991  * mono_runtime_invoke_checked:
2992  * @method: method to invoke
2993  * @obJ: object instance
2994  * @params: arguments to the method
2995  * @error: set on error
2996  *
2997  * Invokes the method represented by @method on the object @obj.
2998  *
2999  * obj is the 'this' pointer, it should be NULL for static
3000  * methods, a MonoObject* for object instances and a pointer to
3001  * the value type for value types.
3002  *
3003  * The params array contains the arguments to the method with the
3004  * same convention: MonoObject* pointers for object instances and
3005  * pointers to the value type otherwise. 
3006  * 
3007  * From unmanaged code you'll usually use the
3008  * mono_runtime_invoke() variant.
3009  *
3010  * Note that this function doesn't handle virtual methods for
3011  * you, it will exec the exact method you pass: we still need to
3012  * expose a function to lookup the derived class implementation
3013  * of a virtual method (there are examples of this in the code,
3014  * though).
3015  * 
3016  * If an exception is thrown, you can't use the MonoObject* result
3017  * from the function.
3018  * 
3019  * If this method cannot be invoked, @error will be set.  If the
3020  * method throws an exception (and we're in coop mode) the exception
3021  * will be set in @error.
3022  *
3023  * If the method returns a value type, it is boxed in an object
3024  * reference.
3025  */
3026 MonoObject*
3027 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3028 {
3029         MONO_REQ_GC_UNSAFE_MODE;
3030
3031         if (mono_runtime_get_no_exec ())
3032                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3033
3034         return do_runtime_invoke (method, obj, params, NULL, error);
3035 }
3036
3037 /**
3038  * mono_method_get_unmanaged_thunk:
3039  * @method: method to generate a thunk for.
3040  *
3041  * Returns an unmanaged->managed thunk that can be used to call
3042  * a managed method directly from C.
3043  *
3044  * The thunk's C signature closely matches the managed signature:
3045  *
3046  * C#: public bool Equals (object obj);
3047  * C:  typedef MonoBoolean (*Equals)(MonoObject*,
3048  *             MonoObject*, MonoException**);
3049  *
3050  * The 1st ("this") parameter must not be used with static methods:
3051  *
3052  * C#: public static bool ReferenceEquals (object a, object b);
3053  * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3054  *             MonoException**);
3055  *
3056  * The last argument must be a non-null pointer of a MonoException* pointer.
3057  * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3058  * exception has been thrown in managed code. Otherwise it will point
3059  * to the MonoException* caught by the thunk. In this case, the result of
3060  * the thunk is undefined:
3061  *
3062  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3063  * MonoException *ex = NULL;
3064  * Equals func = mono_method_get_unmanaged_thunk (method);
3065  * MonoBoolean res = func (thisObj, objToCompare, &ex);
3066  * if (ex) {
3067  *    // handle exception
3068  * }
3069  *
3070  * The calling convention of the thunk matches the platform's default
3071  * convention. This means that under Windows, C declarations must
3072  * contain the __stdcall attribute:
3073  *
3074  * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3075  *             MonoObject*, MonoException**);
3076  *
3077  * LIMITATIONS
3078  *
3079  * Value type arguments and return values are treated as they were objects:
3080  *
3081  * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3082  * C:  typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3083  *
3084  * Arguments must be properly boxed upon trunk's invocation, while return
3085  * values must be unboxed.
3086  */
3087 gpointer
3088 mono_method_get_unmanaged_thunk (MonoMethod *method)
3089 {
3090         MONO_REQ_GC_NEUTRAL_MODE;
3091         MONO_REQ_API_ENTRYPOINT;
3092
3093         gpointer res;
3094
3095         MONO_PREPARE_RESET_BLOCKING;
3096         method = mono_marshal_get_thunk_invoke_wrapper (method);
3097         res = mono_compile_method (method);
3098         MONO_FINISH_RESET_BLOCKING;
3099
3100         return res;
3101 }
3102
3103 void
3104 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3105 {
3106         MONO_REQ_GC_UNSAFE_MODE;
3107
3108         int t;
3109         if (type->byref) {
3110                 /* object fields cannot be byref, so we don't need a
3111                    wbarrier here */
3112                 gpointer *p = (gpointer*)dest;
3113                 *p = value;
3114                 return;
3115         }
3116         t = type->type;
3117 handle_enum:
3118         switch (t) {
3119         case MONO_TYPE_BOOLEAN:
3120         case MONO_TYPE_I1:
3121         case MONO_TYPE_U1: {
3122                 guint8 *p = (guint8*)dest;
3123                 *p = value ? *(guint8*)value : 0;
3124                 return;
3125         }
3126         case MONO_TYPE_I2:
3127         case MONO_TYPE_U2:
3128         case MONO_TYPE_CHAR: {
3129                 guint16 *p = (guint16*)dest;
3130                 *p = value ? *(guint16*)value : 0;
3131                 return;
3132         }
3133 #if SIZEOF_VOID_P == 4
3134         case MONO_TYPE_I:
3135         case MONO_TYPE_U:
3136 #endif
3137         case MONO_TYPE_I4:
3138         case MONO_TYPE_U4: {
3139                 gint32 *p = (gint32*)dest;
3140                 *p = value ? *(gint32*)value : 0;
3141                 return;
3142         }
3143 #if SIZEOF_VOID_P == 8
3144         case MONO_TYPE_I:
3145         case MONO_TYPE_U:
3146 #endif
3147         case MONO_TYPE_I8:
3148         case MONO_TYPE_U8: {
3149                 gint64 *p = (gint64*)dest;
3150                 *p = value ? *(gint64*)value : 0;
3151                 return;
3152         }
3153         case MONO_TYPE_R4: {
3154                 float *p = (float*)dest;
3155                 *p = value ? *(float*)value : 0;
3156                 return;
3157         }
3158         case MONO_TYPE_R8: {
3159                 double *p = (double*)dest;
3160                 *p = value ? *(double*)value : 0;
3161                 return;
3162         }
3163         case MONO_TYPE_STRING:
3164         case MONO_TYPE_SZARRAY:
3165         case MONO_TYPE_CLASS:
3166         case MONO_TYPE_OBJECT:
3167         case MONO_TYPE_ARRAY:
3168                 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3169                 return;
3170         case MONO_TYPE_FNPTR:
3171         case MONO_TYPE_PTR: {
3172                 gpointer *p = (gpointer*)dest;
3173                 *p = deref_pointer? *(gpointer*)value: value;
3174                 return;
3175         }
3176         case MONO_TYPE_VALUETYPE:
3177                 /* note that 't' and 'type->type' can be different */
3178                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3179                         t = mono_class_enum_basetype (type->data.klass)->type;
3180                         goto handle_enum;
3181                 } else {
3182                         MonoClass *klass = mono_class_from_mono_type (type);
3183                         int size = mono_class_value_size (klass, NULL);
3184                         if (value == NULL)
3185                                 mono_gc_bzero_atomic (dest, size);
3186                         else
3187                                 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3188                 }
3189                 return;
3190         case MONO_TYPE_GENERICINST:
3191                 t = type->data.generic_class->container_class->byval_arg.type;
3192                 goto handle_enum;
3193         default:
3194                 g_error ("got type %x", type->type);
3195         }
3196 }
3197
3198 /**
3199  * mono_field_set_value:
3200  * @obj: Instance object
3201  * @field: MonoClassField describing the field to set
3202  * @value: The value to be set
3203  *
3204  * Sets the value of the field described by @field in the object instance @obj
3205  * to the value passed in @value.   This method should only be used for instance
3206  * fields.   For static fields, use mono_field_static_set_value.
3207  *
3208  * The value must be on the native format of the field type. 
3209  */
3210 void
3211 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3212 {
3213         MONO_REQ_GC_UNSAFE_MODE;
3214
3215         void *dest;
3216
3217         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3218
3219         dest = (char*)obj + field->offset;
3220         mono_copy_value (field->type, dest, value, FALSE);
3221 }
3222
3223 /**
3224  * mono_field_static_set_value:
3225  * @field: MonoClassField describing the field to set
3226  * @value: The value to be set
3227  *
3228  * Sets the value of the static field described by @field
3229  * to the value passed in @value.
3230  *
3231  * The value must be on the native format of the field type. 
3232  */
3233 void
3234 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3235 {
3236         MONO_REQ_GC_UNSAFE_MODE;
3237
3238         void *dest;
3239
3240         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3241         /* you cant set a constant! */
3242         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3243
3244         if (field->offset == -1) {
3245                 /* Special static */
3246                 gpointer addr;
3247
3248                 mono_domain_lock (vt->domain);
3249                 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3250                 mono_domain_unlock (vt->domain);
3251                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3252         } else {
3253                 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3254         }
3255         mono_copy_value (field->type, dest, value, FALSE);
3256 }
3257
3258 /**
3259  * mono_vtable_get_static_field_data:
3260  *
3261  * Internal use function: return a pointer to the memory holding the static fields
3262  * for a class or NULL if there are no static fields.
3263  * This is exported only for use by the debugger.
3264  */
3265 void *
3266 mono_vtable_get_static_field_data (MonoVTable *vt)
3267 {
3268         MONO_REQ_GC_NEUTRAL_MODE
3269
3270         if (!vt->has_static_fields)
3271                 return NULL;
3272         return vt->vtable [vt->klass->vtable_size];
3273 }
3274
3275 static guint8*
3276 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3277 {
3278         MONO_REQ_GC_UNSAFE_MODE;
3279
3280         guint8 *src;
3281
3282         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3283                 if (field->offset == -1) {
3284                         /* Special static */
3285                         gpointer addr;
3286
3287                         mono_domain_lock (vt->domain);
3288                         addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3289                         mono_domain_unlock (vt->domain);
3290                         src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3291                 } else {
3292                         src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3293                 }
3294         } else {
3295                 src = (guint8*)obj + field->offset;
3296         }
3297
3298         return src;
3299 }
3300
3301 /**
3302  * mono_field_get_value:
3303  * @obj: Object instance
3304  * @field: MonoClassField describing the field to fetch information from
3305  * @value: pointer to the location where the value will be stored
3306  *
3307  * Use this routine to get the value of the field @field in the object
3308  * passed.
3309  *
3310  * The pointer provided by value must be of the field type, for reference
3311  * types this is a MonoObject*, for value types its the actual pointer to
3312  * the value type.
3313  *
3314  * For example:
3315  *     int i;
3316  *     mono_field_get_value (obj, int_field, &i);
3317  */
3318 void
3319 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3320 {
3321         MONO_REQ_GC_UNSAFE_MODE;
3322
3323         void *src;
3324
3325         g_assert (obj);
3326
3327         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3328
3329         src = (char*)obj + field->offset;
3330         mono_copy_value (field->type, value, src, TRUE);
3331 }
3332
3333 /**
3334  * mono_field_get_value_object:
3335  * @domain: domain where the object will be created (if boxing)
3336  * @field: MonoClassField describing the field to fetch information from
3337  * @obj: The object instance for the field.
3338  *
3339  * Returns: a new MonoObject with the value from the given field.  If the
3340  * field represents a value type, the value is boxed.
3341  *
3342  */
3343 MonoObject *
3344 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3345 {       
3346         MONO_REQ_GC_UNSAFE_MODE;
3347
3348         MonoError error;
3349         MonoObject *o;
3350         MonoClass *klass;
3351         MonoVTable *vtable = NULL;
3352         gchar *v;
3353         gboolean is_static = FALSE;
3354         gboolean is_ref = FALSE;
3355         gboolean is_literal = FALSE;
3356         gboolean is_ptr = FALSE;
3357         MonoType *type = mono_field_get_type_checked (field, &error);
3358
3359         if (!mono_error_ok (&error))
3360                 mono_error_raise_exception (&error);  /* FIXME don't raise here */
3361
3362         switch (type->type) {
3363         case MONO_TYPE_STRING:
3364         case MONO_TYPE_OBJECT:
3365         case MONO_TYPE_CLASS:
3366         case MONO_TYPE_ARRAY:
3367         case MONO_TYPE_SZARRAY:
3368                 is_ref = TRUE;
3369                 break;
3370         case MONO_TYPE_U1:
3371         case MONO_TYPE_I1:
3372         case MONO_TYPE_BOOLEAN:
3373         case MONO_TYPE_U2:
3374         case MONO_TYPE_I2:
3375         case MONO_TYPE_CHAR:
3376         case MONO_TYPE_U:
3377         case MONO_TYPE_I:
3378         case MONO_TYPE_U4:
3379         case MONO_TYPE_I4:
3380         case MONO_TYPE_R4:
3381         case MONO_TYPE_U8:
3382         case MONO_TYPE_I8:
3383         case MONO_TYPE_R8:
3384         case MONO_TYPE_VALUETYPE:
3385                 is_ref = type->byref;
3386                 break;
3387         case MONO_TYPE_GENERICINST:
3388                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3389                 break;
3390         case MONO_TYPE_PTR:
3391                 is_ptr = TRUE;
3392                 break;
3393         default:
3394                 g_error ("type 0x%x not handled in "
3395                          "mono_field_get_value_object", type->type);
3396                 return NULL;
3397         }
3398
3399         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3400                 is_literal = TRUE;
3401
3402         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3403                 is_static = TRUE;
3404
3405                 if (!is_literal) {
3406                         vtable = mono_class_vtable_full (domain, field->parent, &error);
3407                         mono_error_raise_exception (&error);  /* FIXME don't raise here */
3408
3409                         if (!vtable->initialized) {
3410                                 mono_runtime_class_init_full (vtable, &error);
3411                                 mono_error_raise_exception (&error);  /* FIXME don't raise here */
3412                         }
3413                 }
3414         } else {
3415                 g_assert (obj);
3416         }
3417         
3418         if (is_ref) {
3419                 if (is_literal) {
3420                         get_default_field_value (domain, field, &o);
3421                 } else if (is_static) {
3422                         mono_field_static_get_value (vtable, field, &o);
3423                 } else {
3424                         mono_field_get_value (obj, field, &o);
3425                 }
3426                 return o;
3427         }
3428
3429         if (is_ptr) {
3430                 static MonoMethod *m;
3431                 gpointer args [2];
3432                 gpointer *ptr;
3433                 gpointer v;
3434
3435                 if (!m) {
3436                         MonoClass *ptr_klass = mono_class_get_pointer_class ();
3437                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3438                         g_assert (m);
3439                 }
3440
3441                 v = &ptr;
3442                 if (is_literal) {
3443                         get_default_field_value (domain, field, v);
3444                 } else if (is_static) {
3445                         mono_field_static_get_value (vtable, field, v);
3446                 } else {
3447                         mono_field_get_value (obj, field, v);
3448                 }
3449
3450                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3451                 args [0] = ptr ? *ptr : NULL;
3452                 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3453                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3454
3455                 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3456                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3457
3458                 return o;
3459         }
3460
3461         /* boxed value type */
3462         klass = mono_class_from_mono_type (type);
3463
3464         if (mono_class_is_nullable (klass))
3465                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3466
3467         o = mono_object_new_checked (domain, klass, &error);
3468         mono_error_raise_exception (&error); /* FIXME don't raise here */
3469         v = ((gchar *) o) + sizeof (MonoObject);
3470
3471         if (is_literal) {
3472                 get_default_field_value (domain, field, v);
3473         } else if (is_static) {
3474                 mono_field_static_get_value (vtable, field, v);
3475         } else {
3476                 mono_field_get_value (obj, field, v);
3477         }
3478
3479         return o;
3480 }
3481
3482 int
3483 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3484 {
3485         MONO_REQ_GC_UNSAFE_MODE;
3486
3487         int retval = 0;
3488         const char *p = blob;
3489         mono_metadata_decode_blob_size (p, &p);
3490
3491         switch (type) {
3492         case MONO_TYPE_BOOLEAN:
3493         case MONO_TYPE_U1:
3494         case MONO_TYPE_I1:
3495                 *(guint8 *) value = *p;
3496                 break;
3497         case MONO_TYPE_CHAR:
3498         case MONO_TYPE_U2:
3499         case MONO_TYPE_I2:
3500                 *(guint16*) value = read16 (p);
3501                 break;
3502         case MONO_TYPE_U4:
3503         case MONO_TYPE_I4:
3504                 *(guint32*) value = read32 (p);
3505                 break;
3506         case MONO_TYPE_U8:
3507         case MONO_TYPE_I8:
3508                 *(guint64*) value = read64 (p);
3509                 break;
3510         case MONO_TYPE_R4:
3511                 readr4 (p, (float*) value);
3512                 break;
3513         case MONO_TYPE_R8:
3514                 readr8 (p, (double*) value);
3515                 break;
3516         case MONO_TYPE_STRING:
3517                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3518                 break;
3519         case MONO_TYPE_CLASS:
3520                 *(gpointer*) value = NULL;
3521                 break;
3522         default:
3523                 retval = -1;
3524                 g_warning ("type 0x%02x should not be in constant table", type);
3525         }
3526         return retval;
3527 }
3528
3529 static void
3530 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3531 {
3532         MONO_REQ_GC_NEUTRAL_MODE;
3533
3534         MonoTypeEnum def_type;
3535         const char* data;
3536         
3537         data = mono_class_get_field_default_value (field, &def_type);
3538         mono_get_constant_value_from_blob (domain, def_type, data, value);
3539 }
3540
3541 void
3542 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3543 {
3544         MONO_REQ_GC_UNSAFE_MODE;
3545
3546         void *src;
3547
3548         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3549         
3550         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3551                 get_default_field_value (vt->domain, field, value);
3552                 return;
3553         }
3554
3555         if (field->offset == -1) {
3556                 /* Special static */
3557                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3558                 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3559         } else {
3560                 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3561         }
3562         mono_copy_value (field->type, value, src, TRUE);
3563 }
3564
3565 /**
3566  * mono_field_static_get_value:
3567  * @vt: vtable to the object
3568  * @field: MonoClassField describing the field to fetch information from
3569  * @value: where the value is returned
3570  *
3571  * Use this routine to get the value of the static field @field value.
3572  *
3573  * The pointer provided by value must be of the field type, for reference
3574  * types this is a MonoObject*, for value types its the actual pointer to
3575  * the value type.
3576  *
3577  * For example:
3578  *     int i;
3579  *     mono_field_static_get_value (vt, int_field, &i);
3580  */
3581 void
3582 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3583 {
3584         MONO_REQ_GC_NEUTRAL_MODE;
3585
3586         mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3587 }
3588
3589 /**
3590  * mono_property_set_value:
3591  * @prop: MonoProperty to set
3592  * @obj: instance object on which to act
3593  * @params: parameters to pass to the propery
3594  * @exc: optional exception
3595  *
3596  * Invokes the property's set method with the given arguments on the
3597  * object instance obj (or NULL for static properties). 
3598  * 
3599  * You can pass NULL as the exc argument if you don't want to
3600  * catch exceptions, otherwise, *exc will be set to the exception
3601  * thrown, if any.  if an exception is thrown, you can't use the
3602  * MonoObject* result from the function.
3603  */
3604 void
3605 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3606 {
3607         MONO_REQ_GC_UNSAFE_MODE;
3608
3609         MonoError error;
3610         do_runtime_invoke (prop->set, obj, params, exc, &error);
3611         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3612                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3613         } else {
3614                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3615         }
3616 }
3617
3618 /**
3619  * mono_property_get_value:
3620  * @prop: MonoProperty to fetch
3621  * @obj: instance object on which to act
3622  * @params: parameters to pass to the propery
3623  * @exc: optional exception
3624  *
3625  * Invokes the property's get method with the given arguments on the
3626  * object instance obj (or NULL for static properties). 
3627  * 
3628  * You can pass NULL as the exc argument if you don't want to
3629  * catch exceptions, otherwise, *exc will be set to the exception
3630  * thrown, if any.  if an exception is thrown, you can't use the
3631  * MonoObject* result from the function.
3632  *
3633  * Returns: the value from invoking the get method on the property.
3634  */
3635 MonoObject*
3636 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3637 {
3638         MONO_REQ_GC_UNSAFE_MODE;
3639
3640         MonoError error;
3641         MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3642         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3643                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3644         } else {
3645                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3646         }
3647
3648         return val;
3649 }
3650
3651 /*
3652  * mono_nullable_init:
3653  * @buf: The nullable structure to initialize.
3654  * @value: the value to initialize from
3655  * @klass: the type for the object
3656  *
3657  * Initialize the nullable structure pointed to by @buf from @value which
3658  * should be a boxed value type.   The size of @buf should be able to hold
3659  * as much data as the @klass->instance_size (which is the number of bytes
3660  * that will be copies).
3661  *
3662  * Since Nullables have variable structure, we can not define a C
3663  * structure for them.
3664  */
3665 void
3666 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3667 {
3668         MONO_REQ_GC_UNSAFE_MODE;
3669
3670         MonoClass *param_class = klass->cast_class;
3671
3672         mono_class_setup_fields_locking (klass);
3673         g_assert (klass->fields_inited);
3674                                 
3675         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3676         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3677
3678         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3679         if (value) {
3680                 if (param_class->has_references)
3681                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3682                 else
3683                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3684         } else {
3685                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3686         }
3687 }
3688
3689 /**
3690  * mono_nullable_box:
3691  * @buf: The buffer representing the data to be boxed
3692  * @klass: the type to box it as.
3693  *
3694  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3695  * @buf.
3696  */
3697 MonoObject*
3698 mono_nullable_box (guint8 *buf, MonoClass *klass)
3699 {
3700         MONO_REQ_GC_UNSAFE_MODE;
3701
3702         MonoError error;
3703         
3704         MonoClass *param_class = klass->cast_class;
3705
3706         mono_class_setup_fields_locking (klass);
3707         g_assert (klass->fields_inited);
3708
3709         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3710         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3711
3712         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3713                 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3714                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3715                 if (param_class->has_references)
3716                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3717                 else
3718                         mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3719                 return o;
3720         }
3721         else
3722                 return NULL;
3723 }
3724
3725 /**
3726  * mono_get_delegate_invoke:
3727  * @klass: The delegate class
3728  *
3729  * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3730  */
3731 MonoMethod *
3732 mono_get_delegate_invoke (MonoClass *klass)
3733 {
3734         MONO_REQ_GC_NEUTRAL_MODE;
3735
3736         MonoMethod *im;
3737
3738         /* This is called at runtime, so avoid the slower search in metadata */
3739         mono_class_setup_methods (klass);
3740         if (mono_class_has_failure (klass))
3741                 return NULL;
3742         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3743         return im;
3744 }
3745
3746 /**
3747  * mono_get_delegate_begin_invoke:
3748  * @klass: The delegate class
3749  *
3750  * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3751  */
3752 MonoMethod *
3753 mono_get_delegate_begin_invoke (MonoClass *klass)
3754 {
3755         MONO_REQ_GC_NEUTRAL_MODE;
3756
3757         MonoMethod *im;
3758
3759         /* This is called at runtime, so avoid the slower search in metadata */
3760         mono_class_setup_methods (klass);
3761         if (mono_class_has_failure (klass))
3762                 return NULL;
3763         im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3764         return im;
3765 }
3766
3767 /**
3768  * mono_get_delegate_end_invoke:
3769  * @klass: The delegate class
3770  *
3771  * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3772  */
3773 MonoMethod *
3774 mono_get_delegate_end_invoke (MonoClass *klass)
3775 {
3776         MONO_REQ_GC_NEUTRAL_MODE;
3777
3778         MonoMethod *im;
3779
3780         /* This is called at runtime, so avoid the slower search in metadata */
3781         mono_class_setup_methods (klass);
3782         if (mono_class_has_failure (klass))
3783                 return NULL;
3784         im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3785         return im;
3786 }
3787
3788 /**
3789  * mono_runtime_delegate_invoke:
3790  * @delegate: pointer to a delegate object.
3791  * @params: parameters for the delegate.
3792  * @exc: Pointer to the exception result.
3793  *
3794  * Invokes the delegate method @delegate with the parameters provided.
3795  *
3796  * You can pass NULL as the exc argument if you don't want to
3797  * catch exceptions, otherwise, *exc will be set to the exception
3798  * thrown, if any.  if an exception is thrown, you can't use the
3799  * MonoObject* result from the function.
3800  */
3801 MonoObject*
3802 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3803 {
3804         MONO_REQ_GC_UNSAFE_MODE;
3805
3806         MonoError error;
3807         MonoMethod *im;
3808         MonoClass *klass = delegate->vtable->klass;
3809         MonoObject *o;
3810
3811         im = mono_get_delegate_invoke (klass);
3812         if (!im)
3813                 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3814
3815         if (exc) {
3816                 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3817                 if (*exc == NULL && !mono_error_ok (&error))
3818                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3819                 else
3820                         mono_error_cleanup (&error);
3821         } else {
3822                 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3823                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3824         }
3825
3826         return o;
3827 }
3828
3829 static char **main_args = NULL;
3830 static int num_main_args = 0;
3831
3832 /**
3833  * mono_runtime_get_main_args:
3834  *
3835  * Returns: a MonoArray with the arguments passed to the main program
3836  */
3837 MonoArray*
3838 mono_runtime_get_main_args (void)
3839 {
3840         MONO_REQ_GC_UNSAFE_MODE;
3841
3842         MonoArray *res;
3843         int i;
3844         MonoDomain *domain = mono_domain_get ();
3845
3846         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3847
3848         for (i = 0; i < num_main_args; ++i)
3849                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3850
3851         return res;
3852 }
3853
3854 static void
3855 free_main_args (void)
3856 {
3857         MONO_REQ_GC_NEUTRAL_MODE;
3858
3859         int i;
3860
3861         for (i = 0; i < num_main_args; ++i)
3862                 g_free (main_args [i]);
3863         g_free (main_args);
3864         num_main_args = 0;
3865         main_args = NULL;
3866 }
3867
3868 /**
3869  * mono_runtime_set_main_args:
3870  * @argc: number of arguments from the command line
3871  * @argv: array of strings from the command line
3872  *
3873  * Set the command line arguments from an embedding application that doesn't otherwise call
3874  * mono_runtime_run_main ().
3875  */
3876 int
3877 mono_runtime_set_main_args (int argc, char* argv[])
3878 {
3879         MONO_REQ_GC_NEUTRAL_MODE;
3880
3881         int i;
3882
3883         free_main_args ();
3884         main_args = g_new0 (char*, argc);
3885         num_main_args = argc;
3886
3887         for (i = 0; i < argc; ++i) {
3888                 gchar *utf8_arg;
3889
3890                 utf8_arg = mono_utf8_from_external (argv[i]);
3891                 if (utf8_arg == NULL) {
3892                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3893                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3894                         exit (-1);
3895                 }
3896
3897                 main_args [i] = utf8_arg;
3898         }
3899
3900         return 0;
3901 }
3902
3903 /**
3904  * mono_runtime_run_main:
3905  * @method: the method to start the application with (usually Main)
3906  * @argc: number of arguments from the command line
3907  * @argv: array of strings from the command line
3908  * @exc: excetption results
3909  *
3910  * Execute a standard Main() method (argc/argv contains the
3911  * executable name). This method also sets the command line argument value
3912  * needed by System.Environment.
3913  *
3914  * 
3915  */
3916 int
3917 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3918                        MonoObject **exc)
3919 {
3920         MONO_REQ_GC_UNSAFE_MODE;
3921
3922         int i;
3923         MonoArray *args = NULL;
3924         MonoDomain *domain = mono_domain_get ();
3925         gchar *utf8_fullpath;
3926         MonoMethodSignature *sig;
3927
3928         g_assert (method != NULL);
3929         
3930         mono_thread_set_main (mono_thread_current ());
3931
3932         main_args = g_new0 (char*, argc);
3933         num_main_args = argc;
3934
3935         if (!g_path_is_absolute (argv [0])) {
3936                 gchar *basename = g_path_get_basename (argv [0]);
3937                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3938                                                     basename,
3939                                                     NULL);
3940
3941                 utf8_fullpath = mono_utf8_from_external (fullpath);
3942                 if(utf8_fullpath == NULL) {
3943                         /* Printing the arg text will cause glib to
3944                          * whinge about "Invalid UTF-8", but at least
3945                          * its relevant, and shows the problem text
3946                          * string.
3947                          */
3948                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3949                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3950                         exit (-1);
3951                 }
3952
3953                 g_free (fullpath);
3954                 g_free (basename);
3955         } else {
3956                 utf8_fullpath = mono_utf8_from_external (argv[0]);
3957                 if(utf8_fullpath == NULL) {
3958                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3959                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3960                         exit (-1);
3961                 }
3962         }
3963
3964         main_args [0] = utf8_fullpath;
3965
3966         for (i = 1; i < argc; ++i) {
3967                 gchar *utf8_arg;
3968
3969                 utf8_arg=mono_utf8_from_external (argv[i]);
3970                 if(utf8_arg==NULL) {
3971                         /* Ditto the comment about Invalid UTF-8 here */
3972                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3973                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3974                         exit (-1);
3975                 }
3976
3977                 main_args [i] = utf8_arg;
3978         }
3979         argc--;
3980         argv++;
3981
3982         sig = mono_method_signature (method);
3983         if (!sig) {
3984                 g_print ("Unable to load Main method.\n");
3985                 exit (-1);
3986         }
3987
3988         if (sig->param_count) {
3989                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3990                 for (i = 0; i < argc; ++i) {
3991                         /* The encodings should all work, given that
3992                          * we've checked all these args for the
3993                          * main_args array.
3994                          */
3995                         gchar *str = mono_utf8_from_external (argv [i]);
3996                         MonoString *arg = mono_string_new (domain, str);
3997                         mono_array_setref (args, i, arg);
3998                         g_free (str);
3999                 }
4000         } else {
4001                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4002         }
4003         
4004         mono_assembly_set_main (method->klass->image->assembly);
4005
4006         return mono_runtime_exec_main (method, args, exc);
4007 }
4008
4009 static MonoObject*
4010 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4011 {
4012         static MonoMethod *serialize_method;
4013
4014         MonoError error;
4015         void *params [1];
4016         MonoObject *array;
4017
4018         if (!serialize_method) {
4019                 MonoClass *klass = mono_class_get_remoting_services_class ();
4020                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4021         }
4022
4023         if (!serialize_method) {
4024                 *failure = TRUE;
4025                 return NULL;
4026         }
4027
4028         g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4029
4030         params [0] = obj;
4031         *exc = NULL;
4032
4033         array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4034         if (*exc == NULL && !mono_error_ok (&error))
4035                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4036         else
4037                 mono_error_cleanup (&error);
4038
4039         if (*exc)
4040                 *failure = TRUE;
4041
4042         return array;
4043 }
4044
4045 static MonoObject*
4046 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4047 {
4048         MONO_REQ_GC_UNSAFE_MODE;
4049
4050         static MonoMethod *deserialize_method;
4051
4052         MonoError error;
4053         void *params [1];
4054         MonoObject *result;
4055
4056         if (!deserialize_method) {
4057                 MonoClass *klass = mono_class_get_remoting_services_class ();
4058                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4059         }
4060         if (!deserialize_method) {
4061                 *failure = TRUE;
4062                 return NULL;
4063         }
4064
4065         params [0] = obj;
4066         *exc = NULL;
4067
4068         result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4069         if (*exc == NULL && !mono_error_ok (&error))
4070                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4071         else
4072                 mono_error_cleanup (&error);
4073
4074         if (*exc)
4075                 *failure = TRUE;
4076
4077         return result;
4078 }
4079
4080 #ifndef DISABLE_REMOTING
4081 static MonoObject*
4082 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4083 {
4084         MONO_REQ_GC_UNSAFE_MODE;
4085
4086         static MonoMethod *get_proxy_method;
4087
4088         MonoError error;
4089         MonoDomain *domain = mono_domain_get ();
4090         MonoRealProxy *real_proxy;
4091         MonoReflectionType *reflection_type;
4092         MonoTransparentProxy *transparent_proxy;
4093
4094         if (!get_proxy_method)
4095                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4096
4097         g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4098
4099         real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4100         mono_error_raise_exception (&error); /* FIXME don't raise here */
4101         reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4102         mono_error_raise_exception (&error); /* FIXME don't raise here */
4103
4104         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4105         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4106
4107         *exc = NULL;
4108
4109         transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4110         if (*exc == NULL && !mono_error_ok (&error))
4111                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4112         else
4113                 mono_error_cleanup (&error);
4114         if (*exc)
4115                 *failure = TRUE;
4116
4117         return (MonoObject*) transparent_proxy;
4118 }
4119 #endif /* DISABLE_REMOTING */
4120
4121 /**
4122  * mono_object_xdomain_representation
4123  * @obj: an object
4124  * @target_domain: a domain
4125  * @exc: pointer to a MonoObject*
4126  *
4127  * Creates a representation of obj in the domain target_domain.  This
4128  * is either a copy of obj arrived through via serialization and
4129  * deserialization or a proxy, depending on whether the object is
4130  * serializable or marshal by ref.  obj must not be in target_domain.
4131  *
4132  * If the object cannot be represented in target_domain, NULL is
4133  * returned and *exc is set to an appropriate exception.
4134  */
4135 MonoObject*
4136 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4137 {
4138         MONO_REQ_GC_UNSAFE_MODE;
4139
4140         MonoObject *deserialized = NULL;
4141         gboolean failure = FALSE;
4142
4143         g_assert (exc != NULL);
4144         *exc = NULL;
4145
4146 #ifndef DISABLE_REMOTING
4147         if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4148                 deserialized = make_transparent_proxy (obj, &failure, exc);
4149         } 
4150         else
4151 #endif
4152         {
4153                 MonoDomain *domain = mono_domain_get ();
4154                 MonoObject *serialized;
4155
4156                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4157                 serialized = serialize_object (obj, &failure, exc);
4158                 mono_domain_set_internal_with_options (target_domain, FALSE);
4159                 if (!failure)
4160                         deserialized = deserialize_object (serialized, &failure, exc);
4161                 if (domain != target_domain)
4162                         mono_domain_set_internal_with_options (domain, FALSE);
4163         }
4164
4165         return deserialized;
4166 }
4167
4168 /* Used in call_unhandled_exception_delegate */
4169 static MonoObject *
4170 create_unhandled_exception_eventargs (MonoObject *exc)
4171 {
4172         MONO_REQ_GC_UNSAFE_MODE;
4173
4174         MonoError error;
4175         MonoClass *klass;
4176         gpointer args [2];
4177         MonoMethod *method = NULL;
4178         MonoBoolean is_terminating = TRUE;
4179         MonoObject *obj;
4180
4181         klass = mono_class_get_unhandled_exception_event_args_class ();
4182         mono_class_init (klass);
4183
4184         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4185         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4186         g_assert (method);
4187
4188         args [0] = exc;
4189         args [1] = &is_terminating;
4190
4191         obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4192         mono_error_raise_exception (&error); /* FIXME don't raise here */
4193
4194         mono_runtime_invoke_checked (method, obj, args, &error);
4195         mono_error_raise_exception (&error); /* FIXME don't raise here */
4196
4197         return obj;
4198 }
4199
4200 /* Used in mono_unhandled_exception */
4201 static void
4202 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4203         MONO_REQ_GC_UNSAFE_MODE;
4204
4205         MonoObject *e = NULL;
4206         gpointer pa [2];
4207         MonoDomain *current_domain = mono_domain_get ();
4208
4209         if (domain != current_domain)
4210                 mono_domain_set_internal_with_options (domain, FALSE);
4211
4212         g_assert (domain == mono_object_domain (domain->domain));
4213
4214         if (mono_object_domain (exc) != domain) {
4215                 MonoObject *serialization_exc;
4216
4217                 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4218                 if (!exc) {
4219                         if (serialization_exc) {
4220                                 MonoObject *dummy;
4221                                 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4222                                 g_assert (exc);
4223                         } else {
4224                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4225                                                 "System.Runtime.Serialization", "SerializationException",
4226                                                 "Could not serialize unhandled exception.");
4227                         }
4228                 }
4229         }
4230         g_assert (mono_object_domain (exc) == domain);
4231
4232         pa [0] = domain->domain;
4233         pa [1] = create_unhandled_exception_eventargs (exc);
4234         mono_runtime_delegate_invoke (delegate, pa, &e);
4235
4236         if (domain != current_domain)
4237                 mono_domain_set_internal_with_options (current_domain, FALSE);
4238
4239         if (e) {
4240                 MonoError error;
4241                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4242                 if (!mono_error_ok (&error)) {
4243                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4244                         mono_error_cleanup (&error);
4245                 } else {
4246                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
4247                         g_free (msg);
4248                 }
4249         }
4250 }
4251
4252 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4253
4254 /**
4255  * mono_runtime_unhandled_exception_policy_set:
4256  * @policy: the new policy
4257  * 
4258  * This is a VM internal routine.
4259  *
4260  * Sets the runtime policy for handling unhandled exceptions.
4261  */
4262 void
4263 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4264         runtime_unhandled_exception_policy = policy;
4265 }
4266
4267 /**
4268  * mono_runtime_unhandled_exception_policy_get:
4269  *
4270  * This is a VM internal routine.
4271  *
4272  * Gets the runtime policy for handling unhandled exceptions.
4273  */
4274 MonoRuntimeUnhandledExceptionPolicy
4275 mono_runtime_unhandled_exception_policy_get (void) {
4276         return runtime_unhandled_exception_policy;
4277 }
4278
4279 /**
4280  * mono_unhandled_exception:
4281  * @exc: exception thrown
4282  *
4283  * This is a VM internal routine.
4284  *
4285  * We call this function when we detect an unhandled exception
4286  * in the default domain.
4287  *
4288  * It invokes the * UnhandledException event in AppDomain or prints
4289  * a warning to the console 
4290  */
4291 void
4292 mono_unhandled_exception (MonoObject *exc)
4293 {
4294         MONO_REQ_GC_UNSAFE_MODE;
4295
4296         MonoClassField *field;
4297         MonoDomain *current_domain, *root_domain;
4298         MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4299
4300         if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4301                 return;
4302
4303         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4304         g_assert (field);
4305
4306         current_domain = mono_domain_get ();
4307         root_domain = mono_get_root_domain ();
4308
4309         root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4310         if (current_domain != root_domain)
4311                 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4312
4313         /* set exitcode only if we will abort the process */
4314         if (!current_appdomain_delegate && !root_appdomain_delegate) {
4315                 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4316                      || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4317                 {
4318                         mono_environment_exitcode_set (1);
4319                 }
4320
4321                 mono_print_unhandled_exception (exc);
4322         } else {
4323                 if (root_appdomain_delegate)
4324                         call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4325                 if (current_appdomain_delegate)
4326                         call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4327         }
4328 }
4329
4330 /**
4331  * mono_runtime_exec_managed_code:
4332  * @domain: Application domain
4333  * @main_func: function to invoke from the execution thread
4334  * @main_args: parameter to the main_func
4335  *
4336  * Launch a new thread to execute a function
4337  *
4338  * main_func is called back from the thread with main_args as the
4339  * parameter.  The callback function is expected to start Main()
4340  * eventually.  This function then waits for all managed threads to
4341  * finish.
4342  * It is not necesseray anymore to execute managed code in a subthread,
4343  * so this function should not be used anymore by default: just
4344  * execute the code and then call mono_thread_manage ().
4345  */
4346 void
4347 mono_runtime_exec_managed_code (MonoDomain *domain,
4348                                 MonoMainThreadFunc main_func,
4349                                 gpointer main_args)
4350 {
4351         mono_thread_create (domain, main_func, main_args);
4352
4353         mono_thread_manage ();
4354 }
4355
4356 /*
4357  * Execute a standard Main() method (args doesn't contain the
4358  * executable name).
4359  */
4360 int
4361 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4362 {
4363         MONO_REQ_GC_UNSAFE_MODE;
4364
4365         MonoError error;
4366         MonoDomain *domain;
4367         gpointer pa [1];
4368         int rval;
4369         MonoCustomAttrInfo* cinfo;
4370         gboolean has_stathread_attribute;
4371         MonoInternalThread* thread = mono_thread_internal_current ();
4372
4373         g_assert (args);
4374
4375         pa [0] = args;
4376
4377         domain = mono_object_domain (args);
4378         if (!domain->entry_assembly) {
4379                 gchar *str;
4380                 MonoAssembly *assembly;
4381
4382                 assembly = method->klass->image->assembly;
4383                 domain->entry_assembly = assembly;
4384                 /* Domains created from another domain already have application_base and configuration_file set */
4385                 if (domain->setup->application_base == NULL) {
4386                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4387                 }
4388
4389                 if (domain->setup->configuration_file == NULL) {
4390                         str = g_strconcat (assembly->image->name, ".config", NULL);
4391                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4392                         g_free (str);
4393                         mono_domain_set_options_from_config (domain);
4394                 }
4395         }
4396
4397         cinfo = mono_custom_attrs_from_method (method);
4398         if (cinfo) {
4399                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4400                 if (!cinfo->cached)
4401                         mono_custom_attrs_free (cinfo);
4402         } else {
4403                 has_stathread_attribute = FALSE;
4404         }
4405         if (has_stathread_attribute) {
4406                 thread->apartment_state = ThreadApartmentState_STA;
4407         } else {
4408                 thread->apartment_state = ThreadApartmentState_MTA;
4409         }
4410         mono_thread_init_apartment_state ();
4411
4412         /* FIXME: check signature of method */
4413         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4414                 MonoObject *res;
4415                 if (exc) {
4416                         res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4417                         if (*exc == NULL && !mono_error_ok (&error))
4418                                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4419                         else
4420                                 mono_error_cleanup (&error);
4421                 } else {
4422                         res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4423                         mono_error_raise_exception (&error); /* FIXME don't raise here */
4424                 }
4425
4426                 if (!exc || !*exc)
4427                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4428                 else
4429                         rval = -1;
4430
4431                 mono_environment_exitcode_set (rval);
4432         } else {
4433                 if (exc) {
4434                         mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4435                         if (*exc == NULL && !mono_error_ok (&error))
4436                                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4437                         else
4438                                 mono_error_cleanup (&error);
4439                 } else {
4440                         mono_runtime_invoke_checked (method, NULL, pa, &error);
4441                         mono_error_raise_exception (&error); /* FIXME don't raise here */
4442                 }
4443
4444                 if (!exc || !*exc)
4445                         rval = 0;
4446                 else {
4447                         /* If the return type of Main is void, only
4448                          * set the exitcode if an exception was thrown
4449                          * (we don't want to blow away an
4450                          * explicitly-set exit code)
4451                          */
4452                         rval = -1;
4453                         mono_environment_exitcode_set (rval);
4454                 }
4455         }
4456
4457         return rval;
4458 }
4459
4460 /**
4461  * mono_runtime_invoke_array:
4462  * @method: method to invoke
4463  * @obJ: object instance
4464  * @params: arguments to the method
4465  * @exc: exception information.
4466  *
4467  * Invokes the method represented by @method on the object @obj.
4468  *
4469  * obj is the 'this' pointer, it should be NULL for static
4470  * methods, a MonoObject* for object instances and a pointer to
4471  * the value type for value types.
4472  *
4473  * The params array contains the arguments to the method with the
4474  * same convention: MonoObject* pointers for object instances and
4475  * pointers to the value type otherwise. The _invoke_array
4476  * variant takes a C# object[] as the params argument (MonoArray
4477  * *params): in this case the value types are boxed inside the
4478  * respective reference representation.
4479  * 
4480  * From unmanaged code you'll usually use the
4481  * mono_runtime_invoke_checked() variant.
4482  *
4483  * Note that this function doesn't handle virtual methods for
4484  * you, it will exec the exact method you pass: we still need to
4485  * expose a function to lookup the derived class implementation
4486  * of a virtual method (there are examples of this in the code,
4487  * though).
4488  * 
4489  * You can pass NULL as the exc argument if you don't want to
4490  * catch exceptions, otherwise, *exc will be set to the exception
4491  * thrown, if any.  if an exception is thrown, you can't use the
4492  * MonoObject* result from the function.
4493  * 
4494  * If the method returns a value type, it is boxed in an object
4495  * reference.
4496  */
4497 MonoObject*
4498 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4499                            MonoObject **exc)
4500 {
4501         MONO_REQ_GC_UNSAFE_MODE;
4502
4503         MonoError error;
4504         MonoMethodSignature *sig = mono_method_signature (method);
4505         gpointer *pa = NULL;
4506         MonoObject *res;
4507         int i;
4508         gboolean has_byref_nullables = FALSE;
4509
4510         if (NULL != params) {
4511                 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4512                 for (i = 0; i < mono_array_length (params); i++) {
4513                         MonoType *t = sig->params [i];
4514
4515                 again:
4516                         switch (t->type) {
4517                         case MONO_TYPE_U1:
4518                         case MONO_TYPE_I1:
4519                         case MONO_TYPE_BOOLEAN:
4520                         case MONO_TYPE_U2:
4521                         case MONO_TYPE_I2:
4522                         case MONO_TYPE_CHAR:
4523                         case MONO_TYPE_U:
4524                         case MONO_TYPE_I:
4525                         case MONO_TYPE_U4:
4526                         case MONO_TYPE_I4:
4527                         case MONO_TYPE_U8:
4528                         case MONO_TYPE_I8:
4529                         case MONO_TYPE_R4:
4530                         case MONO_TYPE_R8:
4531                         case MONO_TYPE_VALUETYPE:
4532                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4533                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4534                                         pa [i] = mono_array_get (params, MonoObject*, i);
4535                                         if (t->byref)
4536                                                 has_byref_nullables = TRUE;
4537                                 } else {
4538                                         /* MS seems to create the objects if a null is passed in */
4539                                         if (!mono_array_get (params, MonoObject*, i)) {
4540                                                 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4541                                                 mono_error_raise_exception (&error); /* FIXME don't raise here */
4542                                                 mono_array_setref (params, i, o); 
4543                                         }
4544
4545                                         if (t->byref) {
4546                                                 /*
4547                                                  * We can't pass the unboxed vtype byref to the callee, since
4548                                                  * that would mean the callee would be able to modify boxed
4549                                                  * primitive types. So we (and MS) make a copy of the boxed
4550                                                  * object, pass that to the callee, and replace the original
4551                                                  * boxed object in the arg array with the copy.
4552                                                  */
4553                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4554                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4555                                                 mono_array_setref (params, i, copy);
4556                                         }
4557                                                 
4558                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4559                                 }
4560                                 break;
4561                         case MONO_TYPE_STRING:
4562                         case MONO_TYPE_OBJECT:
4563                         case MONO_TYPE_CLASS:
4564                         case MONO_TYPE_ARRAY:
4565                         case MONO_TYPE_SZARRAY:
4566                                 if (t->byref)
4567                                         pa [i] = mono_array_addr (params, MonoObject*, i);
4568                                         // FIXME: I need to check this code path
4569                                 else
4570                                         pa [i] = mono_array_get (params, MonoObject*, i);
4571                                 break;
4572                         case MONO_TYPE_GENERICINST:
4573                                 if (t->byref)
4574                                         t = &t->data.generic_class->container_class->this_arg;
4575                                 else
4576                                         t = &t->data.generic_class->container_class->byval_arg;
4577                                 goto again;
4578                         case MONO_TYPE_PTR: {
4579                                 MonoObject *arg;
4580
4581                                 /* The argument should be an IntPtr */
4582                                 arg = mono_array_get (params, MonoObject*, i);
4583                                 if (arg == NULL) {
4584                                         pa [i] = NULL;
4585                                 } else {
4586                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4587                                         pa [i] = ((MonoIntPtr*)arg)->m_value;
4588                                 }
4589                                 break;
4590                         }
4591                         default:
4592                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4593                         }
4594                 }
4595         }
4596
4597         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4598                 void *o = obj;
4599
4600                 if (mono_class_is_nullable (method->klass)) {
4601                         /* Need to create a boxed vtype instead */
4602                         g_assert (!obj);
4603
4604                         if (!params)
4605                                 return NULL;
4606                         else
4607                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4608                 }
4609
4610                 if (!obj) {
4611                         obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4612                         g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4613 #ifndef DISABLE_REMOTING
4614                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4615                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4616                         }
4617 #endif
4618                         if (method->klass->valuetype)
4619                                 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4620                         else
4621                                 o = obj;
4622                 } else if (method->klass->valuetype) {
4623                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
4624                 }
4625
4626                 if (exc) {
4627                         mono_runtime_try_invoke (method, o, pa, exc, &error);
4628                         if (*exc == NULL && !mono_error_ok (&error))
4629                                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4630                         else
4631                                 mono_error_cleanup (&error);
4632                 } else {
4633                         mono_runtime_invoke_checked (method, o, pa, &error);
4634                         mono_error_raise_exception (&error); /* FIXME don't raise here */
4635                 }
4636
4637                 return (MonoObject *)obj;
4638         } else {
4639                 if (mono_class_is_nullable (method->klass)) {
4640                         MonoObject *nullable;
4641
4642                         /* Convert the unboxed vtype into a Nullable structure */
4643                         nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4644                         mono_error_raise_exception (&error); /* FIXME don't raise here */
4645
4646                         mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4647                         obj = mono_object_unbox (nullable);
4648                 }
4649
4650                 /* obj must be already unboxed if needed */
4651                 if (exc) {
4652                         res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4653                         if (*exc == NULL && !mono_error_ok (&error))
4654                                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4655                         else
4656                                 mono_error_cleanup (&error);
4657                 } else {
4658                         res = mono_runtime_invoke_checked (method, obj, pa, &error);
4659                         mono_error_raise_exception (&error); /* FIXME don't raise here */
4660                 }
4661
4662                 if (sig->ret->type == MONO_TYPE_PTR) {
4663                         MonoClass *pointer_class;
4664                         static MonoMethod *box_method;
4665                         void *box_args [2];
4666                         MonoObject *box_exc;
4667
4668                         /* 
4669                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
4670                          * convert it to a Pointer object.
4671                          */
4672                         pointer_class = mono_class_get_pointer_class ();
4673                         if (!box_method)
4674                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4675
4676                         g_assert (res->vtable->klass == mono_defaults.int_class);
4677                         box_args [0] = ((MonoIntPtr*)res)->m_value;
4678                         box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4679                         mono_error_raise_exception (&error); /* FIXME don't raise here */
4680
4681                         res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4682                         g_assert (box_exc == NULL);
4683                         mono_error_assert_ok (&error);
4684                 }
4685
4686                 if (has_byref_nullables) {
4687                         /* 
4688                          * The runtime invoke wrapper already converted byref nullables back,
4689                          * and stored them in pa, we just need to copy them back to the
4690                          * managed array.
4691                          */
4692                         for (i = 0; i < mono_array_length (params); i++) {
4693                                 MonoType *t = sig->params [i];
4694
4695                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4696                                         mono_array_setref (params, i, pa [i]);
4697                         }
4698                 }
4699
4700                 return res;
4701         }
4702 }
4703
4704 /**
4705  * mono_object_new:
4706  * @klass: the class of the object that we want to create
4707  *
4708  * Returns: a newly created object whose definition is
4709  * looked up using @klass.   This will not invoke any constructors, 
4710  * so the consumer of this routine has to invoke any constructors on
4711  * its own to initialize the object.
4712  * 
4713  * It returns NULL on failure.
4714  */
4715 MonoObject *
4716 mono_object_new (MonoDomain *domain, MonoClass *klass)
4717 {
4718         MONO_REQ_GC_UNSAFE_MODE;
4719
4720         MonoError error;
4721
4722         MonoObject * result = mono_object_new_checked (domain, klass, &error);
4723
4724         mono_error_raise_exception (&error);
4725         return result;
4726 }
4727
4728 MonoObject *
4729 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4730 {
4731         MONO_REQ_GC_UNSAFE_MODE;
4732
4733         MonoError error;
4734
4735         MonoObject * result = mono_object_new_checked (domain, klass, &error);
4736
4737         mono_error_raise_exception (&error);
4738         return result;
4739 }
4740
4741 /**
4742  * mono_object_new_checked:
4743  * @klass: the class of the object that we want to create
4744  * @error: set on error
4745  *
4746  * Returns: a newly created object whose definition is
4747  * looked up using @klass.   This will not invoke any constructors,
4748  * so the consumer of this routine has to invoke any constructors on
4749  * its own to initialize the object.
4750  *
4751  * It returns NULL on failure and sets @error.
4752  */
4753 MonoObject *
4754 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4755 {
4756         MONO_REQ_GC_UNSAFE_MODE;
4757
4758         MonoVTable *vtable;
4759
4760         vtable = mono_class_vtable (domain, klass);
4761         g_assert (vtable); /* FIXME don't swallow the error */
4762
4763         MonoObject *o = mono_object_new_specific_checked (vtable, error);
4764         return o;
4765 }
4766
4767 /**
4768  * mono_object_new_pinned:
4769  *
4770  *   Same as mono_object_new, but the returned object will be pinned.
4771  * For SGEN, these objects will only be freed at appdomain unload.
4772  */
4773 MonoObject *
4774 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4775 {
4776         MONO_REQ_GC_UNSAFE_MODE;
4777
4778         MonoVTable *vtable;
4779
4780         mono_error_init (error);
4781
4782         vtable = mono_class_vtable (domain, klass);
4783         g_assert (vtable); /* FIXME don't swallow the error */
4784
4785         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4786
4787         if (G_UNLIKELY (!o))
4788                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4789         else if (G_UNLIKELY (vtable->klass->has_finalize))
4790                 mono_object_register_finalizer (o, error);
4791
4792         return o;
4793 }
4794
4795 /**
4796  * mono_object_new_specific:
4797  * @vtable: the vtable of the object that we want to create
4798  *
4799  * Returns: A newly created object with class and domain specified
4800  * by @vtable
4801  */
4802 MonoObject *
4803 mono_object_new_specific (MonoVTable *vtable)
4804 {
4805         MonoError error;
4806         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4807         mono_error_raise_exception (&error);
4808
4809         return o;
4810 }
4811
4812 MonoObject *
4813 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4814 {
4815         MONO_REQ_GC_UNSAFE_MODE;
4816
4817         MonoObject *o;
4818
4819         mono_error_init (error);
4820
4821         /* check for is_com_object for COM Interop */
4822         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4823         {
4824                 gpointer pa [1];
4825                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4826
4827                 if (im == NULL) {
4828                         MonoClass *klass = mono_class_get_activation_services_class ();
4829
4830                         if (!klass->inited)
4831                                 mono_class_init (klass);
4832
4833                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4834                         if (!im) {
4835                                 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4836                                 return NULL;
4837                         }
4838                         vtable->domain->create_proxy_for_type_method = im;
4839                 }
4840         
4841                 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4842                 if (!mono_error_ok (error))
4843                         return NULL;
4844
4845                 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4846                 if (!mono_error_ok (error))
4847                         return NULL;
4848
4849                 if (o != NULL)
4850                         return o;
4851         }
4852
4853         return mono_object_new_alloc_specific_checked (vtable, error);
4854 }
4855
4856 MonoObject *
4857 ves_icall_object_new_specific (MonoVTable *vtable)
4858 {
4859         MonoError error;
4860         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4861         mono_error_raise_exception (&error);
4862
4863         return o;
4864 }
4865
4866 /**
4867  * mono_object_new_alloc_specific:
4868  * @vtable: virtual table for the object.
4869  *
4870  * This function allocates a new `MonoObject` with the type derived
4871  * from the @vtable information.   If the class of this object has a 
4872  * finalizer, then the object will be tracked for finalization.
4873  *
4874  * This method might raise an exception on errors.  Use the
4875  * `mono_object_new_fast_checked` method if you want to manually raise
4876  * the exception.
4877  *
4878  * Returns: the allocated object.   
4879  */
4880 MonoObject *
4881 mono_object_new_alloc_specific (MonoVTable *vtable)
4882 {
4883         MonoError error;
4884         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4885         mono_error_raise_exception (&error);
4886
4887         return o;
4888 }
4889
4890 /**
4891  * mono_object_new_alloc_specific_checked:
4892  * @vtable: virtual table for the object.
4893  * @error: holds the error return value.  
4894  *
4895  * This function allocates a new `MonoObject` with the type derived
4896  * from the @vtable information. If the class of this object has a 
4897  * finalizer, then the object will be tracked for finalization.
4898  *
4899  * If there is not enough memory, the @error parameter will be set
4900  * and will contain a user-visible message with the amount of bytes
4901  * that were requested.
4902  *
4903  * Returns: the allocated object, or NULL if there is not enough memory
4904  *
4905  */
4906 MonoObject *
4907 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4908 {
4909         MONO_REQ_GC_UNSAFE_MODE;
4910
4911         MonoObject *o;
4912
4913         mono_error_init (error);
4914
4915         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4916
4917         if (G_UNLIKELY (!o))
4918                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4919         else if (G_UNLIKELY (vtable->klass->has_finalize))
4920                 mono_object_register_finalizer (o, error);
4921
4922         return o;
4923 }
4924
4925 /**
4926  * mono_object_new_fast:
4927  * @vtable: virtual table for the object.
4928  *
4929  * This function allocates a new `MonoObject` with the type derived
4930  * from the @vtable information.   The returned object is not tracked
4931  * for finalization.   If your object implements a finalizer, you should
4932  * use `mono_object_new_alloc_specific` instead.
4933  *
4934  * This method might raise an exception on errors.  Use the
4935  * `mono_object_new_fast_checked` method if you want to manually raise
4936  * the exception.
4937  *
4938  * Returns: the allocated object.   
4939  */
4940 MonoObject*
4941 mono_object_new_fast (MonoVTable *vtable)
4942 {
4943         MonoError error;
4944         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4945         mono_error_raise_exception (&error);
4946
4947         return o;
4948 }
4949
4950 /**
4951  * mono_object_new_fast_checked:
4952  * @vtable: virtual table for the object.
4953  * @error: holds the error return value.
4954  *
4955  * This function allocates a new `MonoObject` with the type derived
4956  * from the @vtable information. The returned object is not tracked
4957  * for finalization.   If your object implements a finalizer, you should
4958  * use `mono_object_new_alloc_specific_checked` instead.
4959  *
4960  * If there is not enough memory, the @error parameter will be set
4961  * and will contain a user-visible message with the amount of bytes
4962  * that were requested.
4963  *
4964  * Returns: the allocated object, or NULL if there is not enough memory
4965  *
4966  */
4967 MonoObject*
4968 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4969 {
4970         MONO_REQ_GC_UNSAFE_MODE;
4971
4972         MonoObject *o;
4973
4974         mono_error_init (error);
4975
4976         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4977
4978         if (G_UNLIKELY (!o))
4979                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4980
4981         return o;
4982 }
4983
4984 MonoObject *
4985 ves_icall_object_new_fast (MonoVTable *vtable)
4986 {
4987         MonoError error;
4988         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4989         mono_error_raise_exception (&error);
4990
4991         return o;
4992 }
4993
4994 MonoObject*
4995 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4996 {
4997         MONO_REQ_GC_UNSAFE_MODE;
4998
4999         MonoObject *o;
5000
5001         mono_error_init (error);
5002
5003         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5004
5005         if (G_UNLIKELY (!o))
5006                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5007         else if (G_UNLIKELY (vtable->klass->has_finalize))
5008                 mono_object_register_finalizer (o, error);
5009
5010         return o;
5011 }
5012
5013 /**
5014  * mono_class_get_allocation_ftn:
5015  * @vtable: vtable
5016  * @for_box: the object will be used for boxing
5017  * @pass_size_in_words: 
5018  *
5019  * Return the allocation function appropriate for the given class.
5020  */
5021
5022 void*
5023 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5024 {
5025         MONO_REQ_GC_NEUTRAL_MODE;
5026
5027         *pass_size_in_words = FALSE;
5028
5029         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5030                 return ves_icall_object_new_specific;
5031
5032         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5033
5034                 return ves_icall_object_new_fast;
5035
5036                 /* 
5037                  * FIXME: This is actually slower than ves_icall_object_new_fast, because
5038                  * of the overhead of parameter passing.
5039                  */
5040                 /*
5041                 *pass_size_in_words = TRUE;
5042 #ifdef GC_REDIRECT_TO_LOCAL
5043                 return GC_local_gcj_fast_malloc;
5044 #else
5045                 return GC_gcj_fast_malloc;
5046 #endif
5047                 */
5048         }
5049
5050         return ves_icall_object_new_specific;
5051 }
5052
5053 /**
5054  * mono_object_new_from_token:
5055  * @image: Context where the type_token is hosted
5056  * @token: a token of the type that we want to create
5057  *
5058  * Returns: A newly created object whose definition is
5059  * looked up using @token in the @image image
5060  */
5061 MonoObject *
5062 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
5063 {
5064         MONO_REQ_GC_UNSAFE_MODE;
5065
5066         MonoError error;
5067         MonoObject *result;
5068         MonoClass *klass;
5069
5070         klass = mono_class_get_checked (image, token, &error);
5071         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5072         
5073         result = mono_object_new_checked (domain, klass, &error);
5074
5075         mono_error_raise_exception (&error); /* FIXME don't raise here */
5076         return result;
5077         
5078 }
5079
5080
5081 /**
5082  * mono_object_clone:
5083  * @obj: the object to clone
5084  *
5085  * Returns: A newly created object who is a shallow copy of @obj
5086  */
5087 MonoObject *
5088 mono_object_clone (MonoObject *obj)
5089 {
5090         MonoError error;
5091         MonoObject *o = mono_object_clone_checked (obj, &error);
5092         mono_error_raise_exception (&error);
5093
5094         return o;
5095 }
5096
5097 MonoObject *
5098 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5099 {
5100         MONO_REQ_GC_UNSAFE_MODE;
5101
5102         MonoObject *o;
5103         int size;
5104
5105         mono_error_init (error);
5106
5107         size = obj->vtable->klass->instance_size;
5108
5109         if (obj->vtable->klass->rank)
5110                 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5111
5112         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5113
5114         if (G_UNLIKELY (!o)) {
5115                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5116                 return NULL;
5117         }
5118
5119         /* If the object doesn't contain references this will do a simple memmove. */
5120         mono_gc_wbarrier_object_copy (o, obj);
5121
5122         if (obj->vtable->klass->has_finalize)
5123                 mono_object_register_finalizer (o, error);
5124         return o;
5125 }
5126
5127 /**
5128  * mono_array_full_copy:
5129  * @src: source array to copy
5130  * @dest: destination array
5131  *
5132  * Copies the content of one array to another with exactly the same type and size.
5133  */
5134 void
5135 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5136 {
5137         MONO_REQ_GC_UNSAFE_MODE;
5138
5139         uintptr_t size;
5140         MonoClass *klass = src->obj.vtable->klass;
5141
5142         g_assert (klass == dest->obj.vtable->klass);
5143
5144         size = mono_array_length (src);
5145         g_assert (size == mono_array_length (dest));
5146         size *= mono_array_element_size (klass);
5147 #ifdef HAVE_SGEN_GC
5148         if (klass->element_class->valuetype) {
5149                 if (klass->element_class->has_references)
5150                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5151                 else
5152                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5153         } else {
5154                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5155         }
5156 #else
5157         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5158 #endif
5159 }
5160
5161 /**
5162  * mono_array_clone_in_domain:
5163  * @domain: the domain in which the array will be cloned into
5164  * @array: the array to clone
5165  *
5166  * This routine returns a copy of the array that is hosted on the
5167  * specified MonoDomain.
5168  */
5169 MonoArray*
5170 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5171 {
5172         MONO_REQ_GC_UNSAFE_MODE;
5173
5174         MonoError error;
5175         MonoArray *o;
5176         uintptr_t size, i;
5177         uintptr_t *sizes;
5178         MonoClass *klass = array->obj.vtable->klass;
5179
5180         if (array->bounds == NULL) {
5181                 size = mono_array_length (array);
5182                 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5183                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5184
5185                 size *= mono_array_element_size (klass);
5186 #ifdef HAVE_SGEN_GC
5187                 if (klass->element_class->valuetype) {
5188                         if (klass->element_class->has_references)
5189                                 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5190                         else
5191                                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5192                 } else {
5193                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5194                 }
5195 #else
5196                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5197 #endif
5198                 return o;
5199         }
5200         
5201         sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5202         size = mono_array_element_size (klass);
5203         for (i = 0; i < klass->rank; ++i) {
5204                 sizes [i] = array->bounds [i].length;
5205                 size *= array->bounds [i].length;
5206                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5207         }
5208         o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5209         mono_error_raise_exception (&error); /* FIXME don't raise here */
5210 #ifdef HAVE_SGEN_GC
5211         if (klass->element_class->valuetype) {
5212                 if (klass->element_class->has_references)
5213                         mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5214                 else
5215                         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5216         } else {
5217                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5218         }
5219 #else
5220         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5221 #endif
5222
5223         return o;
5224 }
5225
5226 /**
5227  * mono_array_clone:
5228  * @array: the array to clone
5229  *
5230  * Returns: A newly created array who is a shallow copy of @array
5231  */
5232 MonoArray*
5233 mono_array_clone (MonoArray *array)
5234 {
5235         MONO_REQ_GC_UNSAFE_MODE;
5236
5237         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5238 }
5239
5240 /* helper macros to check for overflow when calculating the size of arrays */
5241 #ifdef MONO_BIG_ARRAYS
5242 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5243 #define MYGUINT_MAX MYGUINT64_MAX
5244 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5245             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5246 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5247             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
5248                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5249 #else
5250 #define MYGUINT32_MAX 4294967295U
5251 #define MYGUINT_MAX MYGUINT32_MAX
5252 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5253             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5254 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5255             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
5256                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5257 #endif
5258
5259 gboolean
5260 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5261 {
5262         MONO_REQ_GC_NEUTRAL_MODE;
5263
5264         uintptr_t byte_len;
5265
5266         byte_len = mono_array_element_size (klass);
5267         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5268                 return FALSE;
5269         byte_len *= len;
5270         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5271                 return FALSE;
5272         byte_len += MONO_SIZEOF_MONO_ARRAY;
5273
5274         *res = byte_len;
5275
5276         return TRUE;
5277 }
5278
5279 /**
5280  * mono_array_new_full:
5281  * @domain: domain where the object is created
5282  * @array_class: array class
5283  * @lengths: lengths for each dimension in the array
5284  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5285  *
5286  * This routine creates a new array objects with the given dimensions,
5287  * lower bounds and type.
5288  */
5289 MonoArray*
5290 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5291 {
5292         MonoError error;
5293         MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5294         mono_error_raise_exception (&error);
5295
5296         return array;
5297 }
5298
5299 MonoArray*
5300 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5301 {
5302         MONO_REQ_GC_UNSAFE_MODE;
5303
5304         uintptr_t byte_len = 0, len, bounds_size;
5305         MonoObject *o;
5306         MonoArray *array;
5307         MonoArrayBounds *bounds;
5308         MonoVTable *vtable;
5309         int i;
5310
5311         mono_error_init (error);
5312
5313         if (!array_class->inited)
5314                 mono_class_init (array_class);
5315
5316         len = 1;
5317
5318         /* A single dimensional array with a 0 lower bound is the same as an szarray */
5319         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5320                 len = lengths [0];
5321                 if (len > MONO_ARRAY_MAX_INDEX) {
5322                         mono_error_set_generic_error (error, "System", "OverflowException", "");
5323                         return NULL;
5324                 }
5325                 bounds_size = 0;
5326         } else {
5327                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5328
5329                 for (i = 0; i < array_class->rank; ++i) {
5330                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5331                                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5332                                 return NULL;
5333                         }
5334                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5335                                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5336                                 return NULL;
5337                         }
5338                         len *= lengths [i];
5339                 }
5340         }
5341
5342         if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5343                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5344                 return NULL;
5345         }
5346
5347         if (bounds_size) {
5348                 /* align */
5349                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5350                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5351                         return NULL;
5352                 }
5353                 byte_len = (byte_len + 3) & ~3;
5354                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5355                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5356                         return NULL;
5357                 }
5358                 byte_len += bounds_size;
5359         }
5360         /* 
5361          * Following three lines almost taken from mono_object_new ():
5362          * they need to be kept in sync.
5363          */
5364         vtable = mono_class_vtable_full (domain, array_class, error);
5365         return_val_if_nok (error, NULL);
5366
5367         if (bounds_size)
5368                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5369         else
5370                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5371
5372         if (G_UNLIKELY (!o)) {
5373                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5374                 return NULL;
5375         }
5376
5377         array = (MonoArray*)o;
5378
5379         bounds = array->bounds;
5380
5381         if (bounds_size) {
5382                 for (i = 0; i < array_class->rank; ++i) {
5383                         bounds [i].length = lengths [i];
5384                         if (lower_bounds)
5385                                 bounds [i].lower_bound = lower_bounds [i];
5386                 }
5387         }
5388
5389         return array;
5390 }
5391
5392 /**
5393  * mono_array_new:
5394  * @domain: domain where the object is created
5395  * @eclass: element class
5396  * @n: number of array elements
5397  *
5398  * This routine creates a new szarray with @n elements of type @eclass.
5399  */
5400 MonoArray *
5401 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5402 {
5403         MONO_REQ_GC_UNSAFE_MODE;
5404
5405         MonoError error;
5406         MonoClass *ac;
5407         MonoArray *arr;
5408
5409         ac = mono_array_class_get (eclass, 1);
5410         g_assert (ac);
5411
5412         MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5413         mono_error_raise_exception (&error); /* FIXME don't raise here */
5414
5415         arr = mono_array_new_specific_checked (vtable, n, &error);
5416         mono_error_raise_exception (&error); /* FIXME don't raise here */
5417
5418         return arr;
5419 }
5420
5421 /**
5422  * mono_array_new_specific:
5423  * @vtable: a vtable in the appropriate domain for an initialized class
5424  * @n: number of array elements
5425  *
5426  * This routine is a fast alternative to mono_array_new() for code which
5427  * can be sure about the domain it operates in.
5428  */
5429 MonoArray *
5430 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5431 {
5432         MonoError error;
5433         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5434         mono_error_raise_exception (&error); /* FIXME don't raise here */
5435
5436         return arr;
5437 }
5438
5439 MonoArray*
5440 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5441 {
5442         MONO_REQ_GC_UNSAFE_MODE;
5443
5444         MonoObject *o;
5445         uintptr_t byte_len;
5446
5447         mono_error_init (error);
5448
5449         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5450                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5451                 return NULL;
5452         }
5453
5454         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5455                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5456                 return NULL;
5457         }
5458         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5459
5460         if (G_UNLIKELY (!o)) {
5461                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5462                 return NULL;
5463         }
5464
5465         return (MonoArray*)o;
5466 }
5467
5468 MonoArray*
5469 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5470 {
5471         MonoError error;
5472         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5473         mono_error_raise_exception (&error);
5474
5475         return arr;
5476 }
5477
5478 /**
5479  * mono_string_new_utf16:
5480  * @text: a pointer to an utf16 string
5481  * @len: the length of the string
5482  *
5483  * Returns: A newly created string object which contains @text.
5484  */
5485 MonoString *
5486 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5487 {
5488         MONO_REQ_GC_UNSAFE_MODE;
5489
5490         MonoError error;
5491         MonoString *res = NULL;
5492         res = mono_string_new_utf16_checked (domain, text, len, &error);
5493         mono_error_raise_exception (&error);
5494
5495         return res;
5496 }
5497
5498 /**
5499  * mono_string_new_utf16_checked:
5500  * @text: a pointer to an utf16 string
5501  * @len: the length of the string
5502  * @error: written on error.
5503  *
5504  * Returns: A newly created string object which contains @text.
5505  * On error, returns NULL and sets @error.
5506  */
5507 MonoString *
5508 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5509 {
5510         MONO_REQ_GC_UNSAFE_MODE;
5511
5512         MonoString *s;
5513         
5514         mono_error_init (error);
5515         
5516         s = mono_string_new_size_checked (domain, len, error);
5517         if (s != NULL)
5518                 memcpy (mono_string_chars (s), text, len * 2);
5519
5520         return s;
5521 }
5522
5523 /**
5524  * mono_string_new_utf32:
5525  * @text: a pointer to an utf32 string
5526  * @len: the length of the string
5527  *
5528  * Returns: A newly created string object which contains @text.
5529  */
5530 MonoString *
5531 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5532 {
5533         MONO_REQ_GC_UNSAFE_MODE;
5534
5535         MonoError error;
5536         MonoString *s;
5537         mono_unichar2 *utf16_output = NULL;
5538         gint32 utf16_len = 0;
5539         GError *gerror = NULL;
5540         glong items_written;
5541         
5542         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5543         
5544         if (gerror)
5545                 g_error_free (gerror);
5546
5547         while (utf16_output [utf16_len]) utf16_len++;
5548         
5549         s = mono_string_new_size_checked (domain, utf16_len, &error);
5550         mono_error_raise_exception (&error); /* FIXME don't raise here */
5551
5552         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5553
5554         g_free (utf16_output);
5555         
5556         return s;
5557 }
5558
5559 /**
5560  * mono_string_new_size:
5561  * @text: a pointer to an utf16 string
5562  * @len: the length of the string
5563  *
5564  * Returns: A newly created string object of @len
5565  */
5566 MonoString *
5567 mono_string_new_size (MonoDomain *domain, gint32 len)
5568 {
5569         MonoError error;
5570         MonoString *str = mono_string_new_size_checked (domain, len, &error);
5571         mono_error_raise_exception (&error);
5572
5573         return str;
5574 }
5575
5576 MonoString *
5577 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5578 {
5579         MONO_REQ_GC_UNSAFE_MODE;
5580
5581         MonoString *s;
5582         MonoVTable *vtable;
5583         size_t size;
5584
5585         mono_error_init (error);
5586
5587         /* check for overflow */
5588         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5589                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5590                 return NULL;
5591         }
5592
5593         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5594         g_assert (size > 0);
5595
5596         vtable = mono_class_vtable (domain, mono_defaults.string_class);
5597         g_assert (vtable);
5598
5599         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5600
5601         if (G_UNLIKELY (!s)) {
5602                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5603                 return NULL;
5604         }
5605
5606         return s;
5607 }
5608
5609 /**
5610  * mono_string_new_len:
5611  * @text: a pointer to an utf8 string
5612  * @length: number of bytes in @text to consider
5613  *
5614  * Returns: A newly created string object which contains @text.
5615  */
5616 MonoString*
5617 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5618 {
5619         MONO_REQ_GC_UNSAFE_MODE;
5620
5621         MonoError error;
5622         GError *eg_error = NULL;
5623         MonoString *o = NULL;
5624         guint16 *ut;
5625         glong items_written;
5626
5627         mono_error_init (&error);
5628
5629         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5630
5631         if (!eg_error)
5632                 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5633         else 
5634                 g_error_free (eg_error);
5635
5636         g_free (ut);
5637
5638         mono_error_raise_exception (&error); /* FIXME don't raise here */
5639         return o;
5640 }
5641
5642 /**
5643  * mono_string_new:
5644  * @text: a pointer to an utf8 string
5645  *
5646  * Returns: A newly created string object which contains @text.
5647  *
5648  * This function asserts if it cannot allocate a new string.
5649  *
5650  * @deprecated Use mono_string_new_checked in new code.
5651  */
5652 MonoString*
5653 mono_string_new (MonoDomain *domain, const char *text)
5654 {
5655         MonoError error;
5656         MonoString *res = NULL;
5657         res = mono_string_new_checked (domain, text, &error);
5658         mono_error_assert_ok (&error);
5659         return res;
5660 }
5661
5662 /**
5663  * mono_string_new_checked:
5664  * @text: a pointer to an utf8 string
5665  * @merror: set on error
5666  *
5667  * Returns: A newly created string object which contains @text.
5668  * On error returns NULL and sets @merror.
5669  */
5670 MonoString*
5671 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5672 {
5673         MONO_REQ_GC_UNSAFE_MODE;
5674
5675     GError *eg_error = NULL;
5676     MonoString *o = NULL;
5677     guint16 *ut;
5678     glong items_written;
5679     int l;
5680
5681     mono_error_init (error);
5682
5683     l = strlen (text);
5684    
5685     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5686
5687     if (!eg_error)
5688             o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5689     else
5690         g_error_free (eg_error);
5691
5692     g_free (ut);
5693     mono_error_raise_exception (error);
5694     
5695 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5696 #if 0
5697         gunichar2 *str;
5698         const gchar *end;
5699         int len;
5700         MonoString *o = NULL;
5701
5702         if (!g_utf8_validate (text, -1, &end)) {
5703                 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5704                 goto leave;
5705         }
5706
5707         len = g_utf8_strlen (text, -1);
5708         o = mono_string_new_size_checked (domain, len, error);
5709         if (!o)
5710                 goto leave;
5711         str = mono_string_chars (o);
5712
5713         while (text < end) {
5714                 *str++ = g_utf8_get_char (text);
5715                 text = g_utf8_next_char (text);
5716         }
5717
5718 leave:
5719 #endif
5720         return o;
5721 }
5722
5723 /**
5724  * mono_string_new_wrapper:
5725  * @text: pointer to utf8 characters.
5726  *
5727  * Helper function to create a string object from @text in the current domain.
5728  */
5729 MonoString*
5730 mono_string_new_wrapper (const char *text)
5731 {
5732         MONO_REQ_GC_UNSAFE_MODE;
5733
5734         MonoDomain *domain = mono_domain_get ();
5735
5736         if (text)
5737                 return mono_string_new (domain, text);
5738
5739         return NULL;
5740 }
5741
5742 /**
5743  * mono_value_box:
5744  * @class: the class of the value
5745  * @value: a pointer to the unboxed data
5746  *
5747  * Returns: A newly created object which contains @value.
5748  */
5749 MonoObject *
5750 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5751 {
5752         MONO_REQ_GC_UNSAFE_MODE;
5753
5754         MonoError error;
5755         MonoObject *res;
5756         int size;
5757         MonoVTable *vtable;
5758
5759         g_assert (klass->valuetype);
5760         if (mono_class_is_nullable (klass))
5761                 return mono_nullable_box ((guint8 *)value, klass);
5762
5763         vtable = mono_class_vtable (domain, klass);
5764         if (!vtable)
5765                 return NULL;
5766         size = mono_class_instance_size (klass);
5767         res = mono_object_new_alloc_specific_checked (vtable, &error);
5768         mono_error_raise_exception (&error); /* FIXME don't raise here */
5769
5770         size = size - sizeof (MonoObject);
5771
5772 #ifdef HAVE_SGEN_GC
5773         g_assert (size == mono_class_value_size (klass, NULL));
5774         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5775 #else
5776 #if NO_UNALIGNED_ACCESS
5777         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5778 #else
5779         switch (size) {
5780         case 1:
5781                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5782                 break;
5783         case 2:
5784                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5785                 break;
5786         case 4:
5787                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5788                 break;
5789         case 8:
5790                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5791                 break;
5792         default:
5793                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5794         }
5795 #endif
5796 #endif
5797         if (klass->has_finalize) {
5798                 mono_object_register_finalizer (res, &error);
5799                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5800         }
5801         return res;
5802 }
5803
5804 /**
5805  * mono_value_copy:
5806  * @dest: destination pointer
5807  * @src: source pointer
5808  * @klass: a valuetype class
5809  *
5810  * Copy a valuetype from @src to @dest. This function must be used
5811  * when @klass contains references fields.
5812  */
5813 void
5814 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5815 {
5816         MONO_REQ_GC_UNSAFE_MODE;
5817
5818         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5819 }
5820
5821 /**
5822  * mono_value_copy_array:
5823  * @dest: destination array
5824  * @dest_idx: index in the @dest array
5825  * @src: source pointer
5826  * @count: number of items
5827  *
5828  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
5829  * This function must be used when @klass contains references fields.
5830  * Overlap is handled.
5831  */
5832 void
5833 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5834 {
5835         MONO_REQ_GC_UNSAFE_MODE;
5836
5837         int size = mono_array_element_size (dest->obj.vtable->klass);
5838         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5839         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5840         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5841 }
5842
5843 /**
5844  * mono_object_get_domain:
5845  * @obj: object to query
5846  * 
5847  * Returns: the MonoDomain where the object is hosted
5848  */
5849 MonoDomain*
5850 mono_object_get_domain (MonoObject *obj)
5851 {
5852         MONO_REQ_GC_UNSAFE_MODE;
5853
5854         return mono_object_domain (obj);
5855 }
5856
5857 /**
5858  * mono_object_get_class:
5859  * @obj: object to query
5860  *
5861  * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5862  *
5863  * Returns: the MonoClass of the object.
5864  */
5865 MonoClass*
5866 mono_object_get_class (MonoObject *obj)
5867 {
5868         MONO_REQ_GC_UNSAFE_MODE;
5869
5870         return mono_object_class (obj);
5871 }
5872 /**
5873  * mono_object_get_size:
5874  * @o: object to query
5875  * 
5876  * Returns: the size, in bytes, of @o
5877  */
5878 guint
5879 mono_object_get_size (MonoObject* o)
5880 {
5881         MONO_REQ_GC_UNSAFE_MODE;
5882
5883         MonoClass* klass = mono_object_class (o);
5884         if (klass == mono_defaults.string_class) {
5885                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5886         } else if (o->vtable->rank) {
5887                 MonoArray *array = (MonoArray*)o;
5888                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5889                 if (array->bounds) {
5890                         size += 3;
5891                         size &= ~3;
5892                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
5893                 }
5894                 return size;
5895         } else {
5896                 return mono_class_instance_size (klass);
5897         }
5898 }
5899
5900 /**
5901  * mono_object_unbox:
5902  * @obj: object to unbox
5903  * 
5904  * Returns: a pointer to the start of the valuetype boxed in this
5905  * object.
5906  *
5907  * This method will assert if the object passed is not a valuetype.
5908  */
5909 gpointer
5910 mono_object_unbox (MonoObject *obj)
5911 {
5912         MONO_REQ_GC_UNSAFE_MODE;
5913
5914         /* add assert for valuetypes? */
5915         g_assert (obj->vtable->klass->valuetype);
5916         return ((char*)obj) + sizeof (MonoObject);
5917 }
5918
5919 /**
5920  * mono_object_isinst:
5921  * @obj: an object
5922  * @klass: a pointer to a class 
5923  *
5924  * Returns: @obj if @obj is derived from @klass
5925  */
5926 MonoObject *
5927 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5928 {
5929         MONO_REQ_GC_UNSAFE_MODE;
5930
5931         if (!klass->inited)
5932                 mono_class_init (klass);
5933
5934         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5935                 return mono_object_isinst_mbyref (obj, klass);
5936
5937         if (!obj)
5938                 return NULL;
5939
5940         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5941 }
5942
5943 MonoObject *
5944 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5945 {
5946         MONO_REQ_GC_UNSAFE_MODE;
5947
5948         MonoError error;
5949         MonoVTable *vt;
5950
5951         if (!obj)
5952                 return NULL;
5953
5954         vt = obj->vtable;
5955         
5956         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5957                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5958                         return obj;
5959                 }
5960
5961                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5962                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5963                         return obj;
5964         } else {
5965                 MonoClass *oklass = vt->klass;
5966                 if (mono_class_is_transparent_proxy (oklass))
5967                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5968
5969                 mono_class_setup_supertypes (klass);    
5970                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5971                         return obj;
5972         }
5973 #ifndef DISABLE_REMOTING
5974         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5975         {
5976                 MonoDomain *domain = mono_domain_get ();
5977                 MonoObject *res;
5978                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5979                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5980                 MonoMethod *im = NULL;
5981                 gpointer pa [2];
5982
5983                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5984                 if (!im)
5985                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5986                 im = mono_object_get_virtual_method (rp, im);
5987                 g_assert (im);
5988         
5989                 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5990                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5991                 pa [1] = obj;
5992
5993                 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5994                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5995
5996                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5997                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5998                         mono_upgrade_remote_class (domain, obj, klass);
5999                         return obj;
6000                 }
6001         }
6002 #endif /* DISABLE_REMOTING */
6003         return NULL;
6004 }
6005
6006 /**
6007  * mono_object_castclass_mbyref:
6008  * @obj: an object
6009  * @klass: a pointer to a class 
6010  *
6011  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6012  */
6013 MonoObject *
6014 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6015 {
6016         MONO_REQ_GC_UNSAFE_MODE;
6017
6018         if (!obj) return NULL;
6019         if (mono_object_isinst_mbyref (obj, klass)) return obj;
6020                 
6021         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6022                                                         "System",
6023                                                         "InvalidCastException"));
6024         return NULL;
6025 }
6026
6027 typedef struct {
6028         MonoDomain *orig_domain;
6029         MonoString *ins;
6030         MonoString *res;
6031 } LDStrInfo;
6032
6033 static void
6034 str_lookup (MonoDomain *domain, gpointer user_data)
6035 {
6036         MONO_REQ_GC_UNSAFE_MODE;
6037
6038         LDStrInfo *info = (LDStrInfo *)user_data;
6039         if (info->res || domain == info->orig_domain)
6040                 return;
6041         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6042 }
6043
6044 static MonoString*
6045 mono_string_get_pinned (MonoString *str, MonoError *error)
6046 {
6047         MONO_REQ_GC_UNSAFE_MODE;
6048
6049         mono_error_init (error);
6050
6051         /* We only need to make a pinned version of a string if this is a moving GC */
6052         if (!mono_gc_is_moving ())
6053                 return str;
6054         int size;
6055         MonoString *news;
6056         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6057         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6058         if (news) {
6059                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6060                 news->length = mono_string_length (str);
6061         } else {
6062                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6063         }
6064         return news;
6065 }
6066
6067 static MonoString*
6068 mono_string_is_interned_lookup (MonoString *str, int insert)
6069 {
6070         MONO_REQ_GC_UNSAFE_MODE;
6071
6072         MonoError error;
6073         MonoGHashTable *ldstr_table;
6074         MonoString *s, *res;
6075         MonoDomain *domain;
6076         
6077         domain = ((MonoObject *)str)->vtable->domain;
6078         ldstr_table = domain->ldstr_table;
6079         ldstr_lock ();
6080         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6081         if (res) {
6082                 ldstr_unlock ();
6083                 return res;
6084         }
6085         if (insert) {
6086                 /* Allocate outside the lock */
6087                 ldstr_unlock ();
6088                 s = mono_string_get_pinned (str, &error);
6089                 mono_error_raise_exception (&error); /* FIXME don't raise here */
6090                 if (s) {
6091                         ldstr_lock ();
6092                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6093                         if (res) {
6094                                 ldstr_unlock ();
6095                                 return res;
6096                         }
6097                         mono_g_hash_table_insert (ldstr_table, s, s);
6098                         ldstr_unlock ();
6099                 }
6100                 return s;
6101         } else {
6102                 LDStrInfo ldstr_info;
6103                 ldstr_info.orig_domain = domain;
6104                 ldstr_info.ins = str;
6105                 ldstr_info.res = NULL;
6106
6107                 mono_domain_foreach (str_lookup, &ldstr_info);
6108                 if (ldstr_info.res) {
6109                         /* 
6110                          * the string was already interned in some other domain:
6111                          * intern it in the current one as well.
6112                          */
6113                         mono_g_hash_table_insert (ldstr_table, str, str);
6114                         ldstr_unlock ();
6115                         return str;
6116                 }
6117         }
6118         ldstr_unlock ();
6119         return NULL;
6120 }
6121
6122 /**
6123  * mono_string_is_interned:
6124  * @o: String to probe
6125  *
6126  * Returns whether the string has been interned.
6127  */
6128 MonoString*
6129 mono_string_is_interned (MonoString *o)
6130 {
6131         MONO_REQ_GC_UNSAFE_MODE;
6132
6133         return mono_string_is_interned_lookup (o, FALSE);
6134 }
6135
6136 /**
6137  * mono_string_intern:
6138  * @o: String to intern
6139  *
6140  * Interns the string passed.  
6141  * Returns: The interned string.
6142  */
6143 MonoString*
6144 mono_string_intern (MonoString *str)
6145 {
6146         MONO_REQ_GC_UNSAFE_MODE;
6147
6148         return mono_string_is_interned_lookup (str, TRUE);
6149 }
6150
6151 /**
6152  * mono_ldstr:
6153  * @domain: the domain where the string will be used.
6154  * @image: a metadata context
6155  * @idx: index into the user string table.
6156  * 
6157  * Implementation for the ldstr opcode.
6158  * Returns: a loaded string from the @image/@idx combination.
6159  */
6160 MonoString*
6161 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6162 {
6163         MONO_REQ_GC_UNSAFE_MODE;
6164
6165         if (image->dynamic) {
6166                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6167                 return str;
6168         } else {
6169                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6170                         return NULL; /*FIXME we should probably be raising an exception here*/
6171                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6172         }
6173 }
6174
6175 /**
6176  * mono_ldstr_metadata_sig
6177  * @domain: the domain for the string
6178  * @sig: the signature of a metadata string
6179  *
6180  * Returns: a MonoString for a string stored in the metadata
6181  */
6182 static MonoString*
6183 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6184 {
6185         MONO_REQ_GC_UNSAFE_MODE;
6186
6187         MonoError error;
6188         const char *str = sig;
6189         MonoString *o, *interned;
6190         size_t len2;
6191
6192         len2 = mono_metadata_decode_blob_size (str, &str);
6193         len2 >>= 1;
6194
6195         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6196         mono_error_raise_exception (&error); /* FIXME don't raise here */
6197 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6198         {
6199                 int i;
6200                 guint16 *p2 = (guint16*)mono_string_chars (o);
6201                 for (i = 0; i < len2; ++i) {
6202                         *p2 = GUINT16_FROM_LE (*p2);
6203                         ++p2;
6204                 }
6205         }
6206 #endif
6207         ldstr_lock ();
6208         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6209         ldstr_unlock ();
6210         if (interned)
6211                 return interned; /* o will get garbage collected */
6212
6213         o = mono_string_get_pinned (o, &error);
6214         mono_error_raise_exception (&error); /* FIXME don't raise here */
6215         if (o) {
6216                 ldstr_lock ();
6217                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6218                 if (!interned) {
6219                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6220                         interned = o;
6221                 }
6222                 ldstr_unlock ();
6223         }
6224
6225         return interned;
6226 }
6227
6228 /**
6229  * mono_string_to_utf8:
6230  * @s: a System.String
6231  *
6232  * Returns the UTF8 representation for @s.
6233  * The resulting buffer needs to be freed with mono_free().
6234  *
6235  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6236  */
6237 char *
6238 mono_string_to_utf8 (MonoString *s)
6239 {
6240         MONO_REQ_GC_UNSAFE_MODE;
6241
6242         MonoError error;
6243         char *result = mono_string_to_utf8_checked (s, &error);
6244         
6245         if (!mono_error_ok (&error))
6246                 mono_error_raise_exception (&error);
6247         return result;
6248 }
6249
6250 /**
6251  * mono_string_to_utf8_checked:
6252  * @s: a System.String
6253  * @error: a MonoError.
6254  * 
6255  * Converts a MonoString to its UTF8 representation. May fail; check 
6256  * @error to determine whether the conversion was successful.
6257  * The resulting buffer should be freed with mono_free().
6258  */
6259 char *
6260 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6261 {
6262         MONO_REQ_GC_UNSAFE_MODE;
6263
6264         long written = 0;
6265         char *as;
6266         GError *gerror = NULL;
6267
6268         mono_error_init (error);
6269
6270         if (s == NULL)
6271                 return NULL;
6272
6273         if (!s->length)
6274                 return g_strdup ("");
6275
6276         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6277         if (gerror) {
6278                 mono_error_set_argument (error, "string", "%s", gerror->message);
6279                 g_error_free (gerror);
6280                 return NULL;
6281         }
6282         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6283         if (s->length > written) {
6284                 /* allocate the total length and copy the part of the string that has been converted */
6285                 char *as2 = (char *)g_malloc0 (s->length);
6286                 memcpy (as2, as, written);
6287                 g_free (as);
6288                 as = as2;
6289         }
6290
6291         return as;
6292 }
6293
6294 /**
6295  * mono_string_to_utf8_ignore:
6296  * @s: a MonoString
6297  *
6298  * Converts a MonoString to its UTF8 representation. Will ignore
6299  * invalid surrogate pairs.
6300  * The resulting buffer should be freed with mono_free().
6301  * 
6302  */
6303 char *
6304 mono_string_to_utf8_ignore (MonoString *s)
6305 {
6306         MONO_REQ_GC_UNSAFE_MODE;
6307
6308         long written = 0;
6309         char *as;
6310
6311         if (s == NULL)
6312                 return NULL;
6313
6314         if (!s->length)
6315                 return g_strdup ("");
6316
6317         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6318
6319         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6320         if (s->length > written) {
6321                 /* allocate the total length and copy the part of the string that has been converted */
6322                 char *as2 = (char *)g_malloc0 (s->length);
6323                 memcpy (as2, as, written);
6324                 g_free (as);
6325                 as = as2;
6326         }
6327
6328         return as;
6329 }
6330
6331 /**
6332  * mono_string_to_utf8_image_ignore:
6333  * @s: a System.String
6334  *
6335  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6336  */
6337 char *
6338 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6339 {
6340         MONO_REQ_GC_UNSAFE_MODE;
6341
6342         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6343 }
6344
6345 /**
6346  * mono_string_to_utf8_mp_ignore:
6347  * @s: a System.String
6348  *
6349  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6350  */
6351 char *
6352 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6353 {
6354         MONO_REQ_GC_UNSAFE_MODE;
6355
6356         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6357 }
6358
6359
6360 /**
6361  * mono_string_to_utf16:
6362  * @s: a MonoString
6363  *
6364  * Return an null-terminated array of the utf-16 chars
6365  * contained in @s. The result must be freed with g_free().
6366  * This is a temporary helper until our string implementation
6367  * is reworked to always include the null terminating char.
6368  */
6369 mono_unichar2*
6370 mono_string_to_utf16 (MonoString *s)
6371 {
6372         MONO_REQ_GC_UNSAFE_MODE;
6373
6374         char *as;
6375
6376         if (s == NULL)
6377                 return NULL;
6378
6379         as = (char *)g_malloc ((s->length * 2) + 2);
6380         as [(s->length * 2)] = '\0';
6381         as [(s->length * 2) + 1] = '\0';
6382
6383         if (!s->length) {
6384                 return (gunichar2 *)(as);
6385         }
6386         
6387         memcpy (as, mono_string_chars(s), s->length * 2);
6388         return (gunichar2 *)(as);
6389 }
6390
6391 /**
6392  * mono_string_to_utf32:
6393  * @s: a MonoString
6394  *
6395  * Return an null-terminated array of the UTF-32 (UCS-4) chars
6396  * contained in @s. The result must be freed with g_free().
6397  */
6398 mono_unichar4*
6399 mono_string_to_utf32 (MonoString *s)
6400 {
6401         MONO_REQ_GC_UNSAFE_MODE;
6402
6403         mono_unichar4 *utf32_output = NULL; 
6404         GError *error = NULL;
6405         glong items_written;
6406         
6407         if (s == NULL)
6408                 return NULL;
6409                 
6410         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6411         
6412         if (error)
6413                 g_error_free (error);
6414
6415         return utf32_output;
6416 }
6417
6418 /**
6419  * mono_string_from_utf16:
6420  * @data: the UTF16 string (LPWSTR) to convert
6421  *
6422  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6423  *
6424  * Returns: a MonoString.
6425  */
6426 MonoString *
6427 mono_string_from_utf16 (gunichar2 *data)
6428 {
6429         MONO_REQ_GC_UNSAFE_MODE;
6430
6431         MonoError error;
6432         MonoString *res = NULL;
6433         MonoDomain *domain = mono_domain_get ();
6434         int len = 0;
6435
6436         if (!data)
6437                 return NULL;
6438
6439         while (data [len]) len++;
6440
6441         res = mono_string_new_utf16_checked (domain, data, len, &error);
6442         mono_error_raise_exception (&error); /* FIXME don't raise here */
6443         return res;
6444 }
6445
6446 /**
6447  * mono_string_from_utf32:
6448  * @data: the UTF32 string (LPWSTR) to convert
6449  *
6450  * Converts a UTF32 (UCS-4)to a MonoString.
6451  *
6452  * Returns: a MonoString.
6453  */
6454 MonoString *
6455 mono_string_from_utf32 (mono_unichar4 *data)
6456 {
6457         MONO_REQ_GC_UNSAFE_MODE;
6458
6459         MonoString* result = NULL;
6460         mono_unichar2 *utf16_output = NULL;
6461         GError *error = NULL;
6462         glong items_written;
6463         int len = 0;
6464
6465         if (!data)
6466                 return NULL;
6467
6468         while (data [len]) len++;
6469
6470         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6471
6472         if (error)
6473                 g_error_free (error);
6474
6475         result = mono_string_from_utf16 (utf16_output);
6476         g_free (utf16_output);
6477         return result;
6478 }
6479
6480 static char *
6481 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6482 {
6483         MONO_REQ_GC_UNSAFE_MODE;
6484
6485         char *r;
6486         char *mp_s;
6487         int len;
6488
6489         if (ignore_error) {
6490                 r = mono_string_to_utf8_ignore (s);
6491         } else {
6492                 r = mono_string_to_utf8_checked (s, error);
6493                 if (!mono_error_ok (error))
6494                         return NULL;
6495         }
6496
6497         if (!mp && !image)
6498                 return r;
6499
6500         len = strlen (r) + 1;
6501         if (mp)
6502                 mp_s = (char *)mono_mempool_alloc (mp, len);
6503         else
6504                 mp_s = (char *)mono_image_alloc (image, len);
6505
6506         memcpy (mp_s, r, len);
6507
6508         g_free (r);
6509
6510         return mp_s;
6511 }
6512
6513 /**
6514  * mono_string_to_utf8_image:
6515  * @s: a System.String
6516  *
6517  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6518  */
6519 char *
6520 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6521 {
6522         MONO_REQ_GC_UNSAFE_MODE;
6523
6524         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6525 }
6526
6527 /**
6528  * mono_string_to_utf8_mp:
6529  * @s: a System.String
6530  *
6531  * Same as mono_string_to_utf8, but allocate the string from a mempool.
6532  */
6533 char *
6534 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6535 {
6536         MONO_REQ_GC_UNSAFE_MODE;
6537
6538         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6539 }
6540
6541
6542 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6543
6544 void
6545 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6546 {
6547         eh_callbacks = *cbs;
6548 }
6549
6550 MonoRuntimeExceptionHandlingCallbacks *
6551 mono_get_eh_callbacks (void)
6552 {
6553         return &eh_callbacks;
6554 }
6555
6556 /**
6557  * mono_raise_exception:
6558  * @ex: exception object
6559  *
6560  * Signal the runtime that the exception @ex has been raised in unmanaged code.
6561  */
6562 void
6563 mono_raise_exception (MonoException *ex) 
6564 {
6565         MONO_REQ_GC_UNSAFE_MODE;
6566
6567         /*
6568          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6569          * that will cause gcc to omit the function epilog, causing problems when
6570          * the JIT tries to walk the stack, since the return address on the stack
6571          * will point into the next function in the executable, not this one.
6572          */     
6573         eh_callbacks.mono_raise_exception (ex);
6574 }
6575
6576 void
6577 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
6578 {
6579         MONO_REQ_GC_UNSAFE_MODE;
6580
6581         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6582 }
6583
6584 /**
6585  * mono_wait_handle_new:
6586  * @domain: Domain where the object will be created
6587  * @handle: Handle for the wait handle
6588  *
6589  * Returns: A new MonoWaitHandle created in the given domain for the given handle
6590  */
6591 MonoWaitHandle *
6592 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6593 {
6594         MONO_REQ_GC_UNSAFE_MODE;
6595
6596         MonoError error;
6597         MonoWaitHandle *res;
6598         gpointer params [1];
6599         static MonoMethod *handle_set;
6600
6601         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6602         mono_error_raise_exception (&error); /* FIXME don't raise here */
6603
6604         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
6605         if (!handle_set)
6606                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6607
6608         params [0] = &handle;
6609
6610         mono_runtime_invoke_checked (handle_set, res, params, &error);
6611         mono_error_raise_exception (&error); /* FIXME don't raise here */
6612
6613         return res;
6614 }
6615
6616 HANDLE
6617 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6618 {
6619         MONO_REQ_GC_UNSAFE_MODE;
6620
6621         static MonoClassField *f_safe_handle = NULL;
6622         MonoSafeHandle *sh;
6623
6624         if (!f_safe_handle) {
6625                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6626                 g_assert (f_safe_handle);
6627         }
6628
6629         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6630         return sh->handle;
6631 }
6632
6633
6634 static MonoObject*
6635 mono_runtime_capture_context (MonoDomain *domain)
6636 {
6637         MONO_REQ_GC_UNSAFE_MODE;
6638
6639         RuntimeInvokeFunction runtime_invoke;
6640
6641         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6642                 MonoMethod *method = mono_get_context_capture_method ();
6643                 MonoMethod *wrapper;
6644                 if (!method)
6645                         return NULL;
6646                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6647                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6648                 domain->capture_context_method = mono_compile_method (method);
6649         }
6650
6651         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6652
6653         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6654 }
6655 /**
6656  * mono_async_result_new:
6657  * @domain:domain where the object will be created.
6658  * @handle: wait handle.
6659  * @state: state to pass to AsyncResult
6660  * @data: C closure data.
6661  *
6662  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6663  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6664  *
6665  */
6666 MonoAsyncResult *
6667 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6668 {
6669         MONO_REQ_GC_UNSAFE_MODE;
6670
6671         MonoError error;
6672         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6673         mono_error_raise_exception (&error); /* FIXME don't raise here */
6674         MonoObject *context = mono_runtime_capture_context (domain);
6675         /* we must capture the execution context from the original thread */
6676         if (context) {
6677                 MONO_OBJECT_SETREF (res, execution_context, context);
6678                 /* note: result may be null if the flow is suppressed */
6679         }
6680
6681         res->data = (void **)data;
6682         MONO_OBJECT_SETREF (res, object_data, object_data);
6683         MONO_OBJECT_SETREF (res, async_state, state);
6684         if (handle != NULL)
6685                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6686
6687         res->sync_completed = FALSE;
6688         res->completed = FALSE;
6689
6690         return res;
6691 }
6692
6693 MonoObject *
6694 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6695 {
6696         MONO_REQ_GC_UNSAFE_MODE;
6697
6698         MonoError error;
6699         MonoAsyncCall *ac;
6700         MonoObject *res;
6701
6702         g_assert (ares);
6703         g_assert (ares->async_delegate);
6704
6705         ac = (MonoAsyncCall*) ares->object_data;
6706         if (!ac) {
6707                 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6708         } else {
6709                 gpointer wait_event = NULL;
6710
6711                 ac->msg->exc = NULL;
6712                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6713                 MONO_OBJECT_SETREF (ac, res, res);
6714
6715                 mono_monitor_enter ((MonoObject*) ares);
6716                 ares->completed = 1;
6717                 if (ares->handle)
6718                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6719                 mono_monitor_exit ((MonoObject*) ares);
6720
6721                 if (wait_event != NULL)
6722                         SetEvent (wait_event);
6723
6724                 if (ac->cb_method) {
6725                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6726                         mono_error_raise_exception (&error);
6727                 }
6728         }
6729
6730         return res;
6731 }
6732
6733 void
6734 mono_message_init (MonoDomain *domain,
6735                    MonoMethodMessage *this_obj, 
6736                    MonoReflectionMethod *method,
6737                    MonoArray *out_args)
6738 {
6739         MONO_REQ_GC_UNSAFE_MODE;
6740
6741         static MonoClass *object_array_klass;
6742         static MonoClass *byte_array_klass;
6743         static MonoClass *string_array_klass;
6744         MonoError error;
6745         MonoMethodSignature *sig = mono_method_signature (method->method);
6746         MonoString *name;
6747         MonoArray *arr;
6748         int i, j;
6749         char **names;
6750         guint8 arg_type;
6751
6752         if (!object_array_klass) {
6753                 MonoClass *klass;
6754
6755                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6756                 g_assert (klass);
6757                 byte_array_klass = klass;
6758
6759                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6760                 g_assert (klass);
6761                 string_array_klass = klass;
6762
6763                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6764                 g_assert (klass);
6765
6766                 mono_atomic_store_release (&object_array_klass, klass);
6767         }
6768
6769         MONO_OBJECT_SETREF (this_obj, method, method);
6770
6771         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6772         mono_error_raise_exception (&error); /* FIXME don't raise here */
6773
6774         MONO_OBJECT_SETREF (this_obj, args, arr);
6775
6776         arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6777         mono_error_raise_exception (&error); /* FIXME don't raise here */
6778
6779         MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6780
6781         this_obj->async_result = NULL;
6782         this_obj->call_type = CallType_Sync;
6783
6784         names = g_new (char *, sig->param_count);
6785         mono_method_get_param_names (method->method, (const char **) names);
6786
6787         arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6788         mono_error_raise_exception (&error); /* FIXME don't raise here */
6789
6790         MONO_OBJECT_SETREF (this_obj, names, arr);
6791         
6792         for (i = 0; i < sig->param_count; i++) {
6793                 name = mono_string_new (domain, names [i]);
6794                 mono_array_setref (this_obj->names, i, name);   
6795         }
6796
6797         g_free (names);
6798         for (i = 0, j = 0; i < sig->param_count; i++) {
6799                 if (sig->params [i]->byref) {
6800                         if (out_args) {
6801                                 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6802                                 mono_array_setref (this_obj->args, i, arg);
6803                                 j++;
6804                         }
6805                         arg_type = 2;
6806                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6807                                 arg_type |= 1;
6808                 } else {
6809                         arg_type = 1;
6810                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6811                                 arg_type |= 4;
6812                 }
6813                 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6814         }
6815 }
6816
6817 #ifndef DISABLE_REMOTING
6818 /**
6819  * mono_remoting_invoke:
6820  * @real_proxy: pointer to a RealProxy object
6821  * @msg: The MonoMethodMessage to execute
6822  * @exc: used to store exceptions
6823  * @out_args: used to store output arguments
6824  *
6825  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6826  * IMessage interface and it is not trivial to extract results from there. So
6827  * we call an helper method PrivateInvoke instead of calling
6828  * RealProxy::Invoke() directly.
6829  *
6830  * Returns: the result object.
6831  */
6832 MonoObject *
6833 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
6834                       MonoObject **exc, MonoArray **out_args)
6835 {
6836         MONO_REQ_GC_UNSAFE_MODE;
6837
6838         MonoError error;
6839         MonoObject *o;
6840         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6841         gpointer pa [4];
6842
6843         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6844
6845         if (!im) {
6846                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6847                 if (!im)
6848                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6849                 real_proxy->vtable->domain->private_invoke_method = im;
6850         }
6851
6852         pa [0] = real_proxy;
6853         pa [1] = msg;
6854         pa [2] = exc;
6855         pa [3] = out_args;
6856
6857         if (exc) {
6858                 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6859         } else {
6860                 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6861         }
6862         mono_error_raise_exception (&error); /* FIXME don't raise here */
6863
6864         return o;
6865 }
6866 #endif
6867
6868 MonoObject *
6869 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6870                      MonoObject **exc, MonoArray **out_args) 
6871 {
6872         MONO_REQ_GC_UNSAFE_MODE;
6873
6874         static MonoClass *object_array_klass;
6875         MonoError error;
6876         MonoDomain *domain; 
6877         MonoMethod *method;
6878         MonoMethodSignature *sig;
6879         MonoObject *ret;
6880         MonoArray *arr;
6881         int i, j, outarg_count = 0;
6882
6883 #ifndef DISABLE_REMOTING
6884         if (target && mono_object_is_transparent_proxy (target)) {
6885                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6886                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6887                         target = tp->rp->unwrapped_server;
6888                 } else {
6889                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6890                 }
6891         }
6892 #endif
6893
6894         domain = mono_domain_get (); 
6895         method = msg->method->method;
6896         sig = mono_method_signature (method);
6897
6898         for (i = 0; i < sig->param_count; i++) {
6899                 if (sig->params [i]->byref) 
6900                         outarg_count++;
6901         }
6902
6903         if (!object_array_klass) {
6904                 MonoClass *klass;
6905
6906                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6907                 g_assert (klass);
6908
6909                 mono_memory_barrier ();
6910                 object_array_klass = klass;
6911         }
6912
6913         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6914         mono_error_raise_exception (&error); /* FIXME don't raise here */
6915
6916         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6917         *exc = NULL;
6918
6919         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6920
6921         for (i = 0, j = 0; i < sig->param_count; i++) {
6922                 if (sig->params [i]->byref) {
6923                         MonoObject* arg;
6924                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6925                         mono_array_setref (*out_args, j, arg);
6926                         j++;
6927                 }
6928         }
6929
6930         return ret;
6931 }
6932
6933 /**
6934  * mono_object_to_string:
6935  * @obj: The object
6936  * @exc: Any exception thrown by ToString (). May be NULL.
6937  *
6938  * Returns: the result of calling ToString () on an object.
6939  */
6940 MonoString *
6941 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6942 {
6943         MONO_REQ_GC_UNSAFE_MODE;
6944
6945         static MonoMethod *to_string = NULL;
6946         MonoError error;
6947         MonoMethod *method;
6948         MonoString *s;
6949         void *target = obj;
6950
6951         g_assert (obj);
6952
6953         if (!to_string)
6954                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6955
6956         method = mono_object_get_virtual_method (obj, to_string);
6957
6958         // Unbox value type if needed
6959         if (mono_class_is_valuetype (mono_method_get_class (method))) {
6960                 target = mono_object_unbox (obj);
6961         }
6962
6963         if (exc) {
6964                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6965                 if (*exc == NULL && !mono_error_ok (&error))
6966                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6967                 else
6968                         mono_error_cleanup (&error);
6969         } else {
6970                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6971                 mono_error_raise_exception (&error); /* FIXME don't raise here */
6972         }
6973
6974         return s;
6975 }
6976
6977 /**
6978  * mono_print_unhandled_exception:
6979  * @exc: The exception
6980  *
6981  * Prints the unhandled exception.
6982  */
6983 void
6984 mono_print_unhandled_exception (MonoObject *exc)
6985 {
6986         MONO_REQ_GC_UNSAFE_MODE;
6987
6988         MonoString * str;
6989         char *message = (char*)"";
6990         gboolean free_message = FALSE;
6991         MonoError error;
6992
6993         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6994                 message = g_strdup ("OutOfMemoryException");
6995                 free_message = TRUE;
6996         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6997                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6998                 free_message = TRUE;
6999         } else {
7000                 
7001                 if (((MonoException*)exc)->native_trace_ips) {
7002                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
7003                         free_message = TRUE;
7004                 } else {
7005                         MonoObject *other_exc = NULL;
7006                         str = mono_object_to_string (exc, &other_exc);
7007                         if (other_exc) {
7008                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7009                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7010                                 
7011                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7012                                         original_backtrace, nested_backtrace);
7013
7014                                 g_free (original_backtrace);
7015                                 g_free (nested_backtrace);
7016                                 free_message = TRUE;
7017                         } else if (str) {
7018                                 message = mono_string_to_utf8_checked (str, &error);
7019                                 if (!mono_error_ok (&error)) {
7020                                         mono_error_cleanup (&error);
7021                                         message = (char *) "";
7022                                 } else {
7023                                         free_message = TRUE;
7024                                 }
7025                         }
7026                 }
7027         }
7028
7029         /*
7030          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7031          *         exc->vtable->klass->name, message);
7032          */
7033         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7034         
7035         if (free_message)
7036                 g_free (message);
7037 }
7038
7039 /**
7040  * mono_delegate_ctor:
7041  * @this: pointer to an uninitialized delegate object
7042  * @target: target object
7043  * @addr: pointer to native code
7044  * @method: method
7045  *
7046  * Initialize a delegate and sets a specific method, not the one
7047  * associated with addr.  This is useful when sharing generic code.
7048  * In that case addr will most probably not be associated with the
7049  * correct instantiation of the method.
7050  */
7051 void
7052 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7053 {
7054         MONO_REQ_GC_UNSAFE_MODE;
7055
7056         MonoDelegate *delegate = (MonoDelegate *)this_obj;
7057
7058         g_assert (this_obj);
7059         g_assert (addr);
7060
7061         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7062
7063         if (method)
7064                 delegate->method = method;
7065
7066         mono_stats.delegate_creations++;
7067
7068 #ifndef DISABLE_REMOTING
7069         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7070                 g_assert (method);
7071                 method = mono_marshal_get_remoting_invoke (method);
7072                 delegate->method_ptr = mono_compile_method (method);
7073                 MONO_OBJECT_SETREF (delegate, target, target);
7074         } else
7075 #endif
7076         {
7077                 delegate->method_ptr = addr;
7078                 MONO_OBJECT_SETREF (delegate, target, target);
7079         }
7080
7081         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7082         if (callbacks.init_delegate)
7083                 callbacks.init_delegate (delegate);
7084 }
7085
7086 /**
7087  * mono_delegate_ctor:
7088  * @this: pointer to an uninitialized delegate object
7089  * @target: target object
7090  * @addr: pointer to native code
7091  *
7092  * This is used to initialize a delegate.
7093  */
7094 void
7095 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7096 {
7097         MONO_REQ_GC_UNSAFE_MODE;
7098
7099         MonoDomain *domain = mono_domain_get ();
7100         MonoJitInfo *ji;
7101         MonoMethod *method = NULL;
7102
7103         g_assert (addr);
7104
7105         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7106         /* Shared code */
7107         if (!ji && domain != mono_get_root_domain ())
7108                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7109         if (ji) {
7110                 method = mono_jit_info_get_method (ji);
7111                 g_assert (!method->klass->generic_container);
7112         }
7113
7114         mono_delegate_ctor_with_method (this_obj, target, addr, method);
7115 }
7116
7117 /**
7118  * mono_method_call_message_new:
7119  * @method: method to encapsulate
7120  * @params: parameters to the method
7121  * @invoke: optional, delegate invoke.
7122  * @cb: async callback delegate.
7123  * @state: state passed to the async callback.
7124  *
7125  * Translates arguments pointers into a MonoMethodMessage.
7126  */
7127 MonoMethodMessage *
7128 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7129                               MonoDelegate **cb, MonoObject **state)
7130 {
7131         MONO_REQ_GC_UNSAFE_MODE;
7132
7133         MonoError error;
7134
7135         MonoDomain *domain = mono_domain_get ();
7136         MonoMethodSignature *sig = mono_method_signature (method);
7137         MonoMethodMessage *msg;
7138         int i, count;
7139
7140         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error); 
7141         mono_error_raise_exception (&error); /* FIXME don't raise here */
7142
7143         if (invoke) {
7144                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7145                 mono_error_raise_exception (&error); /* FIXME don't raise here */
7146                 mono_message_init (domain, msg, rm, NULL);
7147                 count =  sig->param_count - 2;
7148         } else {
7149                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7150                 mono_error_raise_exception (&error); /* FIXME don't raise here */
7151                 mono_message_init (domain, msg, rm, NULL);
7152                 count =  sig->param_count;
7153         }
7154
7155         for (i = 0; i < count; i++) {
7156                 gpointer vpos;
7157                 MonoClass *klass;
7158                 MonoObject *arg;
7159
7160                 if (sig->params [i]->byref)
7161                         vpos = *((gpointer *)params [i]);
7162                 else 
7163                         vpos = params [i];
7164
7165                 klass = mono_class_from_mono_type (sig->params [i]);
7166
7167                 if (klass->valuetype)
7168                         arg = mono_value_box (domain, klass, vpos);
7169                 else 
7170                         arg = *((MonoObject **)vpos);
7171                       
7172                 mono_array_setref (msg->args, i, arg);
7173         }
7174
7175         if (cb != NULL && state != NULL) {
7176                 *cb = *((MonoDelegate **)params [i]);
7177                 i++;
7178                 *state = *((MonoObject **)params [i]);
7179         }
7180
7181         return msg;
7182 }
7183
7184 /**
7185  * mono_method_return_message_restore:
7186  *
7187  * Restore results from message based processing back to arguments pointers
7188  */
7189 void
7190 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7191 {
7192         MONO_REQ_GC_UNSAFE_MODE;
7193
7194         MonoMethodSignature *sig = mono_method_signature (method);
7195         int i, j, type, size, out_len;
7196         
7197         if (out_args == NULL)
7198                 return;
7199         out_len = mono_array_length (out_args);
7200         if (out_len == 0)
7201                 return;
7202
7203         for (i = 0, j = 0; i < sig->param_count; i++) {
7204                 MonoType *pt = sig->params [i];
7205
7206                 if (pt->byref) {
7207                         char *arg;
7208                         if (j >= out_len)
7209                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7210
7211                         arg = (char *)mono_array_get (out_args, gpointer, j);
7212                         type = pt->type;
7213
7214                         g_assert (type != MONO_TYPE_VOID);
7215
7216                         if (MONO_TYPE_IS_REFERENCE (pt)) {
7217                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7218                         } else {
7219                                 if (arg) {
7220                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7221                                         size = mono_class_value_size (klass, NULL);
7222                                         if (klass->has_references)
7223                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7224                                         else
7225                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7226                                 } else {
7227                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7228                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7229                                 }
7230                         }
7231
7232                         j++;
7233                 }
7234         }
7235 }
7236
7237 #ifndef DISABLE_REMOTING
7238
7239 /**
7240  * mono_load_remote_field:
7241  * @this: pointer to an object
7242  * @klass: klass of the object containing @field
7243  * @field: the field to load
7244  * @res: a storage to store the result
7245  *
7246  * This method is called by the runtime on attempts to load fields of
7247  * transparent proxy objects. @this points to such TP, @klass is the class of
7248  * the object containing @field. @res is a storage location which can be
7249  * used to store the result.
7250  *
7251  * Returns: an address pointing to the value of field.
7252  */
7253 gpointer
7254 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7255 {
7256         MONO_REQ_GC_UNSAFE_MODE;
7257
7258         MonoError error;
7259
7260         static MonoMethod *getter = NULL;
7261         MonoDomain *domain = mono_domain_get ();
7262         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7263         MonoClass *field_class;
7264         MonoMethodMessage *msg;
7265         MonoArray *out_args;
7266         MonoObject *exc;
7267         char* full_name;
7268
7269         g_assert (mono_object_is_transparent_proxy (this_obj));
7270         g_assert (res != NULL);
7271
7272         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7273                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7274                 return res;
7275         }
7276         
7277         if (!getter) {
7278                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7279                 if (!getter)
7280                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7281         }
7282         
7283         field_class = mono_class_from_mono_type (field->type);
7284
7285         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7286         mono_error_raise_exception (&error); /* FIXME don't raise here */
7287         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7288         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7289         mono_error_raise_exception (&error); /* FIXME don't raise here */
7290         mono_message_init (domain, msg, rm, out_args);
7291
7292         full_name = mono_type_get_full_name (klass);
7293         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7294         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7295         g_free (full_name);
7296
7297         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7298
7299         if (exc) mono_raise_exception ((MonoException *)exc);
7300
7301         if (mono_array_length (out_args) == 0)
7302                 return NULL;
7303
7304         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7305
7306         if (field_class->valuetype) {
7307                 return ((char *)*res) + sizeof (MonoObject);
7308         } else
7309                 return res;
7310 }
7311
7312 /**
7313  * mono_load_remote_field_new:
7314  * @this: 
7315  * @klass: 
7316  * @field:
7317  *
7318  * Missing documentation.
7319  */
7320 MonoObject *
7321 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7322 {
7323         MONO_REQ_GC_UNSAFE_MODE;
7324
7325         MonoError error;
7326
7327         static MonoMethod *getter = NULL;
7328         MonoDomain *domain = mono_domain_get ();
7329         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7330         MonoClass *field_class;
7331         MonoMethodMessage *msg;
7332         MonoArray *out_args;
7333         MonoObject *exc, *res;
7334         char* full_name;
7335
7336         g_assert (mono_object_is_transparent_proxy (this_obj));
7337
7338         field_class = mono_class_from_mono_type (field->type);
7339
7340         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7341                 gpointer val;
7342                 if (field_class->valuetype) {
7343                         res = mono_object_new_checked (domain, field_class, &error);
7344                         mono_error_raise_exception (&error); /* FIXME don't raise here */
7345                         val = ((gchar *) res) + sizeof (MonoObject);
7346                 } else {
7347                         val = &res;
7348                 }
7349                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7350                 return res;
7351         }
7352
7353         if (!getter) {
7354                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7355                 if (!getter)
7356                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7357         }
7358         
7359         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7360         mono_error_raise_exception (&error); /* FIXME don't raise here */
7361         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7362
7363         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7364         mono_error_raise_exception (&error); /* FIXME don't raise here */
7365         mono_message_init (domain, msg, rm, out_args);
7366
7367         full_name = mono_type_get_full_name (klass);
7368         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7369         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7370         g_free (full_name);
7371
7372         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7373
7374         if (exc) mono_raise_exception ((MonoException *)exc);
7375
7376         if (mono_array_length (out_args) == 0)
7377                 res = NULL;
7378         else
7379                 res = mono_array_get (out_args, MonoObject *, 0);
7380
7381         return res;
7382 }
7383
7384 /**
7385  * mono_store_remote_field:
7386  * @this_obj: pointer to an object
7387  * @klass: klass of the object containing @field
7388  * @field: the field to load
7389  * @val: the value/object to store
7390  *
7391  * This method is called by the runtime on attempts to store fields of
7392  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7393  * the object containing @field. @val is the new value to store in @field.
7394  */
7395 void
7396 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7397 {
7398         MONO_REQ_GC_UNSAFE_MODE;
7399
7400         MonoError error;
7401
7402         static MonoMethod *setter = NULL;
7403         MonoDomain *domain = mono_domain_get ();
7404         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7405         MonoClass *field_class;
7406         MonoMethodMessage *msg;
7407         MonoArray *out_args;
7408         MonoObject *exc;
7409         MonoObject *arg;
7410         char* full_name;
7411
7412         g_assert (mono_object_is_transparent_proxy (this_obj));
7413
7414         field_class = mono_class_from_mono_type (field->type);
7415
7416         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7417                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7418                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7419                 return;
7420         }
7421
7422         if (!setter) {
7423                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7424                 if (!setter)
7425                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7426         }
7427
7428         if (field_class->valuetype)
7429                 arg = mono_value_box (domain, field_class, val);
7430         else 
7431                 arg = *((MonoObject **)val);
7432                 
7433
7434         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7435         mono_error_raise_exception (&error); /* FIXME don't raise here */
7436         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7437         mono_error_raise_exception (&error); /* FIXME don't raise here */
7438         mono_message_init (domain, msg, rm, NULL);
7439
7440         full_name = mono_type_get_full_name (klass);
7441         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7442         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7443         mono_array_setref (msg->args, 2, arg);
7444         g_free (full_name);
7445
7446         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7447
7448         if (exc) mono_raise_exception ((MonoException *)exc);
7449 }
7450
7451 /**
7452  * mono_store_remote_field_new:
7453  * @this_obj:
7454  * @klass:
7455  * @field:
7456  * @arg:
7457  *
7458  * Missing documentation
7459  */
7460 void
7461 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7462 {
7463         MONO_REQ_GC_UNSAFE_MODE;
7464
7465         MonoError error;
7466
7467         static MonoMethod *setter = NULL;
7468         MonoDomain *domain = mono_domain_get ();
7469         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7470         MonoClass *field_class;
7471         MonoMethodMessage *msg;
7472         MonoArray *out_args;
7473         MonoObject *exc;
7474         char* full_name;
7475
7476         g_assert (mono_object_is_transparent_proxy (this_obj));
7477
7478         field_class = mono_class_from_mono_type (field->type);
7479
7480         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7481                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7482                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7483                 return;
7484         }
7485
7486         if (!setter) {
7487                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7488                 if (!setter)
7489                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7490         }
7491
7492         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7493         mono_error_raise_exception (&error); /* FIXME don't raise here */
7494         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7495         mono_error_raise_exception (&error); /* FIXME don't raise here */
7496         mono_message_init (domain, msg, rm, NULL);
7497
7498         full_name = mono_type_get_full_name (klass);
7499         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7500         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7501         mono_array_setref (msg->args, 2, arg);
7502         g_free (full_name);
7503
7504         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7505
7506         if (exc) mono_raise_exception ((MonoException *)exc);
7507 }
7508 #endif
7509
7510 /*
7511  * mono_create_ftnptr:
7512  *
7513  *   Given a function address, create a function descriptor for it.
7514  * This is only needed on some platforms.
7515  */
7516 gpointer
7517 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7518 {
7519         return callbacks.create_ftnptr (domain, addr);
7520 }
7521
7522 /*
7523  * mono_get_addr_from_ftnptr:
7524  *
7525  *   Given a pointer to a function descriptor, return the function address.
7526  * This is only needed on some platforms.
7527  */
7528 gpointer
7529 mono_get_addr_from_ftnptr (gpointer descr)
7530 {
7531         return callbacks.get_addr_from_ftnptr (descr);
7532 }       
7533
7534 /**
7535  * mono_string_chars:
7536  * @s: a MonoString
7537  *
7538  * Returns a pointer to the UCS16 characters stored in the MonoString
7539  */
7540 gunichar2 *
7541 mono_string_chars (MonoString *s)
7542 {
7543         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7544
7545         return s->chars;
7546 }
7547
7548 /**
7549  * mono_string_length:
7550  * @s: MonoString
7551  *
7552  * Returns the lenght in characters of the string
7553  */
7554 int
7555 mono_string_length (MonoString *s)
7556 {
7557         MONO_REQ_GC_UNSAFE_MODE;
7558
7559         return s->length;
7560 }
7561
7562 /**
7563  * mono_array_length:
7564  * @array: a MonoArray*
7565  *
7566  * Returns the total number of elements in the array. This works for
7567  * both vectors and multidimensional arrays.
7568  */
7569 uintptr_t
7570 mono_array_length (MonoArray *array)
7571 {
7572         MONO_REQ_GC_UNSAFE_MODE;
7573
7574         return array->max_length;
7575 }
7576
7577 /**
7578  * mono_array_addr_with_size:
7579  * @array: a MonoArray*
7580  * @size: size of the array elements
7581  * @idx: index into the array
7582  *
7583  * Use this function to obtain the address for the @idx item on the
7584  * @array containing elements of size @size.
7585  *
7586  * This method performs no bounds checking or type checking.
7587  *
7588  * Returns the address of the @idx element in the array.
7589  */
7590 char*
7591 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7592 {
7593         MONO_REQ_GC_UNSAFE_MODE;
7594
7595         return ((char*)(array)->vector) + size * idx;
7596 }
7597
7598
7599 MonoArray *
7600 mono_glist_to_array (GList *list, MonoClass *eclass) 
7601 {
7602         MonoDomain *domain = mono_domain_get ();
7603         MonoArray *res;
7604         int len, i;
7605
7606         if (!list)
7607                 return NULL;
7608
7609         len = g_list_length (list);
7610         res = mono_array_new (domain, eclass, len);
7611
7612         for (i = 0; list; list = list->next, i++)
7613                 mono_array_set (res, gpointer, i, list->data);
7614
7615         return res;
7616 }
7617
7618 #if NEVER_DEFINED
7619 /*
7620  * The following section is purely to declare prototypes and
7621  * document the API, as these C files are processed by our
7622  * tool
7623  */
7624
7625 /**
7626  * mono_array_set:
7627  * @array: array to alter
7628  * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7629  * @index: index into the array
7630  * @value: value to set
7631  *
7632  * Value Type version: This sets the @index's element of the @array
7633  * with elements of size sizeof(type) to the provided @value.
7634  *
7635  * This macro does not attempt to perform type checking or bounds checking.
7636  *
7637  * Use this to set value types in a `MonoArray`.
7638  */
7639 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7640 {
7641 }
7642
7643 /**
7644  * mono_array_setref:
7645  * @array: array to alter
7646  * @index: index into the array
7647  * @value: value to set
7648  *
7649  * Reference Type version: This sets the @index's element of the
7650  * @array with elements of size sizeof(type) to the provided @value.
7651  *
7652  * This macro does not attempt to perform type checking or bounds checking.
7653  *
7654  * Use this to reference types in a `MonoArray`.
7655  */
7656 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7657 {
7658 }
7659
7660 /**
7661  * mono_array_get:
7662  * @array: array on which to operate on
7663  * @element_type: C element type (example: MonoString *, int, MonoObject *)
7664  * @index: index into the array
7665  *
7666  * Use this macro to retrieve the @index element of an @array and
7667  * extract the value assuming that the elements of the array match
7668  * the provided type value.
7669  *
7670  * This method can be used with both arrays holding value types and
7671  * reference types.   For reference types, the @type parameter should
7672  * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7673  *
7674  * This macro does not attempt to perform type checking or bounds checking.
7675  *
7676  * Returns: The element at the @index position in the @array.
7677  */
7678 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
7679 {
7680 }
7681 #endif
7682