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