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