Merge pull request #2748 from lambdageek/dev/monoerror-mono_value_box
[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
6000  */
6001 MonoObject *
6002 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6003 {
6004         MONO_REQ_GC_UNSAFE_MODE;
6005
6006         if (!klass->inited)
6007                 mono_class_init (klass);
6008
6009         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
6010                 return mono_object_isinst_mbyref (obj, klass);
6011
6012         if (!obj)
6013                 return NULL;
6014
6015         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6016 }
6017
6018 MonoObject *
6019 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6020 {
6021         MONO_REQ_GC_UNSAFE_MODE;
6022
6023         MonoError error;
6024         MonoVTable *vt;
6025
6026         if (!obj)
6027                 return NULL;
6028
6029         vt = obj->vtable;
6030         
6031         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6032                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6033                         return obj;
6034                 }
6035
6036                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6037                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6038                         return obj;
6039         } else {
6040                 MonoClass *oklass = vt->klass;
6041                 if (mono_class_is_transparent_proxy (oklass))
6042                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6043
6044                 mono_class_setup_supertypes (klass);    
6045                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6046                         return obj;
6047         }
6048 #ifndef DISABLE_REMOTING
6049         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
6050         {
6051                 MonoDomain *domain = mono_domain_get ();
6052                 MonoObject *res;
6053                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6054                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6055                 MonoMethod *im = NULL;
6056                 gpointer pa [2];
6057
6058                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6059                 if (!im)
6060                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6061                 im = mono_object_get_virtual_method (rp, im);
6062                 g_assert (im);
6063         
6064                 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
6065                 mono_error_raise_exception (&error); /* FIXME don't raise here */
6066                 pa [1] = obj;
6067
6068                 res = mono_runtime_invoke_checked (im, rp, pa, &error);
6069                 mono_error_raise_exception (&error); /* FIXME don't raise here */
6070
6071                 if (*(MonoBoolean *) mono_object_unbox(res)) {
6072                         /* Update the vtable of the remote type, so it can safely cast to this new type */
6073                         mono_upgrade_remote_class (domain, obj, klass);
6074                         return obj;
6075                 }
6076         }
6077 #endif /* DISABLE_REMOTING */
6078         return NULL;
6079 }
6080
6081 /**
6082  * mono_object_castclass_mbyref:
6083  * @obj: an object
6084  * @klass: a pointer to a class 
6085  *
6086  * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6087  */
6088 MonoObject *
6089 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6090 {
6091         MONO_REQ_GC_UNSAFE_MODE;
6092
6093         if (!obj) return NULL;
6094         if (mono_object_isinst_mbyref (obj, klass)) return obj;
6095                 
6096         return NULL;
6097 }
6098
6099 typedef struct {
6100         MonoDomain *orig_domain;
6101         MonoString *ins;
6102         MonoString *res;
6103 } LDStrInfo;
6104
6105 static void
6106 str_lookup (MonoDomain *domain, gpointer user_data)
6107 {
6108         MONO_REQ_GC_UNSAFE_MODE;
6109
6110         LDStrInfo *info = (LDStrInfo *)user_data;
6111         if (info->res || domain == info->orig_domain)
6112                 return;
6113         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6114 }
6115
6116 static MonoString*
6117 mono_string_get_pinned (MonoString *str, MonoError *error)
6118 {
6119         MONO_REQ_GC_UNSAFE_MODE;
6120
6121         mono_error_init (error);
6122
6123         /* We only need to make a pinned version of a string if this is a moving GC */
6124         if (!mono_gc_is_moving ())
6125                 return str;
6126         int size;
6127         MonoString *news;
6128         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6129         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6130         if (news) {
6131                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6132                 news->length = mono_string_length (str);
6133         } else {
6134                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6135         }
6136         return news;
6137 }
6138
6139 static MonoString*
6140 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6141 {
6142         MONO_REQ_GC_UNSAFE_MODE;
6143
6144         MonoGHashTable *ldstr_table;
6145         MonoString *s, *res;
6146         MonoDomain *domain;
6147         
6148         mono_error_init (error);
6149
6150         domain = ((MonoObject *)str)->vtable->domain;
6151         ldstr_table = domain->ldstr_table;
6152         ldstr_lock ();
6153         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6154         if (res) {
6155                 ldstr_unlock ();
6156                 return res;
6157         }
6158         if (insert) {
6159                 /* Allocate outside the lock */
6160                 ldstr_unlock ();
6161                 s = mono_string_get_pinned (str, error);
6162                 return_val_if_nok (error, NULL);
6163                 if (s) {
6164                         ldstr_lock ();
6165                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6166                         if (res) {
6167                                 ldstr_unlock ();
6168                                 return res;
6169                         }
6170                         mono_g_hash_table_insert (ldstr_table, s, s);
6171                         ldstr_unlock ();
6172                 }
6173                 return s;
6174         } else {
6175                 LDStrInfo ldstr_info;
6176                 ldstr_info.orig_domain = domain;
6177                 ldstr_info.ins = str;
6178                 ldstr_info.res = NULL;
6179
6180                 mono_domain_foreach (str_lookup, &ldstr_info);
6181                 if (ldstr_info.res) {
6182                         /* 
6183                          * the string was already interned in some other domain:
6184                          * intern it in the current one as well.
6185                          */
6186                         mono_g_hash_table_insert (ldstr_table, str, str);
6187                         ldstr_unlock ();
6188                         return str;
6189                 }
6190         }
6191         ldstr_unlock ();
6192         return NULL;
6193 }
6194
6195 /**
6196  * mono_string_is_interned:
6197  * @o: String to probe
6198  *
6199  * Returns whether the string has been interned.
6200  */
6201 MonoString*
6202 mono_string_is_interned (MonoString *o)
6203 {
6204         MonoError error;
6205         MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6206         /* This function does not fail. */
6207         mono_error_assert_ok (&error);
6208         return result;
6209 }
6210
6211 /**
6212  * mono_string_intern:
6213  * @o: String to intern
6214  *
6215  * Interns the string passed.  
6216  * Returns: The interned string.
6217  */
6218 MonoString*
6219 mono_string_intern (MonoString *str)
6220 {
6221         MonoError error;
6222         MonoString *result = mono_string_intern_checked (str, &error);
6223         mono_error_assert_ok (&error);
6224         return result;
6225 }
6226
6227 /**
6228  * mono_string_intern_checked:
6229  * @o: String to intern
6230  * @error: set on error.
6231  *
6232  * Interns the string passed.
6233  * Returns: The interned string.  On failure returns NULL and sets @error
6234  */
6235 MonoString*
6236 mono_string_intern_checked (MonoString *str, MonoError *error)
6237 {
6238         MONO_REQ_GC_UNSAFE_MODE;
6239
6240         mono_error_init (error);
6241
6242         return mono_string_is_interned_lookup (str, TRUE, error);
6243 }
6244
6245 /**
6246  * mono_ldstr:
6247  * @domain: the domain where the string will be used.
6248  * @image: a metadata context
6249  * @idx: index into the user string table.
6250  * 
6251  * Implementation for the ldstr opcode.
6252  * Returns: a loaded string from the @image/@idx combination.
6253  */
6254 MonoString*
6255 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6256 {
6257         MONO_REQ_GC_UNSAFE_MODE;
6258
6259         if (image->dynamic) {
6260                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6261                 return str;
6262         } else {
6263                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6264                         return NULL; /*FIXME we should probably be raising an exception here*/
6265                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6266         }
6267 }
6268
6269 /**
6270  * mono_ldstr_metadata_sig
6271  * @domain: the domain for the string
6272  * @sig: the signature of a metadata string
6273  *
6274  * Returns: a MonoString for a string stored in the metadata
6275  */
6276 static MonoString*
6277 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6278 {
6279         MONO_REQ_GC_UNSAFE_MODE;
6280
6281         MonoError error;
6282         const char *str = sig;
6283         MonoString *o, *interned;
6284         size_t len2;
6285
6286         len2 = mono_metadata_decode_blob_size (str, &str);
6287         len2 >>= 1;
6288
6289         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6290         mono_error_raise_exception (&error); /* FIXME don't raise here */
6291 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6292         {
6293                 int i;
6294                 guint16 *p2 = (guint16*)mono_string_chars (o);
6295                 for (i = 0; i < len2; ++i) {
6296                         *p2 = GUINT16_FROM_LE (*p2);
6297                         ++p2;
6298                 }
6299         }
6300 #endif
6301         ldstr_lock ();
6302         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6303         ldstr_unlock ();
6304         if (interned)
6305                 return interned; /* o will get garbage collected */
6306
6307         o = mono_string_get_pinned (o, &error);
6308         mono_error_raise_exception (&error); /* FIXME don't raise here */
6309         if (o) {
6310                 ldstr_lock ();
6311                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6312                 if (!interned) {
6313                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6314                         interned = o;
6315                 }
6316                 ldstr_unlock ();
6317         }
6318
6319         return interned;
6320 }
6321
6322 /**
6323  * mono_string_to_utf8:
6324  * @s: a System.String
6325  *
6326  * Returns the UTF8 representation for @s.
6327  * The resulting buffer needs to be freed with mono_free().
6328  *
6329  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6330  */
6331 char *
6332 mono_string_to_utf8 (MonoString *s)
6333 {
6334         MONO_REQ_GC_UNSAFE_MODE;
6335
6336         MonoError error;
6337         char *result = mono_string_to_utf8_checked (s, &error);
6338         
6339         if (!mono_error_ok (&error))
6340                 mono_error_raise_exception (&error);
6341         return result;
6342 }
6343
6344 /**
6345  * mono_string_to_utf8_checked:
6346  * @s: a System.String
6347  * @error: a MonoError.
6348  * 
6349  * Converts a MonoString to its UTF8 representation. May fail; check 
6350  * @error to determine whether the conversion was successful.
6351  * The resulting buffer should be freed with mono_free().
6352  */
6353 char *
6354 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6355 {
6356         MONO_REQ_GC_UNSAFE_MODE;
6357
6358         long written = 0;
6359         char *as;
6360         GError *gerror = NULL;
6361
6362         mono_error_init (error);
6363
6364         if (s == NULL)
6365                 return NULL;
6366
6367         if (!s->length)
6368                 return g_strdup ("");
6369
6370         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6371         if (gerror) {
6372                 mono_error_set_argument (error, "string", "%s", gerror->message);
6373                 g_error_free (gerror);
6374                 return NULL;
6375         }
6376         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6377         if (s->length > written) {
6378                 /* allocate the total length and copy the part of the string that has been converted */
6379                 char *as2 = (char *)g_malloc0 (s->length);
6380                 memcpy (as2, as, written);
6381                 g_free (as);
6382                 as = as2;
6383         }
6384
6385         return as;
6386 }
6387
6388 /**
6389  * mono_string_to_utf8_ignore:
6390  * @s: a MonoString
6391  *
6392  * Converts a MonoString to its UTF8 representation. Will ignore
6393  * invalid surrogate pairs.
6394  * The resulting buffer should be freed with mono_free().
6395  * 
6396  */
6397 char *
6398 mono_string_to_utf8_ignore (MonoString *s)
6399 {
6400         MONO_REQ_GC_UNSAFE_MODE;
6401
6402         long written = 0;
6403         char *as;
6404
6405         if (s == NULL)
6406                 return NULL;
6407
6408         if (!s->length)
6409                 return g_strdup ("");
6410
6411         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6412
6413         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6414         if (s->length > written) {
6415                 /* allocate the total length and copy the part of the string that has been converted */
6416                 char *as2 = (char *)g_malloc0 (s->length);
6417                 memcpy (as2, as, written);
6418                 g_free (as);
6419                 as = as2;
6420         }
6421
6422         return as;
6423 }
6424
6425 /**
6426  * mono_string_to_utf8_image_ignore:
6427  * @s: a System.String
6428  *
6429  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6430  */
6431 char *
6432 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6433 {
6434         MONO_REQ_GC_UNSAFE_MODE;
6435
6436         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6437 }
6438
6439 /**
6440  * mono_string_to_utf8_mp_ignore:
6441  * @s: a System.String
6442  *
6443  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6444  */
6445 char *
6446 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6447 {
6448         MONO_REQ_GC_UNSAFE_MODE;
6449
6450         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6451 }
6452
6453
6454 /**
6455  * mono_string_to_utf16:
6456  * @s: a MonoString
6457  *
6458  * Return an null-terminated array of the utf-16 chars
6459  * contained in @s. The result must be freed with g_free().
6460  * This is a temporary helper until our string implementation
6461  * is reworked to always include the null terminating char.
6462  */
6463 mono_unichar2*
6464 mono_string_to_utf16 (MonoString *s)
6465 {
6466         MONO_REQ_GC_UNSAFE_MODE;
6467
6468         char *as;
6469
6470         if (s == NULL)
6471                 return NULL;
6472
6473         as = (char *)g_malloc ((s->length * 2) + 2);
6474         as [(s->length * 2)] = '\0';
6475         as [(s->length * 2) + 1] = '\0';
6476
6477         if (!s->length) {
6478                 return (gunichar2 *)(as);
6479         }
6480         
6481         memcpy (as, mono_string_chars(s), s->length * 2);
6482         return (gunichar2 *)(as);
6483 }
6484
6485 /**
6486  * mono_string_to_utf32:
6487  * @s: a MonoString
6488  *
6489  * Return an null-terminated array of the UTF-32 (UCS-4) chars
6490  * contained in @s. The result must be freed with g_free().
6491  */
6492 mono_unichar4*
6493 mono_string_to_utf32 (MonoString *s)
6494 {
6495         MONO_REQ_GC_UNSAFE_MODE;
6496
6497         mono_unichar4 *utf32_output = NULL; 
6498         GError *error = NULL;
6499         glong items_written;
6500         
6501         if (s == NULL)
6502                 return NULL;
6503                 
6504         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6505         
6506         if (error)
6507                 g_error_free (error);
6508
6509         return utf32_output;
6510 }
6511
6512 /**
6513  * mono_string_from_utf16:
6514  * @data: the UTF16 string (LPWSTR) to convert
6515  *
6516  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6517  *
6518  * Returns: a MonoString.
6519  */
6520 MonoString *
6521 mono_string_from_utf16 (gunichar2 *data)
6522 {
6523         MONO_REQ_GC_UNSAFE_MODE;
6524
6525         MonoError error;
6526         MonoString *res = NULL;
6527         MonoDomain *domain = mono_domain_get ();
6528         int len = 0;
6529
6530         if (!data)
6531                 return NULL;
6532
6533         while (data [len]) len++;
6534
6535         res = mono_string_new_utf16_checked (domain, data, len, &error);
6536         mono_error_raise_exception (&error); /* FIXME don't raise here */
6537         return res;
6538 }
6539
6540 /**
6541  * mono_string_from_utf32:
6542  * @data: the UTF32 string (LPWSTR) to convert
6543  *
6544  * Converts a UTF32 (UCS-4)to a MonoString.
6545  *
6546  * Returns: a MonoString.
6547  */
6548 MonoString *
6549 mono_string_from_utf32 (mono_unichar4 *data)
6550 {
6551         MONO_REQ_GC_UNSAFE_MODE;
6552
6553         MonoString* result = NULL;
6554         mono_unichar2 *utf16_output = NULL;
6555         GError *error = NULL;
6556         glong items_written;
6557         int len = 0;
6558
6559         if (!data)
6560                 return NULL;
6561
6562         while (data [len]) len++;
6563
6564         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6565
6566         if (error)
6567                 g_error_free (error);
6568
6569         result = mono_string_from_utf16 (utf16_output);
6570         g_free (utf16_output);
6571         return result;
6572 }
6573
6574 static char *
6575 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6576 {
6577         MONO_REQ_GC_UNSAFE_MODE;
6578
6579         char *r;
6580         char *mp_s;
6581         int len;
6582
6583         if (ignore_error) {
6584                 r = mono_string_to_utf8_ignore (s);
6585         } else {
6586                 r = mono_string_to_utf8_checked (s, error);
6587                 if (!mono_error_ok (error))
6588                         return NULL;
6589         }
6590
6591         if (!mp && !image)
6592                 return r;
6593
6594         len = strlen (r) + 1;
6595         if (mp)
6596                 mp_s = (char *)mono_mempool_alloc (mp, len);
6597         else
6598                 mp_s = (char *)mono_image_alloc (image, len);
6599
6600         memcpy (mp_s, r, len);
6601
6602         g_free (r);
6603
6604         return mp_s;
6605 }
6606
6607 /**
6608  * mono_string_to_utf8_image:
6609  * @s: a System.String
6610  *
6611  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6612  */
6613 char *
6614 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6615 {
6616         MONO_REQ_GC_UNSAFE_MODE;
6617
6618         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6619 }
6620
6621 /**
6622  * mono_string_to_utf8_mp:
6623  * @s: a System.String
6624  *
6625  * Same as mono_string_to_utf8, but allocate the string from a mempool.
6626  */
6627 char *
6628 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6629 {
6630         MONO_REQ_GC_UNSAFE_MODE;
6631
6632         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6633 }
6634
6635
6636 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6637
6638 void
6639 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6640 {
6641         eh_callbacks = *cbs;
6642 }
6643
6644 MonoRuntimeExceptionHandlingCallbacks *
6645 mono_get_eh_callbacks (void)
6646 {
6647         return &eh_callbacks;
6648 }
6649
6650 /**
6651  * mono_raise_exception:
6652  * @ex: exception object
6653  *
6654  * Signal the runtime that the exception @ex has been raised in unmanaged code.
6655  */
6656 void
6657 mono_raise_exception (MonoException *ex) 
6658 {
6659         MONO_REQ_GC_UNSAFE_MODE;
6660
6661         /*
6662          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6663          * that will cause gcc to omit the function epilog, causing problems when
6664          * the JIT tries to walk the stack, since the return address on the stack
6665          * will point into the next function in the executable, not this one.
6666          */     
6667         eh_callbacks.mono_raise_exception (ex);
6668 }
6669
6670 void
6671 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
6672 {
6673         MONO_REQ_GC_UNSAFE_MODE;
6674
6675         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6676 }
6677
6678 /**
6679  * mono_wait_handle_new:
6680  * @domain: Domain where the object will be created
6681  * @handle: Handle for the wait handle
6682  *
6683  * Returns: A new MonoWaitHandle created in the given domain for the given handle
6684  */
6685 MonoWaitHandle *
6686 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6687 {
6688         MONO_REQ_GC_UNSAFE_MODE;
6689
6690         MonoError error;
6691         MonoWaitHandle *res;
6692         gpointer params [1];
6693         static MonoMethod *handle_set;
6694
6695         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6696         mono_error_raise_exception (&error); /* FIXME don't raise here */
6697
6698         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
6699         if (!handle_set)
6700                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6701
6702         params [0] = &handle;
6703
6704         mono_runtime_invoke_checked (handle_set, res, params, &error);
6705         mono_error_raise_exception (&error); /* FIXME don't raise here */
6706
6707         return res;
6708 }
6709
6710 HANDLE
6711 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6712 {
6713         MONO_REQ_GC_UNSAFE_MODE;
6714
6715         static MonoClassField *f_safe_handle = NULL;
6716         MonoSafeHandle *sh;
6717
6718         if (!f_safe_handle) {
6719                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6720                 g_assert (f_safe_handle);
6721         }
6722
6723         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6724         return sh->handle;
6725 }
6726
6727
6728 static MonoObject*
6729 mono_runtime_capture_context (MonoDomain *domain)
6730 {
6731         MONO_REQ_GC_UNSAFE_MODE;
6732
6733         RuntimeInvokeFunction runtime_invoke;
6734
6735         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6736                 MonoMethod *method = mono_get_context_capture_method ();
6737                 MonoMethod *wrapper;
6738                 if (!method)
6739                         return NULL;
6740                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6741                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6742                 domain->capture_context_method = mono_compile_method (method);
6743         }
6744
6745         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6746
6747         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6748 }
6749 /**
6750  * mono_async_result_new:
6751  * @domain:domain where the object will be created.
6752  * @handle: wait handle.
6753  * @state: state to pass to AsyncResult
6754  * @data: C closure data.
6755  *
6756  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6757  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6758  *
6759  */
6760 MonoAsyncResult *
6761 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6762 {
6763         MONO_REQ_GC_UNSAFE_MODE;
6764
6765         MonoError error;
6766         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6767         mono_error_raise_exception (&error); /* FIXME don't raise here */
6768         MonoObject *context = mono_runtime_capture_context (domain);
6769         /* we must capture the execution context from the original thread */
6770         if (context) {
6771                 MONO_OBJECT_SETREF (res, execution_context, context);
6772                 /* note: result may be null if the flow is suppressed */
6773         }
6774
6775         res->data = (void **)data;
6776         MONO_OBJECT_SETREF (res, object_data, object_data);
6777         MONO_OBJECT_SETREF (res, async_state, state);
6778         if (handle != NULL)
6779                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6780
6781         res->sync_completed = FALSE;
6782         res->completed = FALSE;
6783
6784         return res;
6785 }
6786
6787 MonoObject *
6788 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6789 {
6790         MONO_REQ_GC_UNSAFE_MODE;
6791
6792         MonoError error;
6793         MonoAsyncCall *ac;
6794         MonoObject *res;
6795
6796         g_assert (ares);
6797         g_assert (ares->async_delegate);
6798
6799         ac = (MonoAsyncCall*) ares->object_data;
6800         if (!ac) {
6801                 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6802         } else {
6803                 gpointer wait_event = NULL;
6804
6805                 ac->msg->exc = NULL;
6806                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6807                 MONO_OBJECT_SETREF (ac, res, res);
6808
6809                 mono_monitor_enter ((MonoObject*) ares);
6810                 ares->completed = 1;
6811                 if (ares->handle)
6812                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6813                 mono_monitor_exit ((MonoObject*) ares);
6814
6815                 if (wait_event != NULL)
6816                         SetEvent (wait_event);
6817
6818                 if (ac->cb_method) {
6819                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6820                         mono_error_raise_exception (&error);
6821                 }
6822         }
6823
6824         return res;
6825 }
6826
6827 void
6828 mono_message_init (MonoDomain *domain,
6829                    MonoMethodMessage *this_obj, 
6830                    MonoReflectionMethod *method,
6831                    MonoArray *out_args)
6832 {
6833         MONO_REQ_GC_UNSAFE_MODE;
6834
6835         static MonoClass *object_array_klass;
6836         static MonoClass *byte_array_klass;
6837         static MonoClass *string_array_klass;
6838         MonoError error;
6839         MonoMethodSignature *sig = mono_method_signature (method->method);
6840         MonoString *name;
6841         MonoArray *arr;
6842         int i, j;
6843         char **names;
6844         guint8 arg_type;
6845
6846         if (!object_array_klass) {
6847                 MonoClass *klass;
6848
6849                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6850                 g_assert (klass);
6851                 byte_array_klass = klass;
6852
6853                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6854                 g_assert (klass);
6855                 string_array_klass = klass;
6856
6857                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6858                 g_assert (klass);
6859
6860                 mono_atomic_store_release (&object_array_klass, klass);
6861         }
6862
6863         MONO_OBJECT_SETREF (this_obj, method, method);
6864
6865         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6866         mono_error_raise_exception (&error); /* FIXME don't raise here */
6867
6868         MONO_OBJECT_SETREF (this_obj, args, arr);
6869
6870         arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6871         mono_error_raise_exception (&error); /* FIXME don't raise here */
6872
6873         MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6874
6875         this_obj->async_result = NULL;
6876         this_obj->call_type = CallType_Sync;
6877
6878         names = g_new (char *, sig->param_count);
6879         mono_method_get_param_names (method->method, (const char **) names);
6880
6881         arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6882         mono_error_raise_exception (&error); /* FIXME don't raise here */
6883
6884         MONO_OBJECT_SETREF (this_obj, names, arr);
6885         
6886         for (i = 0; i < sig->param_count; i++) {
6887                 name = mono_string_new (domain, names [i]);
6888                 mono_array_setref (this_obj->names, i, name);   
6889         }
6890
6891         g_free (names);
6892         for (i = 0, j = 0; i < sig->param_count; i++) {
6893                 if (sig->params [i]->byref) {
6894                         if (out_args) {
6895                                 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6896                                 mono_array_setref (this_obj->args, i, arg);
6897                                 j++;
6898                         }
6899                         arg_type = 2;
6900                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6901                                 arg_type |= 1;
6902                 } else {
6903                         arg_type = 1;
6904                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6905                                 arg_type |= 4;
6906                 }
6907                 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6908         }
6909 }
6910
6911 #ifndef DISABLE_REMOTING
6912 /**
6913  * mono_remoting_invoke:
6914  * @real_proxy: pointer to a RealProxy object
6915  * @msg: The MonoMethodMessage to execute
6916  * @exc: used to store exceptions
6917  * @out_args: used to store output arguments
6918  *
6919  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6920  * IMessage interface and it is not trivial to extract results from there. So
6921  * we call an helper method PrivateInvoke instead of calling
6922  * RealProxy::Invoke() directly.
6923  *
6924  * Returns: the result object.
6925  */
6926 MonoObject *
6927 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
6928 {
6929         MONO_REQ_GC_UNSAFE_MODE;
6930
6931         MonoObject *o;
6932         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6933         gpointer pa [4];
6934
6935         g_assert (exc);
6936
6937         mono_error_init (error);
6938
6939         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6940
6941         if (!im) {
6942                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6943                 if (!im) {
6944                         mono_error_set_not_supported (error, "Linked away.");
6945                         return NULL;
6946                 }
6947                 real_proxy->vtable->domain->private_invoke_method = im;
6948         }
6949
6950         pa [0] = real_proxy;
6951         pa [1] = msg;
6952         pa [2] = exc;
6953         pa [3] = out_args;
6954
6955         o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
6956         return_val_if_nok (error, NULL);
6957
6958         return o;
6959 }
6960 #endif
6961
6962 MonoObject *
6963 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6964                      MonoObject **exc, MonoArray **out_args) 
6965 {
6966         MONO_REQ_GC_UNSAFE_MODE;
6967
6968         static MonoClass *object_array_klass;
6969         MonoError error;
6970         MonoDomain *domain; 
6971         MonoMethod *method;
6972         MonoMethodSignature *sig;
6973         MonoObject *ret;
6974         MonoArray *arr;
6975         int i, j, outarg_count = 0;
6976
6977 #ifndef DISABLE_REMOTING
6978         if (target && mono_object_is_transparent_proxy (target)) {
6979                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6980                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6981                         target = tp->rp->unwrapped_server;
6982                 } else {
6983                         ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
6984                         mono_error_raise_exception (&error); /* FIXME don't raise here */
6985
6986                         return ret;
6987                 }
6988         }
6989 #endif
6990
6991         domain = mono_domain_get (); 
6992         method = msg->method->method;
6993         sig = mono_method_signature (method);
6994
6995         for (i = 0; i < sig->param_count; i++) {
6996                 if (sig->params [i]->byref) 
6997                         outarg_count++;
6998         }
6999
7000         if (!object_array_klass) {
7001                 MonoClass *klass;
7002
7003                 klass = mono_array_class_get (mono_defaults.object_class, 1);
7004                 g_assert (klass);
7005
7006                 mono_memory_barrier ();
7007                 object_array_klass = klass;
7008         }
7009
7010         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
7011         mono_error_raise_exception (&error); /* FIXME don't raise here */
7012
7013         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7014         *exc = NULL;
7015
7016         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
7017
7018         for (i = 0, j = 0; i < sig->param_count; i++) {
7019                 if (sig->params [i]->byref) {
7020                         MonoObject* arg;
7021                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7022                         mono_array_setref (*out_args, j, arg);
7023                         j++;
7024                 }
7025         }
7026
7027         return ret;
7028 }
7029
7030 /**
7031  * mono_object_to_string:
7032  * @obj: The object
7033  * @exc: Any exception thrown by ToString (). May be NULL.
7034  *
7035  * Returns: the result of calling ToString () on an object.
7036  */
7037 MonoString *
7038 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7039 {
7040         MONO_REQ_GC_UNSAFE_MODE;
7041
7042         static MonoMethod *to_string = NULL;
7043         MonoError error;
7044         MonoMethod *method;
7045         MonoString *s;
7046         void *target = obj;
7047
7048         g_assert (obj);
7049
7050         if (!to_string)
7051                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7052
7053         method = mono_object_get_virtual_method (obj, to_string);
7054
7055         // Unbox value type if needed
7056         if (mono_class_is_valuetype (mono_method_get_class (method))) {
7057                 target = mono_object_unbox (obj);
7058         }
7059
7060         if (exc) {
7061                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7062                 if (*exc == NULL && !mono_error_ok (&error))
7063                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7064                 else
7065                         mono_error_cleanup (&error);
7066         } else {
7067                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7068                 mono_error_raise_exception (&error); /* FIXME don't raise here */
7069         }
7070
7071         return s;
7072 }
7073
7074 /**
7075  * mono_print_unhandled_exception:
7076  * @exc: The exception
7077  *
7078  * Prints the unhandled exception.
7079  */
7080 void
7081 mono_print_unhandled_exception (MonoObject *exc)
7082 {
7083         MONO_REQ_GC_UNSAFE_MODE;
7084
7085         MonoString * str;
7086         char *message = (char*)"";
7087         gboolean free_message = FALSE;
7088         MonoError error;
7089
7090         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7091                 message = g_strdup ("OutOfMemoryException");
7092                 free_message = TRUE;
7093         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7094                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7095                 free_message = TRUE;
7096         } else {
7097                 
7098                 if (((MonoException*)exc)->native_trace_ips) {
7099                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
7100                         free_message = TRUE;
7101                 } else {
7102                         MonoObject *other_exc = NULL;
7103                         str = mono_object_to_string (exc, &other_exc);
7104                         if (other_exc) {
7105                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7106                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7107                                 
7108                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7109                                         original_backtrace, nested_backtrace);
7110
7111                                 g_free (original_backtrace);
7112                                 g_free (nested_backtrace);
7113                                 free_message = TRUE;
7114                         } else if (str) {
7115                                 message = mono_string_to_utf8_checked (str, &error);
7116                                 if (!mono_error_ok (&error)) {
7117                                         mono_error_cleanup (&error);
7118                                         message = (char *) "";
7119                                 } else {
7120                                         free_message = TRUE;
7121                                 }
7122                         }
7123                 }
7124         }
7125
7126         /*
7127          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7128          *         exc->vtable->klass->name, message);
7129          */
7130         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7131         
7132         if (free_message)
7133                 g_free (message);
7134 }
7135
7136 /**
7137  * mono_delegate_ctor:
7138  * @this: pointer to an uninitialized delegate object
7139  * @target: target object
7140  * @addr: pointer to native code
7141  * @method: method
7142  *
7143  * Initialize a delegate and sets a specific method, not the one
7144  * associated with addr.  This is useful when sharing generic code.
7145  * In that case addr will most probably not be associated with the
7146  * correct instantiation of the method.
7147  */
7148 void
7149 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7150 {
7151         MONO_REQ_GC_UNSAFE_MODE;
7152
7153         MonoDelegate *delegate = (MonoDelegate *)this_obj;
7154
7155         g_assert (this_obj);
7156         g_assert (addr);
7157
7158         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7159
7160         if (method)
7161                 delegate->method = method;
7162
7163         mono_stats.delegate_creations++;
7164
7165 #ifndef DISABLE_REMOTING
7166         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7167                 g_assert (method);
7168                 method = mono_marshal_get_remoting_invoke (method);
7169                 delegate->method_ptr = mono_compile_method (method);
7170                 MONO_OBJECT_SETREF (delegate, target, target);
7171         } else
7172 #endif
7173         {
7174                 delegate->method_ptr = addr;
7175                 MONO_OBJECT_SETREF (delegate, target, target);
7176         }
7177
7178         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7179         if (callbacks.init_delegate)
7180                 callbacks.init_delegate (delegate);
7181 }
7182
7183 /**
7184  * mono_delegate_ctor:
7185  * @this: pointer to an uninitialized delegate object
7186  * @target: target object
7187  * @addr: pointer to native code
7188  *
7189  * This is used to initialize a delegate.
7190  */
7191 void
7192 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7193 {
7194         MONO_REQ_GC_UNSAFE_MODE;
7195
7196         MonoDomain *domain = mono_domain_get ();
7197         MonoJitInfo *ji;
7198         MonoMethod *method = NULL;
7199
7200         g_assert (addr);
7201
7202         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7203         /* Shared code */
7204         if (!ji && domain != mono_get_root_domain ())
7205                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7206         if (ji) {
7207                 method = mono_jit_info_get_method (ji);
7208                 g_assert (!method->klass->generic_container);
7209         }
7210
7211         mono_delegate_ctor_with_method (this_obj, target, addr, method);
7212 }
7213
7214 /**
7215  * mono_method_call_message_new:
7216  * @method: method to encapsulate
7217  * @params: parameters to the method
7218  * @invoke: optional, delegate invoke.
7219  * @cb: async callback delegate.
7220  * @state: state passed to the async callback.
7221  *
7222  * Translates arguments pointers into a MonoMethodMessage.
7223  */
7224 MonoMethodMessage *
7225 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7226                               MonoDelegate **cb, MonoObject **state)
7227 {
7228         MONO_REQ_GC_UNSAFE_MODE;
7229
7230         MonoError error;
7231
7232         MonoDomain *domain = mono_domain_get ();
7233         MonoMethodSignature *sig = mono_method_signature (method);
7234         MonoMethodMessage *msg;
7235         int i, count;
7236
7237         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error); 
7238         mono_error_raise_exception (&error); /* FIXME don't raise here */
7239
7240         if (invoke) {
7241                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7242                 mono_error_raise_exception (&error); /* FIXME don't raise here */
7243                 mono_message_init (domain, msg, rm, NULL);
7244                 count =  sig->param_count - 2;
7245         } else {
7246                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7247                 mono_error_raise_exception (&error); /* FIXME don't raise here */
7248                 mono_message_init (domain, msg, rm, NULL);
7249                 count =  sig->param_count;
7250         }
7251
7252         for (i = 0; i < count; i++) {
7253                 gpointer vpos;
7254                 MonoClass *klass;
7255                 MonoObject *arg;
7256
7257                 if (sig->params [i]->byref)
7258                         vpos = *((gpointer *)params [i]);
7259                 else 
7260                         vpos = params [i];
7261
7262                 klass = mono_class_from_mono_type (sig->params [i]);
7263
7264                 if (klass->valuetype) {
7265                         arg = mono_value_box_checked (domain, klass, vpos, &error);
7266                         mono_error_raise_exception (&error); /* FIXME don't raise here */
7267                 } else 
7268                         arg = *((MonoObject **)vpos);
7269                       
7270                 mono_array_setref (msg->args, i, arg);
7271         }
7272
7273         if (cb != NULL && state != NULL) {
7274                 *cb = *((MonoDelegate **)params [i]);
7275                 i++;
7276                 *state = *((MonoObject **)params [i]);
7277         }
7278
7279         return msg;
7280 }
7281
7282 /**
7283  * mono_method_return_message_restore:
7284  *
7285  * Restore results from message based processing back to arguments pointers
7286  */
7287 void
7288 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7289 {
7290         MONO_REQ_GC_UNSAFE_MODE;
7291
7292         MonoMethodSignature *sig = mono_method_signature (method);
7293         int i, j, type, size, out_len;
7294         
7295         if (out_args == NULL)
7296                 return;
7297         out_len = mono_array_length (out_args);
7298         if (out_len == 0)
7299                 return;
7300
7301         for (i = 0, j = 0; i < sig->param_count; i++) {
7302                 MonoType *pt = sig->params [i];
7303
7304                 if (pt->byref) {
7305                         char *arg;
7306                         if (j >= out_len)
7307                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7308
7309                         arg = (char *)mono_array_get (out_args, gpointer, j);
7310                         type = pt->type;
7311
7312                         g_assert (type != MONO_TYPE_VOID);
7313
7314                         if (MONO_TYPE_IS_REFERENCE (pt)) {
7315                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7316                         } else {
7317                                 if (arg) {
7318                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7319                                         size = mono_class_value_size (klass, NULL);
7320                                         if (klass->has_references)
7321                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7322                                         else
7323                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7324                                 } else {
7325                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7326                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7327                                 }
7328                         }
7329
7330                         j++;
7331                 }
7332         }
7333 }
7334
7335 #ifndef DISABLE_REMOTING
7336
7337 /**
7338  * mono_load_remote_field:
7339  * @this: pointer to an object
7340  * @klass: klass of the object containing @field
7341  * @field: the field to load
7342  * @res: a storage to store the result
7343  *
7344  * This method is called by the runtime on attempts to load fields of
7345  * transparent proxy objects. @this points to such TP, @klass is the class of
7346  * the object containing @field. @res is a storage location which can be
7347  * used to store the result.
7348  *
7349  * Returns: an address pointing to the value of field.
7350  */
7351 gpointer
7352 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7353 {
7354         MONO_REQ_GC_UNSAFE_MODE;
7355
7356         MonoError error;
7357
7358         static MonoMethod *getter = NULL;
7359         MonoDomain *domain = mono_domain_get ();
7360         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7361         MonoClass *field_class;
7362         MonoMethodMessage *msg;
7363         MonoArray *out_args;
7364         MonoObject *exc;
7365         char* full_name;
7366
7367         g_assert (mono_object_is_transparent_proxy (this_obj));
7368         g_assert (res != NULL);
7369
7370         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7371                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7372                 return res;
7373         }
7374         
7375         if (!getter) {
7376                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7377                 if (!getter)
7378                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7379         }
7380         
7381         field_class = mono_class_from_mono_type (field->type);
7382
7383         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7384         mono_error_raise_exception (&error); /* FIXME don't raise here */
7385         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7386         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7387         mono_error_raise_exception (&error); /* FIXME don't raise here */
7388         mono_message_init (domain, msg, rm, out_args);
7389
7390         full_name = mono_type_get_full_name (klass);
7391         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7392         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7393         g_free (full_name);
7394
7395         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7396         mono_error_raise_exception (&error); /* FIXME don't raise here */
7397
7398         if (exc) mono_raise_exception ((MonoException *)exc);
7399
7400         if (mono_array_length (out_args) == 0)
7401                 return NULL;
7402
7403         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7404
7405         if (field_class->valuetype) {
7406                 return ((char *)*res) + sizeof (MonoObject);
7407         } else
7408                 return res;
7409 }
7410
7411 /**
7412  * mono_load_remote_field_new:
7413  * @this: 
7414  * @klass: 
7415  * @field:
7416  *
7417  * Missing documentation.
7418  */
7419 MonoObject *
7420 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7421 {
7422         MONO_REQ_GC_UNSAFE_MODE;
7423
7424         MonoError error;
7425
7426         static MonoMethod *getter = NULL;
7427         MonoDomain *domain = mono_domain_get ();
7428         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7429         MonoClass *field_class;
7430         MonoMethodMessage *msg;
7431         MonoArray *out_args;
7432         MonoObject *exc, *res;
7433         char* full_name;
7434
7435         g_assert (mono_object_is_transparent_proxy (this_obj));
7436
7437         field_class = mono_class_from_mono_type (field->type);
7438
7439         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7440                 gpointer val;
7441                 if (field_class->valuetype) {
7442                         res = mono_object_new_checked (domain, field_class, &error);
7443                         mono_error_raise_exception (&error); /* FIXME don't raise here */
7444                         val = ((gchar *) res) + sizeof (MonoObject);
7445                 } else {
7446                         val = &res;
7447                 }
7448                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7449                 return res;
7450         }
7451
7452         if (!getter) {
7453                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7454                 if (!getter)
7455                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7456         }
7457         
7458         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7459         mono_error_raise_exception (&error); /* FIXME don't raise here */
7460         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7461
7462         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7463         mono_error_raise_exception (&error); /* FIXME don't raise here */
7464         mono_message_init (domain, msg, rm, out_args);
7465
7466         full_name = mono_type_get_full_name (klass);
7467         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7468         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7469         g_free (full_name);
7470
7471         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7472         mono_error_raise_exception (&error); /* FIXME don't raise here */
7473
7474         if (exc) mono_raise_exception ((MonoException *)exc);
7475
7476         if (mono_array_length (out_args) == 0)
7477                 res = NULL;
7478         else
7479                 res = mono_array_get (out_args, MonoObject *, 0);
7480
7481         return res;
7482 }
7483
7484 /**
7485  * mono_store_remote_field:
7486  * @this_obj: pointer to an object
7487  * @klass: klass of the object containing @field
7488  * @field: the field to load
7489  * @val: the value/object to store
7490  *
7491  * This method is called by the runtime on attempts to store fields of
7492  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7493  * the object containing @field. @val is the new value to store in @field.
7494  */
7495 void
7496 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7497 {
7498         MONO_REQ_GC_UNSAFE_MODE;
7499
7500         MonoError error;
7501
7502         static MonoMethod *setter = NULL;
7503         MonoDomain *domain = mono_domain_get ();
7504         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7505         MonoClass *field_class;
7506         MonoMethodMessage *msg;
7507         MonoArray *out_args;
7508         MonoObject *exc;
7509         MonoObject *arg;
7510         char* full_name;
7511
7512         g_assert (mono_object_is_transparent_proxy (this_obj));
7513
7514         field_class = mono_class_from_mono_type (field->type);
7515
7516         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7517                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7518                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7519                 return;
7520         }
7521
7522         if (!setter) {
7523                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7524                 if (!setter)
7525                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7526         }
7527
7528         if (field_class->valuetype) {
7529                 arg = mono_value_box_checked (domain, field_class, val, &error);
7530                 mono_error_raise_exception (&error); /* FIXME don't raise here */
7531         } else 
7532                 arg = *((MonoObject **)val);
7533                 
7534
7535         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7536         mono_error_raise_exception (&error); /* FIXME don't raise here */
7537         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7538         mono_error_raise_exception (&error); /* FIXME don't raise here */
7539         mono_message_init (domain, msg, rm, NULL);
7540
7541         full_name = mono_type_get_full_name (klass);
7542         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7543         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7544         mono_array_setref (msg->args, 2, arg);
7545         g_free (full_name);
7546
7547         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7548         mono_error_raise_exception (&error); /* FIXME don't raise here */
7549
7550         if (exc) mono_raise_exception ((MonoException *)exc);
7551 }
7552
7553 /**
7554  * mono_store_remote_field_new:
7555  * @this_obj:
7556  * @klass:
7557  * @field:
7558  * @arg:
7559  *
7560  * Missing documentation
7561  */
7562 void
7563 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7564 {
7565         MONO_REQ_GC_UNSAFE_MODE;
7566
7567         MonoError error;
7568
7569         static MonoMethod *setter = NULL;
7570         MonoDomain *domain = mono_domain_get ();
7571         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7572         MonoClass *field_class;
7573         MonoMethodMessage *msg;
7574         MonoArray *out_args;
7575         MonoObject *exc;
7576         char* full_name;
7577
7578         g_assert (mono_object_is_transparent_proxy (this_obj));
7579
7580         field_class = mono_class_from_mono_type (field->type);
7581
7582         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7583                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7584                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7585                 return;
7586         }
7587
7588         if (!setter) {
7589                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7590                 if (!setter)
7591                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7592         }
7593
7594         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7595         mono_error_raise_exception (&error); /* FIXME don't raise here */
7596         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7597         mono_error_raise_exception (&error); /* FIXME don't raise here */
7598         mono_message_init (domain, msg, rm, NULL);
7599
7600         full_name = mono_type_get_full_name (klass);
7601         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7602         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7603         mono_array_setref (msg->args, 2, arg);
7604         g_free (full_name);
7605
7606         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7607         mono_error_raise_exception (&error); /* FIXME don't raise here */
7608
7609         if (exc) mono_raise_exception ((MonoException *)exc);
7610 }
7611 #endif
7612
7613 /*
7614  * mono_create_ftnptr:
7615  *
7616  *   Given a function address, create a function descriptor for it.
7617  * This is only needed on some platforms.
7618  */
7619 gpointer
7620 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7621 {
7622         return callbacks.create_ftnptr (domain, addr);
7623 }
7624
7625 /*
7626  * mono_get_addr_from_ftnptr:
7627  *
7628  *   Given a pointer to a function descriptor, return the function address.
7629  * This is only needed on some platforms.
7630  */
7631 gpointer
7632 mono_get_addr_from_ftnptr (gpointer descr)
7633 {
7634         return callbacks.get_addr_from_ftnptr (descr);
7635 }       
7636
7637 /**
7638  * mono_string_chars:
7639  * @s: a MonoString
7640  *
7641  * Returns a pointer to the UCS16 characters stored in the MonoString
7642  */
7643 gunichar2 *
7644 mono_string_chars (MonoString *s)
7645 {
7646         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7647
7648         return s->chars;
7649 }
7650
7651 /**
7652  * mono_string_length:
7653  * @s: MonoString
7654  *
7655  * Returns the lenght in characters of the string
7656  */
7657 int
7658 mono_string_length (MonoString *s)
7659 {
7660         MONO_REQ_GC_UNSAFE_MODE;
7661
7662         return s->length;
7663 }
7664
7665 /**
7666  * mono_array_length:
7667  * @array: a MonoArray*
7668  *
7669  * Returns the total number of elements in the array. This works for
7670  * both vectors and multidimensional arrays.
7671  */
7672 uintptr_t
7673 mono_array_length (MonoArray *array)
7674 {
7675         MONO_REQ_GC_UNSAFE_MODE;
7676
7677         return array->max_length;
7678 }
7679
7680 /**
7681  * mono_array_addr_with_size:
7682  * @array: a MonoArray*
7683  * @size: size of the array elements
7684  * @idx: index into the array
7685  *
7686  * Use this function to obtain the address for the @idx item on the
7687  * @array containing elements of size @size.
7688  *
7689  * This method performs no bounds checking or type checking.
7690  *
7691  * Returns the address of the @idx element in the array.
7692  */
7693 char*
7694 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7695 {
7696         MONO_REQ_GC_UNSAFE_MODE;
7697
7698         return ((char*)(array)->vector) + size * idx;
7699 }
7700
7701
7702 MonoArray *
7703 mono_glist_to_array (GList *list, MonoClass *eclass) 
7704 {
7705         MonoDomain *domain = mono_domain_get ();
7706         MonoArray *res;
7707         int len, i;
7708
7709         if (!list)
7710                 return NULL;
7711
7712         len = g_list_length (list);
7713         res = mono_array_new (domain, eclass, len);
7714
7715         for (i = 0; list; list = list->next, i++)
7716                 mono_array_set (res, gpointer, i, list->data);
7717
7718         return res;
7719 }
7720
7721 #if NEVER_DEFINED
7722 /*
7723  * The following section is purely to declare prototypes and
7724  * document the API, as these C files are processed by our
7725  * tool
7726  */
7727
7728 /**
7729  * mono_array_set:
7730  * @array: array to alter
7731  * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7732  * @index: index into the array
7733  * @value: value to set
7734  *
7735  * Value Type version: This sets the @index's element of the @array
7736  * with elements of size sizeof(type) to the provided @value.
7737  *
7738  * This macro does not attempt to perform type checking or bounds checking.
7739  *
7740  * Use this to set value types in a `MonoArray`.
7741  */
7742 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7743 {
7744 }
7745
7746 /**
7747  * mono_array_setref:
7748  * @array: array to alter
7749  * @index: index into the array
7750  * @value: value to set
7751  *
7752  * Reference Type version: This sets the @index's element of the
7753  * @array with elements of size sizeof(type) to the provided @value.
7754  *
7755  * This macro does not attempt to perform type checking or bounds checking.
7756  *
7757  * Use this to reference types in a `MonoArray`.
7758  */
7759 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7760 {
7761 }
7762
7763 /**
7764  * mono_array_get:
7765  * @array: array on which to operate on
7766  * @element_type: C element type (example: MonoString *, int, MonoObject *)
7767  * @index: index into the array
7768  *
7769  * Use this macro to retrieve the @index element of an @array and
7770  * extract the value assuming that the elements of the array match
7771  * the provided type value.
7772  *
7773  * This method can be used with both arrays holding value types and
7774  * reference types.   For reference types, the @type parameter should
7775  * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7776  *
7777  * This macro does not attempt to perform type checking or bounds checking.
7778  *
7779  * Returns: The element at the @index position in the @array.
7780  */
7781 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
7782 {
7783 }
7784 #endif
7785