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