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