737986052251c1385acfca6a20c6a908489ebb62
[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                         rval = -1;
4779                 }
4780         }
4781         return rval;
4782 }
4783
4784 static int
4785 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4786 {
4787         MONO_REQ_GC_UNSAFE_MODE;
4788
4789         gpointer pa [1];
4790         int rval;
4791
4792         g_assert (args);
4793         g_assert (exc);
4794
4795         pa [0] = args;
4796
4797         /* FIXME: check signature of method */
4798         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4799                 MonoError inner_error;
4800                 MonoObject *res;
4801                 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4802                 if (*exc == NULL && !mono_error_ok (&inner_error))
4803                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4804                 else
4805                         mono_error_cleanup (&inner_error);
4806
4807                 if (*exc == NULL)
4808                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4809                 else
4810                         rval = -1;
4811
4812                 mono_environment_exitcode_set (rval);
4813         } else {
4814                 MonoError inner_error;
4815                 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4816                 if (*exc == NULL && !mono_error_ok (&inner_error))
4817                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4818                 else
4819                         mono_error_cleanup (&inner_error);
4820
4821                 if (*exc == NULL)
4822                         rval = 0;
4823                 else {
4824                         /* If the return type of Main is void, only
4825                          * set the exitcode if an exception was thrown
4826                          * (we don't want to blow away an
4827                          * explicitly-set exit code)
4828                          */
4829                         rval = -1;
4830                         mono_environment_exitcode_set (rval);
4831                 }
4832         }
4833
4834         return rval;
4835 }
4836
4837 /*
4838  * Execute a standard Main() method (args doesn't contain the
4839  * executable name).
4840  */
4841 int
4842 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4843 {
4844         MonoError error;
4845         prepare_thread_to_exec_main (mono_object_domain (args), method);
4846         if (exc) {
4847                 int rval = do_try_exec_main (method, args, exc);
4848                 return rval;
4849         } else {
4850                 int rval = do_exec_main_checked (method, args, &error);
4851                 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4852                 return rval;
4853         }
4854 }
4855
4856 /*
4857  * Execute a standard Main() method (args doesn't contain the
4858  * executable name).
4859  *
4860  * On failure sets @error
4861  */
4862 int
4863 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4864 {
4865         mono_error_init (error);
4866         prepare_thread_to_exec_main (mono_object_domain (args), method);
4867         return do_exec_main_checked (method, args, error);
4868 }
4869
4870 /*
4871  * Execute a standard Main() method (args doesn't contain the
4872  * executable name).
4873  *
4874  * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4875  */
4876 int
4877 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4878 {
4879         prepare_thread_to_exec_main (mono_object_domain (args), method);
4880         return do_try_exec_main (method, args, exc);
4881 }
4882
4883
4884
4885 /** invoke_array_extract_argument:
4886  * @params: array of arguments to the method.
4887  * @i: the index of the argument to extract.
4888  * @t: ith type from the method signature.
4889  * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4890  * @error: set on error.
4891  *
4892  * Given an array of method arguments, return the ith one using the corresponding type
4893  * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4894  *
4895  * On failure sets @error and returns NULL.
4896  */
4897 static gpointer
4898 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4899 {
4900         MonoType *t_orig = t;
4901         gpointer result = NULL;
4902         mono_error_init (error);
4903                 again:
4904                         switch (t->type) {
4905                         case MONO_TYPE_U1:
4906                         case MONO_TYPE_I1:
4907                         case MONO_TYPE_BOOLEAN:
4908                         case MONO_TYPE_U2:
4909                         case MONO_TYPE_I2:
4910                         case MONO_TYPE_CHAR:
4911                         case MONO_TYPE_U:
4912                         case MONO_TYPE_I:
4913                         case MONO_TYPE_U4:
4914                         case MONO_TYPE_I4:
4915                         case MONO_TYPE_U8:
4916                         case MONO_TYPE_I8:
4917                         case MONO_TYPE_R4:
4918                         case MONO_TYPE_R8:
4919                         case MONO_TYPE_VALUETYPE:
4920                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4921                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4922                                         result = mono_array_get (params, MonoObject*, i);
4923                                         if (t->byref)
4924                                                 *has_byref_nullables = TRUE;
4925                                 } else {
4926                                         /* MS seems to create the objects if a null is passed in */
4927                                         if (!mono_array_get (params, MonoObject*, i)) {
4928                                                 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4929                                                 return_val_if_nok (error, NULL);
4930                                                 mono_array_setref (params, i, o); 
4931                                         }
4932
4933                                         if (t->byref) {
4934                                                 /*
4935                                                  * We can't pass the unboxed vtype byref to the callee, since
4936                                                  * that would mean the callee would be able to modify boxed
4937                                                  * primitive types. So we (and MS) make a copy of the boxed
4938                                                  * object, pass that to the callee, and replace the original
4939                                                  * boxed object in the arg array with the copy.
4940                                                  */
4941                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4942                                                 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4943                                                 return_val_if_nok (error, NULL);
4944                                                 mono_array_setref (params, i, copy);
4945                                         }
4946                                                 
4947                                         result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4948                                 }
4949                                 break;
4950                         case MONO_TYPE_STRING:
4951                         case MONO_TYPE_OBJECT:
4952                         case MONO_TYPE_CLASS:
4953                         case MONO_TYPE_ARRAY:
4954                         case MONO_TYPE_SZARRAY:
4955                                 if (t->byref)
4956                                         result = mono_array_addr (params, MonoObject*, i);
4957                                         // FIXME: I need to check this code path
4958                                 else
4959                                         result = mono_array_get (params, MonoObject*, i);
4960                                 break;
4961                         case MONO_TYPE_GENERICINST:
4962                                 if (t->byref)
4963                                         t = &t->data.generic_class->container_class->this_arg;
4964                                 else
4965                                         t = &t->data.generic_class->container_class->byval_arg;
4966                                 goto again;
4967                         case MONO_TYPE_PTR: {
4968                                 MonoObject *arg;
4969
4970                                 /* The argument should be an IntPtr */
4971                                 arg = mono_array_get (params, MonoObject*, i);
4972                                 if (arg == NULL) {
4973                                         result = NULL;
4974                                 } else {
4975                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4976                                         result = ((MonoIntPtr*)arg)->m_value;
4977                                 }
4978                                 break;
4979                         }
4980                         default:
4981                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4982                         }
4983         return result;
4984 }
4985 /**
4986  * mono_runtime_invoke_array:
4987  * @method: method to invoke
4988  * @obJ: object instance
4989  * @params: arguments to the method
4990  * @exc: exception information.
4991  *
4992  * Invokes the method represented by @method on the object @obj.
4993  *
4994  * obj is the 'this' pointer, it should be NULL for static
4995  * methods, a MonoObject* for object instances and a pointer to
4996  * the value type for value types.
4997  *
4998  * The params array contains the arguments to the method with the
4999  * same convention: MonoObject* pointers for object instances and
5000  * pointers to the value type otherwise. The _invoke_array
5001  * variant takes a C# object[] as the params argument (MonoArray
5002  * *params): in this case the value types are boxed inside the
5003  * respective reference representation.
5004  * 
5005  * From unmanaged code you'll usually use the
5006  * mono_runtime_invoke_checked() variant.
5007  *
5008  * Note that this function doesn't handle virtual methods for
5009  * you, it will exec the exact method you pass: we still need to
5010  * expose a function to lookup the derived class implementation
5011  * of a virtual method (there are examples of this in the code,
5012  * though).
5013  * 
5014  * You can pass NULL as the exc argument if you don't want to
5015  * catch exceptions, otherwise, *exc will be set to the exception
5016  * thrown, if any.  if an exception is thrown, you can't use the
5017  * MonoObject* result from the function.
5018  * 
5019  * If the method returns a value type, it is boxed in an object
5020  * reference.
5021  */
5022 MonoObject*
5023 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5024                            MonoObject **exc)
5025 {
5026         MonoError error;
5027         if (exc) {
5028                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
5029                 if (*exc) {
5030                         mono_error_cleanup (&error);
5031                         return NULL;
5032                 } else {
5033                         if (!is_ok (&error))
5034                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
5035                         return result;
5036                 }
5037         } else {
5038                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
5039                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
5040                 return result;
5041         }
5042 }
5043
5044 /**
5045  * mono_runtime_invoke_array_checked:
5046  * @method: method to invoke
5047  * @obJ: object instance
5048  * @params: arguments to the method
5049  * @error: set on failure.
5050  *
5051  * Invokes the method represented by @method on the object @obj.
5052  *
5053  * obj is the 'this' pointer, it should be NULL for static
5054  * methods, a MonoObject* for object instances and a pointer to
5055  * the value type for value types.
5056  *
5057  * The params array contains the arguments to the method with the
5058  * same convention: MonoObject* pointers for object instances and
5059  * pointers to the value type otherwise. The _invoke_array
5060  * variant takes a C# object[] as the params argument (MonoArray
5061  * *params): in this case the value types are boxed inside the
5062  * respective reference representation.
5063  *
5064  * From unmanaged code you'll usually use the
5065  * mono_runtime_invoke_checked() variant.
5066  *
5067  * Note that this function doesn't handle virtual methods for
5068  * you, it will exec the exact method you pass: we still need to
5069  * expose a function to lookup the derived class implementation
5070  * of a virtual method (there are examples of this in the code,
5071  * though).
5072  *
5073  * On failure or exception, @error will be set. In that case, you
5074  * can't use the MonoObject* result from the function.
5075  *
5076  * If the method returns a value type, it is boxed in an object
5077  * reference.
5078  */
5079 MonoObject*
5080 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5081                                    MonoError *error)
5082 {
5083         mono_error_init (error);
5084         return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5085 }
5086
5087 /**
5088  * mono_runtime_try_invoke_array:
5089  * @method: method to invoke
5090  * @obJ: object instance
5091  * @params: arguments to the method
5092  * @exc: exception information.
5093  * @error: set on failure.
5094  *
5095  * Invokes the method represented by @method on the object @obj.
5096  *
5097  * obj is the 'this' pointer, it should be NULL for static
5098  * methods, a MonoObject* for object instances and a pointer to
5099  * the value type for value types.
5100  *
5101  * The params array contains the arguments to the method with the
5102  * same convention: MonoObject* pointers for object instances and
5103  * pointers to the value type otherwise. The _invoke_array
5104  * variant takes a C# object[] as the params argument (MonoArray
5105  * *params): in this case the value types are boxed inside the
5106  * respective reference representation.
5107  *
5108  * From unmanaged code you'll usually use the
5109  * mono_runtime_invoke_checked() variant.
5110  *
5111  * Note that this function doesn't handle virtual methods for
5112  * you, it will exec the exact method you pass: we still need to
5113  * expose a function to lookup the derived class implementation
5114  * of a virtual method (there are examples of this in the code,
5115  * though).
5116  *
5117  * You can pass NULL as the exc argument if you don't want to catch
5118  * exceptions, otherwise, *exc will be set to the exception thrown, if
5119  * any.  On other failures, @error will be set. If an exception is
5120  * thrown or there's an error, you can't use the MonoObject* result
5121  * from the function.
5122  *
5123  * If the method returns a value type, it is boxed in an object
5124  * reference.
5125  */
5126 MonoObject*
5127 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5128                                MonoObject **exc, MonoError *error)
5129 {
5130         MONO_REQ_GC_UNSAFE_MODE;
5131
5132         mono_error_init (error);
5133
5134         MonoMethodSignature *sig = mono_method_signature (method);
5135         gpointer *pa = NULL;
5136         MonoObject *res;
5137         int i;
5138         gboolean has_byref_nullables = FALSE;
5139
5140         if (NULL != params) {
5141                 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5142                 for (i = 0; i < mono_array_length (params); i++) {
5143                         MonoType *t = sig->params [i];
5144                         pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5145                         return_val_if_nok (error, NULL);
5146                 }
5147         }
5148
5149         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5150                 void *o = obj;
5151
5152                 if (mono_class_is_nullable (method->klass)) {
5153                         /* Need to create a boxed vtype instead */
5154                         g_assert (!obj);
5155
5156                         if (!params)
5157                                 return NULL;
5158                         else {
5159                                 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5160                         }
5161                 }
5162
5163                 if (!obj) {
5164                         obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5165                         mono_error_assert_ok (error);
5166                         g_assert (obj); /*maybe we should raise a TLE instead?*/
5167 #ifndef DISABLE_REMOTING
5168                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5169                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5170                         }
5171 #endif
5172                         if (method->klass->valuetype)
5173                                 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5174                         else
5175                                 o = obj;
5176                 } else if (method->klass->valuetype) {
5177                         obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5178                         return_val_if_nok (error, NULL);
5179                 }
5180
5181                 if (exc) {
5182                         mono_runtime_try_invoke (method, o, pa, exc, error);
5183                 } else {
5184                         mono_runtime_invoke_checked (method, o, pa, error);
5185                 }
5186
5187                 return (MonoObject *)obj;
5188         } else {
5189                 if (mono_class_is_nullable (method->klass)) {
5190                         MonoObject *nullable;
5191
5192                         /* Convert the unboxed vtype into a Nullable structure */
5193                         nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5194                         return_val_if_nok (error, NULL);
5195
5196                         MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5197                         return_val_if_nok (error, NULL);
5198                         mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5199                         obj = mono_object_unbox (nullable);
5200                 }
5201
5202                 /* obj must be already unboxed if needed */
5203                 if (exc) {
5204                         res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5205                 } else {
5206                         res = mono_runtime_invoke_checked (method, obj, pa, error);
5207                 }
5208                 return_val_if_nok (error, NULL);
5209
5210                 if (sig->ret->type == MONO_TYPE_PTR) {
5211                         MonoClass *pointer_class;
5212                         static MonoMethod *box_method;
5213                         void *box_args [2];
5214                         MonoObject *box_exc;
5215
5216                         /* 
5217                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
5218                          * convert it to a Pointer object.
5219                          */
5220                         pointer_class = mono_class_get_pointer_class ();
5221                         if (!box_method)
5222                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5223
5224                         g_assert (res->vtable->klass == mono_defaults.int_class);
5225                         box_args [0] = ((MonoIntPtr*)res)->m_value;
5226                         box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5227                         return_val_if_nok (error, NULL);
5228
5229                         res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5230                         g_assert (box_exc == NULL);
5231                         mono_error_assert_ok (error);
5232                 }
5233
5234                 if (has_byref_nullables) {
5235                         /* 
5236                          * The runtime invoke wrapper already converted byref nullables back,
5237                          * and stored them in pa, we just need to copy them back to the
5238                          * managed array.
5239                          */
5240                         for (i = 0; i < mono_array_length (params); i++) {
5241                                 MonoType *t = sig->params [i];
5242
5243                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5244                                         mono_array_setref (params, i, pa [i]);
5245                         }
5246                 }
5247
5248                 return res;
5249         }
5250 }
5251
5252 /**
5253  * mono_object_new:
5254  * @klass: the class of the object that we want to create
5255  *
5256  * Returns: a newly created object whose definition is
5257  * looked up using @klass.   This will not invoke any constructors, 
5258  * so the consumer of this routine has to invoke any constructors on
5259  * its own to initialize the object.
5260  * 
5261  * It returns NULL on failure.
5262  */
5263 MonoObject *
5264 mono_object_new (MonoDomain *domain, MonoClass *klass)
5265 {
5266         MONO_REQ_GC_UNSAFE_MODE;
5267
5268         MonoError error;
5269
5270         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5271
5272         mono_error_cleanup (&error);
5273         return result;
5274 }
5275
5276 MonoObject *
5277 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5278 {
5279         MONO_REQ_GC_UNSAFE_MODE;
5280
5281         MonoError error;
5282
5283         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5284
5285         mono_error_set_pending_exception (&error);
5286         return result;
5287 }
5288
5289 /**
5290  * mono_object_new_checked:
5291  * @klass: the class of the object that we want to create
5292  * @error: set on error
5293  *
5294  * Returns: a newly created object whose definition is
5295  * looked up using @klass.   This will not invoke any constructors,
5296  * so the consumer of this routine has to invoke any constructors on
5297  * its own to initialize the object.
5298  *
5299  * It returns NULL on failure and sets @error.
5300  */
5301 MonoObject *
5302 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5303 {
5304         MONO_REQ_GC_UNSAFE_MODE;
5305
5306         MonoVTable *vtable;
5307
5308         vtable = mono_class_vtable (domain, klass);
5309         g_assert (vtable); /* FIXME don't swallow the error */
5310
5311         MonoObject *o = mono_object_new_specific_checked (vtable, error);
5312         return o;
5313 }
5314
5315 /**
5316  * mono_object_new_pinned:
5317  *
5318  *   Same as mono_object_new, but the returned object will be pinned.
5319  * For SGEN, these objects will only be freed at appdomain unload.
5320  */
5321 MonoObject *
5322 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5323 {
5324         MONO_REQ_GC_UNSAFE_MODE;
5325
5326         MonoVTable *vtable;
5327
5328         mono_error_init (error);
5329
5330         vtable = mono_class_vtable (domain, klass);
5331         g_assert (vtable); /* FIXME don't swallow the error */
5332
5333         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5334
5335         if (G_UNLIKELY (!o))
5336                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5337         else if (G_UNLIKELY (vtable->klass->has_finalize))
5338                 mono_object_register_finalizer (o);
5339
5340         return o;
5341 }
5342
5343 /**
5344  * mono_object_new_specific:
5345  * @vtable: the vtable of the object that we want to create
5346  *
5347  * Returns: A newly created object with class and domain specified
5348  * by @vtable
5349  */
5350 MonoObject *
5351 mono_object_new_specific (MonoVTable *vtable)
5352 {
5353         MonoError error;
5354         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5355         mono_error_cleanup (&error);
5356
5357         return o;
5358 }
5359
5360 MonoObject *
5361 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5362 {
5363         MONO_REQ_GC_UNSAFE_MODE;
5364
5365         MonoObject *o;
5366
5367         mono_error_init (error);
5368
5369         /* check for is_com_object for COM Interop */
5370         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5371         {
5372                 gpointer pa [1];
5373                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5374
5375                 if (im == NULL) {
5376                         MonoClass *klass = mono_class_get_activation_services_class ();
5377
5378                         if (!klass->inited)
5379                                 mono_class_init (klass);
5380
5381                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5382                         if (!im) {
5383                                 mono_error_set_not_supported (error, "Linked away.");
5384                                 return NULL;
5385                         }
5386                         vtable->domain->create_proxy_for_type_method = im;
5387                 }
5388         
5389                 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5390                 if (!mono_error_ok (error))
5391                         return NULL;
5392
5393                 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5394                 if (!mono_error_ok (error))
5395                         return NULL;
5396
5397                 if (o != NULL)
5398                         return o;
5399         }
5400
5401         return mono_object_new_alloc_specific_checked (vtable, error);
5402 }
5403
5404 MonoObject *
5405 ves_icall_object_new_specific (MonoVTable *vtable)
5406 {
5407         MonoError error;
5408         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5409         mono_error_set_pending_exception (&error);
5410
5411         return o;
5412 }
5413
5414 /**
5415  * mono_object_new_alloc_specific:
5416  * @vtable: virtual table for the object.
5417  *
5418  * This function allocates a new `MonoObject` with the type derived
5419  * from the @vtable information.   If the class of this object has a 
5420  * finalizer, then the object will be tracked for finalization.
5421  *
5422  * This method might raise an exception on errors.  Use the
5423  * `mono_object_new_fast_checked` method if you want to manually raise
5424  * the exception.
5425  *
5426  * Returns: the allocated object.   
5427  */
5428 MonoObject *
5429 mono_object_new_alloc_specific (MonoVTable *vtable)
5430 {
5431         MonoError error;
5432         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5433         mono_error_cleanup (&error);
5434
5435         return o;
5436 }
5437
5438 /**
5439  * mono_object_new_alloc_specific_checked:
5440  * @vtable: virtual table for the object.
5441  * @error: holds the error return value.  
5442  *
5443  * This function allocates a new `MonoObject` with the type derived
5444  * from the @vtable information. If the class of this object has a 
5445  * finalizer, then the object will be tracked for finalization.
5446  *
5447  * If there is not enough memory, the @error parameter will be set
5448  * and will contain a user-visible message with the amount of bytes
5449  * that were requested.
5450  *
5451  * Returns: the allocated object, or NULL if there is not enough memory
5452  *
5453  */
5454 MonoObject *
5455 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5456 {
5457         MONO_REQ_GC_UNSAFE_MODE;
5458
5459         MonoObject *o;
5460
5461         mono_error_init (error);
5462
5463         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5464
5465         if (G_UNLIKELY (!o))
5466                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5467         else if (G_UNLIKELY (vtable->klass->has_finalize))
5468                 mono_object_register_finalizer (o);
5469
5470         return o;
5471 }
5472
5473 /**
5474  * mono_object_new_fast:
5475  * @vtable: virtual table for the object.
5476  *
5477  * This function allocates a new `MonoObject` with the type derived
5478  * from the @vtable information.   The returned object is not tracked
5479  * for finalization.   If your object implements a finalizer, you should
5480  * use `mono_object_new_alloc_specific` instead.
5481  *
5482  * This method might raise an exception on errors.  Use the
5483  * `mono_object_new_fast_checked` method if you want to manually raise
5484  * the exception.
5485  *
5486  * Returns: the allocated object.   
5487  */
5488 MonoObject*
5489 mono_object_new_fast (MonoVTable *vtable)
5490 {
5491         MonoError error;
5492         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5493         mono_error_cleanup (&error);
5494
5495         return o;
5496 }
5497
5498 /**
5499  * mono_object_new_fast_checked:
5500  * @vtable: virtual table for the object.
5501  * @error: holds the error return value.
5502  *
5503  * This function allocates a new `MonoObject` with the type derived
5504  * from the @vtable information. The returned object is not tracked
5505  * for finalization.   If your object implements a finalizer, you should
5506  * use `mono_object_new_alloc_specific_checked` instead.
5507  *
5508  * If there is not enough memory, the @error parameter will be set
5509  * and will contain a user-visible message with the amount of bytes
5510  * that were requested.
5511  *
5512  * Returns: the allocated object, or NULL if there is not enough memory
5513  *
5514  */
5515 MonoObject*
5516 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5517 {
5518         MONO_REQ_GC_UNSAFE_MODE;
5519
5520         MonoObject *o;
5521
5522         mono_error_init (error);
5523
5524         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5525
5526         if (G_UNLIKELY (!o))
5527                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5528
5529         return o;
5530 }
5531
5532 MonoObject *
5533 ves_icall_object_new_fast (MonoVTable *vtable)
5534 {
5535         MonoError error;
5536         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5537         mono_error_set_pending_exception (&error);
5538
5539         return o;
5540 }
5541
5542 MonoObject*
5543 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5544 {
5545         MONO_REQ_GC_UNSAFE_MODE;
5546
5547         MonoObject *o;
5548
5549         mono_error_init (error);
5550
5551         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5552
5553         if (G_UNLIKELY (!o))
5554                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5555         else if (G_UNLIKELY (vtable->klass->has_finalize))
5556                 mono_object_register_finalizer (o);
5557
5558         return o;
5559 }
5560
5561 /**
5562  * mono_class_get_allocation_ftn:
5563  * @vtable: vtable
5564  * @for_box: the object will be used for boxing
5565  * @pass_size_in_words: 
5566  *
5567  * Return the allocation function appropriate for the given class.
5568  */
5569
5570 void*
5571 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5572 {
5573         MONO_REQ_GC_NEUTRAL_MODE;
5574
5575         *pass_size_in_words = FALSE;
5576
5577         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5578                 return ves_icall_object_new_specific;
5579
5580         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5581
5582                 return ves_icall_object_new_fast;
5583
5584                 /* 
5585                  * FIXME: This is actually slower than ves_icall_object_new_fast, because
5586                  * of the overhead of parameter passing.
5587                  */
5588                 /*
5589                 *pass_size_in_words = TRUE;
5590 #ifdef GC_REDIRECT_TO_LOCAL
5591                 return GC_local_gcj_fast_malloc;
5592 #else
5593                 return GC_gcj_fast_malloc;
5594 #endif
5595                 */
5596         }
5597
5598         return ves_icall_object_new_specific;
5599 }
5600
5601 /**
5602  * mono_object_new_from_token:
5603  * @image: Context where the type_token is hosted
5604  * @token: a token of the type that we want to create
5605  *
5606  * Returns: A newly created object whose definition is
5607  * looked up using @token in the @image image
5608  */
5609 MonoObject *
5610 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
5611 {
5612         MONO_REQ_GC_UNSAFE_MODE;
5613
5614         MonoError error;
5615         MonoObject *result;
5616         MonoClass *klass;
5617
5618         klass = mono_class_get_checked (image, token, &error);
5619         mono_error_assert_ok (&error);
5620         
5621         result = mono_object_new_checked (domain, klass, &error);
5622
5623         mono_error_cleanup (&error);
5624         return result;
5625         
5626 }
5627
5628
5629 /**
5630  * mono_object_clone:
5631  * @obj: the object to clone
5632  *
5633  * Returns: A newly created object who is a shallow copy of @obj
5634  */
5635 MonoObject *
5636 mono_object_clone (MonoObject *obj)
5637 {
5638         MonoError error;
5639         MonoObject *o = mono_object_clone_checked (obj, &error);
5640         mono_error_cleanup (&error);
5641
5642         return o;
5643 }
5644
5645 MonoObject *
5646 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5647 {
5648         MONO_REQ_GC_UNSAFE_MODE;
5649
5650         MonoObject *o;
5651         int size;
5652
5653         mono_error_init (error);
5654
5655         size = obj->vtable->klass->instance_size;
5656
5657         if (obj->vtable->klass->rank)
5658                 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5659
5660         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5661
5662         if (G_UNLIKELY (!o)) {
5663                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5664                 return NULL;
5665         }
5666
5667         /* If the object doesn't contain references this will do a simple memmove. */
5668         mono_gc_wbarrier_object_copy (o, obj);
5669
5670         if (obj->vtable->klass->has_finalize)
5671                 mono_object_register_finalizer (o);
5672         return o;
5673 }
5674
5675 /**
5676  * mono_array_full_copy:
5677  * @src: source array to copy
5678  * @dest: destination array
5679  *
5680  * Copies the content of one array to another with exactly the same type and size.
5681  */
5682 void
5683 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5684 {
5685         MONO_REQ_GC_UNSAFE_MODE;
5686
5687         uintptr_t size;
5688         MonoClass *klass = src->obj.vtable->klass;
5689
5690         g_assert (klass == dest->obj.vtable->klass);
5691
5692         size = mono_array_length (src);
5693         g_assert (size == mono_array_length (dest));
5694         size *= mono_array_element_size (klass);
5695 #ifdef HAVE_SGEN_GC
5696         if (klass->element_class->valuetype) {
5697                 if (klass->element_class->has_references)
5698                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5699                 else
5700                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5701         } else {
5702                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5703         }
5704 #else
5705         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5706 #endif
5707 }
5708
5709 /**
5710  * mono_array_clone_in_domain:
5711  * @domain: the domain in which the array will be cloned into
5712  * @array: the array to clone
5713  * @error: set on error
5714  *
5715  * This routine returns a copy of the array that is hosted on the
5716  * specified MonoDomain.  On failure returns NULL and sets @error.
5717  */
5718 MonoArray*
5719 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5720 {
5721         MONO_REQ_GC_UNSAFE_MODE;
5722
5723         MonoArray *o;
5724         uintptr_t size, i;
5725         uintptr_t *sizes;
5726         MonoClass *klass = array->obj.vtable->klass;
5727
5728         mono_error_init (error);
5729
5730         if (array->bounds == NULL) {
5731                 size = mono_array_length (array);
5732                 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5733                 return_val_if_nok (error, NULL);
5734
5735                 size *= mono_array_element_size (klass);
5736 #ifdef HAVE_SGEN_GC
5737                 if (klass->element_class->valuetype) {
5738                         if (klass->element_class->has_references)
5739                                 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5740                         else
5741                                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5742                 } else {
5743                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5744                 }
5745 #else
5746                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5747 #endif
5748                 return o;
5749         }
5750         
5751         sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5752         size = mono_array_element_size (klass);
5753         for (i = 0; i < klass->rank; ++i) {
5754                 sizes [i] = array->bounds [i].length;
5755                 size *= array->bounds [i].length;
5756                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5757         }
5758         o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5759         return_val_if_nok (error, NULL);
5760 #ifdef HAVE_SGEN_GC
5761         if (klass->element_class->valuetype) {
5762                 if (klass->element_class->has_references)
5763                         mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5764                 else
5765                         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5766         } else {
5767                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5768         }
5769 #else
5770         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5771 #endif
5772
5773         return o;
5774 }
5775
5776 /**
5777  * mono_array_clone:
5778  * @array: the array to clone
5779  *
5780  * Returns: A newly created array who is a shallow copy of @array
5781  */
5782 MonoArray*
5783 mono_array_clone (MonoArray *array)
5784 {
5785         MONO_REQ_GC_UNSAFE_MODE;
5786
5787         MonoError error;
5788         MonoArray *result = mono_array_clone_checked (array, &error);
5789         mono_error_cleanup (&error);
5790         return result;
5791 }
5792
5793 /**
5794  * mono_array_clone_checked:
5795  * @array: the array to clone
5796  * @error: set on error
5797  *
5798  * Returns: A newly created array who is a shallow copy of @array.  On
5799  * failure returns NULL and sets @error.
5800  */
5801 MonoArray*
5802 mono_array_clone_checked (MonoArray *array, MonoError *error)
5803 {
5804
5805         MONO_REQ_GC_UNSAFE_MODE;
5806         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5807 }
5808
5809 /* helper macros to check for overflow when calculating the size of arrays */
5810 #ifdef MONO_BIG_ARRAYS
5811 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5812 #define MYGUINT_MAX MYGUINT64_MAX
5813 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5814             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5815 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5816             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
5817                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5818 #else
5819 #define MYGUINT32_MAX 4294967295U
5820 #define MYGUINT_MAX MYGUINT32_MAX
5821 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5822             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5823 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5824             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
5825                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5826 #endif
5827
5828 gboolean
5829 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5830 {
5831         MONO_REQ_GC_NEUTRAL_MODE;
5832
5833         uintptr_t byte_len;
5834
5835         byte_len = mono_array_element_size (klass);
5836         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5837                 return FALSE;
5838         byte_len *= len;
5839         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5840                 return FALSE;
5841         byte_len += MONO_SIZEOF_MONO_ARRAY;
5842
5843         *res = byte_len;
5844
5845         return TRUE;
5846 }
5847
5848 /**
5849  * mono_array_new_full:
5850  * @domain: domain where the object is created
5851  * @array_class: array class
5852  * @lengths: lengths for each dimension in the array
5853  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5854  *
5855  * This routine creates a new array objects with the given dimensions,
5856  * lower bounds and type.
5857  */
5858 MonoArray*
5859 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5860 {
5861         MonoError error;
5862         MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5863         mono_error_cleanup (&error);
5864
5865         return array;
5866 }
5867
5868 MonoArray*
5869 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5870 {
5871         MONO_REQ_GC_UNSAFE_MODE;
5872
5873         uintptr_t byte_len = 0, len, bounds_size;
5874         MonoObject *o;
5875         MonoArray *array;
5876         MonoArrayBounds *bounds;
5877         MonoVTable *vtable;
5878         int i;
5879
5880         mono_error_init (error);
5881
5882         if (!array_class->inited)
5883                 mono_class_init (array_class);
5884
5885         len = 1;
5886
5887         /* A single dimensional array with a 0 lower bound is the same as an szarray */
5888         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5889                 len = lengths [0];
5890                 if (len > MONO_ARRAY_MAX_INDEX) {
5891                         mono_error_set_generic_error (error, "System", "OverflowException", "");
5892                         return NULL;
5893                 }
5894                 bounds_size = 0;
5895         } else {
5896                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5897
5898                 for (i = 0; i < array_class->rank; ++i) {
5899                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5900                                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5901                                 return NULL;
5902                         }
5903                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5904                                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5905                                 return NULL;
5906                         }
5907                         len *= lengths [i];
5908                 }
5909         }
5910
5911         if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5912                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5913                 return NULL;
5914         }
5915
5916         if (bounds_size) {
5917                 /* align */
5918                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5919                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5920                         return NULL;
5921                 }
5922                 byte_len = (byte_len + 3) & ~3;
5923                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5924                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5925                         return NULL;
5926                 }
5927                 byte_len += bounds_size;
5928         }
5929         /* 
5930          * Following three lines almost taken from mono_object_new ():
5931          * they need to be kept in sync.
5932          */
5933         vtable = mono_class_vtable_full (domain, array_class, error);
5934         return_val_if_nok (error, NULL);
5935
5936         if (bounds_size)
5937                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5938         else
5939                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5940
5941         if (G_UNLIKELY (!o)) {
5942                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5943                 return NULL;
5944         }
5945
5946         array = (MonoArray*)o;
5947
5948         bounds = array->bounds;
5949
5950         if (bounds_size) {
5951                 for (i = 0; i < array_class->rank; ++i) {
5952                         bounds [i].length = lengths [i];
5953                         if (lower_bounds)
5954                                 bounds [i].lower_bound = lower_bounds [i];
5955                 }
5956         }
5957
5958         return array;
5959 }
5960
5961 /**
5962  * mono_array_new:
5963  * @domain: domain where the object is created
5964  * @eclass: element class
5965  * @n: number of array elements
5966  *
5967  * This routine creates a new szarray with @n elements of type @eclass.
5968  */
5969 MonoArray *
5970 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5971 {
5972         MONO_REQ_GC_UNSAFE_MODE;
5973
5974         MonoError error;
5975         MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5976         mono_error_cleanup (&error);
5977         return result;
5978 }
5979
5980 /**
5981  * mono_array_new_checked:
5982  * @domain: domain where the object is created
5983  * @eclass: element class
5984  * @n: number of array elements
5985  * @error: set on error
5986  *
5987  * This routine creates a new szarray with @n elements of type @eclass.
5988  * On failure returns NULL and sets @error.
5989  */
5990 MonoArray *
5991 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5992 {
5993         MonoClass *ac;
5994
5995         mono_error_init (error);
5996
5997         ac = mono_array_class_get (eclass, 1);
5998         g_assert (ac);
5999
6000         MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
6001         return_val_if_nok (error, NULL);
6002
6003         return mono_array_new_specific_checked (vtable, n, error);
6004 }
6005
6006 MonoArray*
6007 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6008 {
6009         MonoError error;
6010         MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
6011         mono_error_set_pending_exception (&error);
6012
6013         return arr;
6014 }
6015
6016 /**
6017  * mono_array_new_specific:
6018  * @vtable: a vtable in the appropriate domain for an initialized class
6019  * @n: number of array elements
6020  *
6021  * This routine is a fast alternative to mono_array_new() for code which
6022  * can be sure about the domain it operates in.
6023  */
6024 MonoArray *
6025 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
6026 {
6027         MonoError error;
6028         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6029         mono_error_cleanup (&error);
6030
6031         return arr;
6032 }
6033
6034 MonoArray*
6035 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
6036 {
6037         MONO_REQ_GC_UNSAFE_MODE;
6038
6039         MonoObject *o;
6040         uintptr_t byte_len;
6041
6042         mono_error_init (error);
6043
6044         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6045                 mono_error_set_generic_error (error, "System", "OverflowException", "");
6046                 return NULL;
6047         }
6048
6049         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6050                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6051                 return NULL;
6052         }
6053         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6054
6055         if (G_UNLIKELY (!o)) {
6056                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
6057                 return NULL;
6058         }
6059
6060         return (MonoArray*)o;
6061 }
6062
6063 MonoArray*
6064 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6065 {
6066         MonoError error;
6067         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6068         mono_error_set_pending_exception (&error);
6069
6070         return arr;
6071 }
6072
6073 /**
6074  * mono_string_new_utf16:
6075  * @text: a pointer to an utf16 string
6076  * @len: the length of the string
6077  *
6078  * Returns: A newly created string object which contains @text.
6079  */
6080 MonoString *
6081 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6082 {
6083         MONO_REQ_GC_UNSAFE_MODE;
6084
6085         MonoError error;
6086         MonoString *res = NULL;
6087         res = mono_string_new_utf16_checked (domain, text, len, &error);
6088         mono_error_cleanup (&error);
6089
6090         return res;
6091 }
6092
6093 /**
6094  * mono_string_new_utf16_checked:
6095  * @text: a pointer to an utf16 string
6096  * @len: the length of the string
6097  * @error: written on error.
6098  *
6099  * Returns: A newly created string object which contains @text.
6100  * On error, returns NULL and sets @error.
6101  */
6102 MonoString *
6103 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6104 {
6105         MONO_REQ_GC_UNSAFE_MODE;
6106
6107         MonoString *s;
6108         
6109         mono_error_init (error);
6110         
6111         s = mono_string_new_size_checked (domain, len, error);
6112         if (s != NULL)
6113                 memcpy (mono_string_chars (s), text, len * 2);
6114
6115         return s;
6116 }
6117
6118 /**
6119  * mono_string_new_utf32:
6120  * @text: a pointer to an utf32 string
6121  * @len: the length of the string
6122  * @error: set on failure.
6123  *
6124  * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6125  */
6126 static MonoString *
6127 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6128 {
6129         MONO_REQ_GC_UNSAFE_MODE;
6130
6131         MonoString *s;
6132         mono_unichar2 *utf16_output = NULL;
6133         gint32 utf16_len = 0;
6134         GError *gerror = NULL;
6135         glong items_written;
6136         
6137         mono_error_init (error);
6138         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6139         
6140         if (gerror)
6141                 g_error_free (gerror);
6142
6143         while (utf16_output [utf16_len]) utf16_len++;
6144         
6145         s = mono_string_new_size_checked (domain, utf16_len, error);
6146         return_val_if_nok (error, NULL);
6147
6148         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6149
6150         g_free (utf16_output);
6151         
6152         return s;
6153 }
6154
6155 /**
6156  * mono_string_new_utf32:
6157  * @text: a pointer to an utf32 string
6158  * @len: the length of the string
6159  *
6160  * Returns: A newly created string object which contains @text.
6161  */
6162 MonoString *
6163 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6164 {
6165         MonoError error;
6166         MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6167         mono_error_cleanup (&error);
6168         return result;
6169 }
6170
6171 /**
6172  * mono_string_new_size:
6173  * @text: a pointer to an utf16 string
6174  * @len: the length of the string
6175  *
6176  * Returns: A newly created string object of @len
6177  */
6178 MonoString *
6179 mono_string_new_size (MonoDomain *domain, gint32 len)
6180 {
6181         MonoError error;
6182         MonoString *str = mono_string_new_size_checked (domain, len, &error);
6183         mono_error_cleanup (&error);
6184
6185         return str;
6186 }
6187
6188 MonoString *
6189 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6190 {
6191         MONO_REQ_GC_UNSAFE_MODE;
6192
6193         MonoString *s;
6194         MonoVTable *vtable;
6195         size_t size;
6196
6197         mono_error_init (error);
6198
6199         /* check for overflow */
6200         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6201                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6202                 return NULL;
6203         }
6204
6205         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6206         g_assert (size > 0);
6207
6208         vtable = mono_class_vtable (domain, mono_defaults.string_class);
6209         g_assert (vtable);
6210
6211         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6212
6213         if (G_UNLIKELY (!s)) {
6214                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6215                 return NULL;
6216         }
6217
6218         return s;
6219 }
6220
6221 /**
6222  * mono_string_new_len:
6223  * @text: a pointer to an utf8 string
6224  * @length: number of bytes in @text to consider
6225  *
6226  * Returns: A newly created string object which contains @text.
6227  */
6228 MonoString*
6229 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6230 {
6231         MONO_REQ_GC_UNSAFE_MODE;
6232
6233         MonoError error;
6234         MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6235         mono_error_cleanup (&error);
6236         return result;
6237 }
6238
6239 /**
6240  * mono_string_new_len_checked:
6241  * @text: a pointer to an utf8 string
6242  * @length: number of bytes in @text to consider
6243  * @error: set on error
6244  *
6245  * Returns: A newly created string object which contains @text. On
6246  * failure returns NULL and sets @error.
6247  */
6248 MonoString*
6249 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6250 {
6251         MONO_REQ_GC_UNSAFE_MODE;
6252
6253         mono_error_init (error);
6254
6255         GError *eg_error = NULL;
6256         MonoString *o = NULL;
6257         guint16 *ut = NULL;
6258         glong items_written;
6259
6260         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6261
6262         if (!eg_error)
6263                 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6264         else 
6265                 g_error_free (eg_error);
6266
6267         g_free (ut);
6268
6269         return o;
6270 }
6271
6272 /**
6273  * mono_string_new:
6274  * @text: a pointer to an utf8 string
6275  *
6276  * Returns: A newly created string object which contains @text.
6277  *
6278  * This function asserts if it cannot allocate a new string.
6279  *
6280  * @deprecated Use mono_string_new_checked in new code.
6281  */
6282 MonoString*
6283 mono_string_new (MonoDomain *domain, const char *text)
6284 {
6285         MonoError error;
6286         MonoString *res = NULL;
6287         res = mono_string_new_checked (domain, text, &error);
6288         mono_error_assert_ok (&error);
6289         return res;
6290 }
6291
6292 /**
6293  * mono_string_new_checked:
6294  * @text: a pointer to an utf8 string
6295  * @merror: set on error
6296  *
6297  * Returns: A newly created string object which contains @text.
6298  * On error returns NULL and sets @merror.
6299  */
6300 MonoString*
6301 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6302 {
6303         MONO_REQ_GC_UNSAFE_MODE;
6304
6305     GError *eg_error = NULL;
6306     MonoString *o = NULL;
6307     guint16 *ut;
6308     glong items_written;
6309     int l;
6310
6311     mono_error_init (error);
6312
6313     l = strlen (text);
6314    
6315     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6316
6317     if (!eg_error)
6318             o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6319     else
6320         g_error_free (eg_error);
6321
6322     g_free (ut);
6323     
6324 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6325 #if 0
6326         gunichar2 *str;
6327         const gchar *end;
6328         int len;
6329         MonoString *o = NULL;
6330
6331         if (!g_utf8_validate (text, -1, &end)) {
6332                 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6333                 goto leave;
6334         }
6335
6336         len = g_utf8_strlen (text, -1);
6337         o = mono_string_new_size_checked (domain, len, error);
6338         if (!o)
6339                 goto leave;
6340         str = mono_string_chars (o);
6341
6342         while (text < end) {
6343                 *str++ = g_utf8_get_char (text);
6344                 text = g_utf8_next_char (text);
6345         }
6346
6347 leave:
6348 #endif
6349         return o;
6350 }
6351
6352 /**
6353  * mono_string_new_wrapper:
6354  * @text: pointer to utf8 characters.
6355  *
6356  * Helper function to create a string object from @text in the current domain.
6357  */
6358 MonoString*
6359 mono_string_new_wrapper (const char *text)
6360 {
6361         MONO_REQ_GC_UNSAFE_MODE;
6362
6363         MonoDomain *domain = mono_domain_get ();
6364
6365         if (text)
6366                 return mono_string_new (domain, text);
6367
6368         return NULL;
6369 }
6370
6371 /**
6372  * mono_value_box:
6373  * @class: the class of the value
6374  * @value: a pointer to the unboxed data
6375  *
6376  * Returns: A newly created object which contains @value.
6377  */
6378 MonoObject *
6379 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6380 {
6381         MonoError error;
6382         MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6383         mono_error_cleanup (&error);
6384         return result;
6385 }
6386
6387 /**
6388  * mono_value_box_checked:
6389  * @domain: the domain of the new object
6390  * @class: the class of the value
6391  * @value: a pointer to the unboxed data
6392  * @error: set on error
6393  *
6394  * Returns: A newly created object which contains @value. On failure
6395  * returns NULL and sets @error.
6396  */
6397 MonoObject *
6398 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6399 {
6400         MONO_REQ_GC_UNSAFE_MODE;
6401         MonoObject *res;
6402         int size;
6403         MonoVTable *vtable;
6404
6405         mono_error_init (error);
6406
6407         g_assert (klass->valuetype);
6408         if (mono_class_is_nullable (klass))
6409                 return mono_nullable_box ((guint8 *)value, klass, error);
6410
6411         vtable = mono_class_vtable (domain, klass);
6412         if (!vtable)
6413                 return NULL;
6414         size = mono_class_instance_size (klass);
6415         res = mono_object_new_alloc_specific_checked (vtable, error);
6416         return_val_if_nok (error, NULL);
6417
6418         size = size - sizeof (MonoObject);
6419
6420 #ifdef HAVE_SGEN_GC
6421         g_assert (size == mono_class_value_size (klass, NULL));
6422         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6423 #else
6424 #if NO_UNALIGNED_ACCESS
6425         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6426 #else
6427         switch (size) {
6428         case 1:
6429                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6430                 break;
6431         case 2:
6432                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6433                 break;
6434         case 4:
6435                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6436                 break;
6437         case 8:
6438                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6439                 break;
6440         default:
6441                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6442         }
6443 #endif
6444 #endif
6445         if (klass->has_finalize) {
6446                 mono_object_register_finalizer (res);
6447                 return_val_if_nok (error, NULL);
6448         }
6449         return res;
6450 }
6451
6452 /**
6453  * mono_value_copy:
6454  * @dest: destination pointer
6455  * @src: source pointer
6456  * @klass: a valuetype class
6457  *
6458  * Copy a valuetype from @src to @dest. This function must be used
6459  * when @klass contains references fields.
6460  */
6461 void
6462 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6463 {
6464         MONO_REQ_GC_UNSAFE_MODE;
6465
6466         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6467 }
6468
6469 /**
6470  * mono_value_copy_array:
6471  * @dest: destination array
6472  * @dest_idx: index in the @dest array
6473  * @src: source pointer
6474  * @count: number of items
6475  *
6476  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
6477  * This function must be used when @klass contains references fields.
6478  * Overlap is handled.
6479  */
6480 void
6481 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6482 {
6483         MONO_REQ_GC_UNSAFE_MODE;
6484
6485         int size = mono_array_element_size (dest->obj.vtable->klass);
6486         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6487         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6488         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6489 }
6490
6491 /**
6492  * mono_object_get_domain:
6493  * @obj: object to query
6494  * 
6495  * Returns: the MonoDomain where the object is hosted
6496  */
6497 MonoDomain*
6498 mono_object_get_domain (MonoObject *obj)
6499 {
6500         MONO_REQ_GC_UNSAFE_MODE;
6501
6502         return mono_object_domain (obj);
6503 }
6504
6505 /**
6506  * mono_object_get_class:
6507  * @obj: object to query
6508  *
6509  * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6510  *
6511  * Returns: the MonoClass of the object.
6512  */
6513 MonoClass*
6514 mono_object_get_class (MonoObject *obj)
6515 {
6516         MONO_REQ_GC_UNSAFE_MODE;
6517
6518         return mono_object_class (obj);
6519 }
6520 /**
6521  * mono_object_get_size:
6522  * @o: object to query
6523  * 
6524  * Returns: the size, in bytes, of @o
6525  */
6526 guint
6527 mono_object_get_size (MonoObject* o)
6528 {
6529         MONO_REQ_GC_UNSAFE_MODE;
6530
6531         MonoClass* klass = mono_object_class (o);
6532         if (klass == mono_defaults.string_class) {
6533                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6534         } else if (o->vtable->rank) {
6535                 MonoArray *array = (MonoArray*)o;
6536                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6537                 if (array->bounds) {
6538                         size += 3;
6539                         size &= ~3;
6540                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
6541                 }
6542                 return size;
6543         } else {
6544                 return mono_class_instance_size (klass);
6545         }
6546 }
6547
6548 /**
6549  * mono_object_unbox:
6550  * @obj: object to unbox
6551  * 
6552  * Returns: a pointer to the start of the valuetype boxed in this
6553  * object.
6554  *
6555  * This method will assert if the object passed is not a valuetype.
6556  */
6557 gpointer
6558 mono_object_unbox (MonoObject *obj)
6559 {
6560         MONO_REQ_GC_UNSAFE_MODE;
6561
6562         /* add assert for valuetypes? */
6563         g_assert (obj->vtable->klass->valuetype);
6564         return ((char*)obj) + sizeof (MonoObject);
6565 }
6566
6567 /**
6568  * mono_object_isinst:
6569  * @obj: an object
6570  * @klass: a pointer to a class 
6571  *
6572  * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6573  */
6574 MonoObject *
6575 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6576 {
6577         MONO_REQ_GC_UNSAFE_MODE;
6578
6579         MonoError error;
6580         MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6581         mono_error_cleanup (&error);
6582         return result;
6583 }
6584         
6585
6586 /**
6587  * mono_object_isinst_checked:
6588  * @obj: an object
6589  * @klass: a pointer to a class 
6590  * @error: set on error
6591  *
6592  * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6593  * On failure returns NULL and sets @error.
6594  */
6595 MonoObject *
6596 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6597 {
6598         MONO_REQ_GC_UNSAFE_MODE;
6599
6600         mono_error_init (error);
6601         
6602         MonoObject *result = NULL;
6603
6604         if (!klass->inited)
6605                 mono_class_init (klass);
6606
6607         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6608                 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6609                 return result;
6610         }
6611
6612         if (!obj)
6613                 return NULL;
6614
6615         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6616 }
6617
6618 MonoObject *
6619 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6620 {
6621         MONO_REQ_GC_UNSAFE_MODE;
6622
6623         MonoError error;
6624         MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6625         mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6626         return result;
6627 }
6628
6629 MonoObject *
6630 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6631 {
6632         MONO_REQ_GC_UNSAFE_MODE;
6633
6634         MonoVTable *vt;
6635
6636         mono_error_init (error);
6637
6638         if (!obj)
6639                 return NULL;
6640
6641         vt = obj->vtable;
6642         
6643         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6644                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6645                         return obj;
6646                 }
6647
6648                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6649                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6650                         return obj;
6651         } else {
6652                 MonoClass *oklass = vt->klass;
6653                 if (mono_class_is_transparent_proxy (oklass))
6654                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6655
6656                 mono_class_setup_supertypes (klass);    
6657                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6658                         return obj;
6659         }
6660 #ifndef DISABLE_REMOTING
6661         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
6662         {
6663                 MonoDomain *domain = mono_domain_get ();
6664                 MonoObject *res;
6665                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6666                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6667                 MonoMethod *im = NULL;
6668                 gpointer pa [2];
6669
6670                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6671                 if (!im) {
6672                         mono_error_set_not_supported (error, "Linked away.");
6673                         return NULL;
6674                 }
6675                 im = mono_object_get_virtual_method (rp, im);
6676                 g_assert (im);
6677         
6678                 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6679                 return_val_if_nok (error, NULL);
6680                 pa [1] = obj;
6681
6682                 res = mono_runtime_invoke_checked (im, rp, pa, error);
6683                 return_val_if_nok (error, NULL);
6684
6685                 if (*(MonoBoolean *) mono_object_unbox(res)) {
6686                         /* Update the vtable of the remote type, so it can safely cast to this new type */
6687                         mono_upgrade_remote_class (domain, obj, klass, error);
6688                         return_val_if_nok (error, NULL);
6689                         return obj;
6690                 }
6691         }
6692 #endif /* DISABLE_REMOTING */
6693         return NULL;
6694 }
6695
6696 /**
6697  * mono_object_castclass_mbyref:
6698  * @obj: an object
6699  * @klass: a pointer to a class 
6700  *
6701  * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6702  */
6703 MonoObject *
6704 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6705 {
6706         MONO_REQ_GC_UNSAFE_MODE;
6707         MonoError error;
6708
6709         if (!obj) return NULL;
6710         if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6711         mono_error_cleanup (&error);
6712         return NULL;
6713 }
6714
6715 typedef struct {
6716         MonoDomain *orig_domain;
6717         MonoString *ins;
6718         MonoString *res;
6719 } LDStrInfo;
6720
6721 static void
6722 str_lookup (MonoDomain *domain, gpointer user_data)
6723 {
6724         MONO_REQ_GC_UNSAFE_MODE;
6725
6726         LDStrInfo *info = (LDStrInfo *)user_data;
6727         if (info->res || domain == info->orig_domain)
6728                 return;
6729         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6730 }
6731
6732 static MonoString*
6733 mono_string_get_pinned (MonoString *str, MonoError *error)
6734 {
6735         MONO_REQ_GC_UNSAFE_MODE;
6736
6737         mono_error_init (error);
6738
6739         /* We only need to make a pinned version of a string if this is a moving GC */
6740         if (!mono_gc_is_moving ())
6741                 return str;
6742         int size;
6743         MonoString *news;
6744         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6745         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6746         if (news) {
6747                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6748                 news->length = mono_string_length (str);
6749         } else {
6750                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6751         }
6752         return news;
6753 }
6754
6755 static MonoString*
6756 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6757 {
6758         MONO_REQ_GC_UNSAFE_MODE;
6759
6760         MonoGHashTable *ldstr_table;
6761         MonoString *s, *res;
6762         MonoDomain *domain;
6763         
6764         mono_error_init (error);
6765
6766         domain = ((MonoObject *)str)->vtable->domain;
6767         ldstr_table = domain->ldstr_table;
6768         ldstr_lock ();
6769         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6770         if (res) {
6771                 ldstr_unlock ();
6772                 return res;
6773         }
6774         if (insert) {
6775                 /* Allocate outside the lock */
6776                 ldstr_unlock ();
6777                 s = mono_string_get_pinned (str, error);
6778                 return_val_if_nok (error, NULL);
6779                 if (s) {
6780                         ldstr_lock ();
6781                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6782                         if (res) {
6783                                 ldstr_unlock ();
6784                                 return res;
6785                         }
6786                         mono_g_hash_table_insert (ldstr_table, s, s);
6787                         ldstr_unlock ();
6788                 }
6789                 return s;
6790         } else {
6791                 LDStrInfo ldstr_info;
6792                 ldstr_info.orig_domain = domain;
6793                 ldstr_info.ins = str;
6794                 ldstr_info.res = NULL;
6795
6796                 mono_domain_foreach (str_lookup, &ldstr_info);
6797                 if (ldstr_info.res) {
6798                         /* 
6799                          * the string was already interned in some other domain:
6800                          * intern it in the current one as well.
6801                          */
6802                         mono_g_hash_table_insert (ldstr_table, str, str);
6803                         ldstr_unlock ();
6804                         return str;
6805                 }
6806         }
6807         ldstr_unlock ();
6808         return NULL;
6809 }
6810
6811 /**
6812  * mono_string_is_interned:
6813  * @o: String to probe
6814  *
6815  * Returns whether the string has been interned.
6816  */
6817 MonoString*
6818 mono_string_is_interned (MonoString *o)
6819 {
6820         MonoError error;
6821         MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6822         /* This function does not fail. */
6823         mono_error_assert_ok (&error);
6824         return result;
6825 }
6826
6827 /**
6828  * mono_string_intern:
6829  * @o: String to intern
6830  *
6831  * Interns the string passed.  
6832  * Returns: The interned string.
6833  */
6834 MonoString*
6835 mono_string_intern (MonoString *str)
6836 {
6837         MonoError error;
6838         MonoString *result = mono_string_intern_checked (str, &error);
6839         mono_error_assert_ok (&error);
6840         return result;
6841 }
6842
6843 /**
6844  * mono_string_intern_checked:
6845  * @o: String to intern
6846  * @error: set on error.
6847  *
6848  * Interns the string passed.
6849  * Returns: The interned string.  On failure returns NULL and sets @error
6850  */
6851 MonoString*
6852 mono_string_intern_checked (MonoString *str, MonoError *error)
6853 {
6854         MONO_REQ_GC_UNSAFE_MODE;
6855
6856         mono_error_init (error);
6857
6858         return mono_string_is_interned_lookup (str, TRUE, error);
6859 }
6860
6861 /**
6862  * mono_ldstr:
6863  * @domain: the domain where the string will be used.
6864  * @image: a metadata context
6865  * @idx: index into the user string table.
6866  * 
6867  * Implementation for the ldstr opcode.
6868  * Returns: a loaded string from the @image/@idx combination.
6869  */
6870 MonoString*
6871 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6872 {
6873         MonoError error;
6874         MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6875         mono_error_cleanup (&error);
6876         return result;
6877 }
6878
6879 /**
6880  * mono_ldstr_checked:
6881  * @domain: the domain where the string will be used.
6882  * @image: a metadata context
6883  * @idx: index into the user string table.
6884  * @error: set on error.
6885  * 
6886  * Implementation for the ldstr opcode.
6887  * Returns: a loaded string from the @image/@idx combination.
6888  * On failure returns NULL and sets @error.
6889  */
6890 MonoString*
6891 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6892 {
6893         MONO_REQ_GC_UNSAFE_MODE;
6894         mono_error_init (error);
6895
6896         if (image->dynamic) {
6897                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6898                 return str;
6899         } else {
6900                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6901                         return NULL; /*FIXME we should probably be raising an exception here*/
6902                 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6903                 return str;
6904         }
6905 }
6906
6907 /**
6908  * mono_ldstr_metadata_sig
6909  * @domain: the domain for the string
6910  * @sig: the signature of a metadata string
6911  * @error: set on error
6912  *
6913  * Returns: a MonoString for a string stored in the metadata. On
6914  * failure returns NULL and sets @error.
6915  */
6916 static MonoString*
6917 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6918 {
6919         MONO_REQ_GC_UNSAFE_MODE;
6920
6921         mono_error_init (error);
6922         const char *str = sig;
6923         MonoString *o, *interned;
6924         size_t len2;
6925
6926         len2 = mono_metadata_decode_blob_size (str, &str);
6927         len2 >>= 1;
6928
6929         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6930         return_val_if_nok (error, NULL);
6931 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6932         {
6933                 int i;
6934                 guint16 *p2 = (guint16*)mono_string_chars (o);
6935                 for (i = 0; i < len2; ++i) {
6936                         *p2 = GUINT16_FROM_LE (*p2);
6937                         ++p2;
6938                 }
6939         }
6940 #endif
6941         ldstr_lock ();
6942         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6943         ldstr_unlock ();
6944         if (interned)
6945                 return interned; /* o will get garbage collected */
6946
6947         o = mono_string_get_pinned (o, error);
6948         if (o) {
6949                 ldstr_lock ();
6950                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6951                 if (!interned) {
6952                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6953                         interned = o;
6954                 }
6955                 ldstr_unlock ();
6956         }
6957
6958         return interned;
6959 }
6960
6961 /*
6962  * mono_ldstr_utf8:
6963  *
6964  *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
6965  * of an object.
6966  */
6967 char*
6968 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6969 {
6970         const char *str;
6971         size_t len2;
6972         long written = 0;
6973         char *as;
6974         GError *gerror = NULL;
6975
6976         mono_error_init (error);
6977
6978         if (!mono_verifier_verify_string_signature (image, idx, NULL))
6979                 return NULL; /*FIXME we should probably be raising an exception here*/
6980         str = mono_metadata_user_string (image, idx);
6981
6982         len2 = mono_metadata_decode_blob_size (str, &str);
6983         len2 >>= 1;
6984
6985         as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6986         if (gerror) {
6987                 mono_error_set_argument (error, "string", "%s", gerror->message);
6988                 g_error_free (gerror);
6989                 return NULL;
6990         }
6991         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6992         if (len2 > written) {
6993                 /* allocate the total length and copy the part of the string that has been converted */
6994                 char *as2 = (char *)g_malloc0 (len2);
6995                 memcpy (as2, as, written);
6996                 g_free (as);
6997                 as = as2;
6998         }
6999
7000         return as;
7001 }
7002
7003 /**
7004  * mono_string_to_utf8:
7005  * @s: a System.String
7006  *
7007  * Returns the UTF8 representation for @s.
7008  * The resulting buffer needs to be freed with mono_free().
7009  *
7010  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7011  */
7012 char *
7013 mono_string_to_utf8 (MonoString *s)
7014 {
7015         MONO_REQ_GC_UNSAFE_MODE;
7016
7017         MonoError error;
7018         char *result = mono_string_to_utf8_checked (s, &error);
7019         
7020         if (!is_ok (&error)) {
7021                 mono_error_cleanup (&error);
7022                 return NULL;
7023         }
7024         return result;
7025 }
7026
7027 /**
7028  * mono_string_to_utf8_checked:
7029  * @s: a System.String
7030  * @error: a MonoError.
7031  * 
7032  * Converts a MonoString to its UTF8 representation. May fail; check 
7033  * @error to determine whether the conversion was successful.
7034  * The resulting buffer should be freed with mono_free().
7035  */
7036 char *
7037 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7038 {
7039         MONO_REQ_GC_UNSAFE_MODE;
7040
7041         long written = 0;
7042         char *as;
7043         GError *gerror = NULL;
7044
7045         mono_error_init (error);
7046
7047         if (s == NULL)
7048                 return NULL;
7049
7050         if (!s->length)
7051                 return g_strdup ("");
7052
7053         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7054         if (gerror) {
7055                 mono_error_set_argument (error, "string", "%s", gerror->message);
7056                 g_error_free (gerror);
7057                 return NULL;
7058         }
7059         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7060         if (s->length > written) {
7061                 /* allocate the total length and copy the part of the string that has been converted */
7062                 char *as2 = (char *)g_malloc0 (s->length);
7063                 memcpy (as2, as, written);
7064                 g_free (as);
7065                 as = as2;
7066         }
7067
7068         return as;
7069 }
7070
7071 /**
7072  * mono_string_to_utf8_ignore:
7073  * @s: a MonoString
7074  *
7075  * Converts a MonoString to its UTF8 representation. Will ignore
7076  * invalid surrogate pairs.
7077  * The resulting buffer should be freed with mono_free().
7078  * 
7079  */
7080 char *
7081 mono_string_to_utf8_ignore (MonoString *s)
7082 {
7083         MONO_REQ_GC_UNSAFE_MODE;
7084
7085         long written = 0;
7086         char *as;
7087
7088         if (s == NULL)
7089                 return NULL;
7090
7091         if (!s->length)
7092                 return g_strdup ("");
7093
7094         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7095
7096         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7097         if (s->length > written) {
7098                 /* allocate the total length and copy the part of the string that has been converted */
7099                 char *as2 = (char *)g_malloc0 (s->length);
7100                 memcpy (as2, as, written);
7101                 g_free (as);
7102                 as = as2;
7103         }
7104
7105         return as;
7106 }
7107
7108 /**
7109  * mono_string_to_utf8_image_ignore:
7110  * @s: a System.String
7111  *
7112  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7113  */
7114 char *
7115 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7116 {
7117         MONO_REQ_GC_UNSAFE_MODE;
7118
7119         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7120 }
7121
7122 /**
7123  * mono_string_to_utf8_mp_ignore:
7124  * @s: a System.String
7125  *
7126  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7127  */
7128 char *
7129 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7130 {
7131         MONO_REQ_GC_UNSAFE_MODE;
7132
7133         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7134 }
7135
7136
7137 /**
7138  * mono_string_to_utf16:
7139  * @s: a MonoString
7140  *
7141  * Return an null-terminated array of the utf-16 chars
7142  * contained in @s. The result must be freed with g_free().
7143  * This is a temporary helper until our string implementation
7144  * is reworked to always include the null terminating char.
7145  */
7146 mono_unichar2*
7147 mono_string_to_utf16 (MonoString *s)
7148 {
7149         MONO_REQ_GC_UNSAFE_MODE;
7150
7151         char *as;
7152
7153         if (s == NULL)
7154                 return NULL;
7155
7156         as = (char *)g_malloc ((s->length * 2) + 2);
7157         as [(s->length * 2)] = '\0';
7158         as [(s->length * 2) + 1] = '\0';
7159
7160         if (!s->length) {
7161                 return (gunichar2 *)(as);
7162         }
7163         
7164         memcpy (as, mono_string_chars(s), s->length * 2);
7165         return (gunichar2 *)(as);
7166 }
7167
7168 /**
7169  * mono_string_to_utf32:
7170  * @s: a MonoString
7171  *
7172  * Return an null-terminated array of the UTF-32 (UCS-4) chars
7173  * contained in @s. The result must be freed with g_free().
7174  */
7175 mono_unichar4*
7176 mono_string_to_utf32 (MonoString *s)
7177 {
7178         MONO_REQ_GC_UNSAFE_MODE;
7179
7180         mono_unichar4 *utf32_output = NULL; 
7181         GError *error = NULL;
7182         glong items_written;
7183         
7184         if (s == NULL)
7185                 return NULL;
7186                 
7187         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7188         
7189         if (error)
7190                 g_error_free (error);
7191
7192         return utf32_output;
7193 }
7194
7195 /**
7196  * mono_string_from_utf16:
7197  * @data: the UTF16 string (LPWSTR) to convert
7198  *
7199  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7200  *
7201  * Returns: a MonoString.
7202  */
7203 MonoString *
7204 mono_string_from_utf16 (gunichar2 *data)
7205 {
7206         MonoError error;
7207         MonoString *result = mono_string_from_utf16_checked (data, &error);
7208         mono_error_cleanup (&error);
7209         return result;
7210 }
7211
7212 /**
7213  * mono_string_from_utf16_checked:
7214  * @data: the UTF16 string (LPWSTR) to convert
7215  * @error: set on error
7216  *
7217  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7218  *
7219  * Returns: a MonoString. On failure sets @error and returns NULL.
7220  */
7221 MonoString *
7222 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7223 {
7224
7225         MONO_REQ_GC_UNSAFE_MODE;
7226
7227         mono_error_init (error);
7228         MonoDomain *domain = mono_domain_get ();
7229         int len = 0;
7230
7231         if (!data)
7232                 return NULL;
7233
7234         while (data [len]) len++;
7235
7236         return mono_string_new_utf16_checked (domain, data, len, error);
7237 }
7238
7239 /**
7240  * mono_string_from_utf32:
7241  * @data: the UTF32 string (LPWSTR) to convert
7242  *
7243  * Converts a UTF32 (UCS-4)to a MonoString.
7244  *
7245  * Returns: a MonoString.
7246  */
7247 MonoString *
7248 mono_string_from_utf32 (mono_unichar4 *data)
7249 {
7250         MonoError error;
7251         MonoString *result = mono_string_from_utf32_checked (data, &error);
7252         mono_error_cleanup (&error);
7253         return result;
7254 }
7255
7256 /**
7257  * mono_string_from_utf32_checked:
7258  * @data: the UTF32 string (LPWSTR) to convert
7259  * @error: set on error
7260  *
7261  * Converts a UTF32 (UCS-4)to a MonoString.
7262  *
7263  * Returns: a MonoString. On failure returns NULL and sets @error.
7264  */
7265 MonoString *
7266 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7267 {
7268         MONO_REQ_GC_UNSAFE_MODE;
7269
7270         mono_error_init (error);
7271         MonoString* result = NULL;
7272         mono_unichar2 *utf16_output = NULL;
7273         GError *gerror = NULL;
7274         glong items_written;
7275         int len = 0;
7276
7277         if (!data)
7278                 return NULL;
7279
7280         while (data [len]) len++;
7281
7282         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7283
7284         if (gerror)
7285                 g_error_free (gerror);
7286
7287         result = mono_string_from_utf16_checked (utf16_output, error);
7288         g_free (utf16_output);
7289         return result;
7290 }
7291
7292 static char *
7293 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7294 {
7295         MONO_REQ_GC_UNSAFE_MODE;
7296
7297         char *r;
7298         char *mp_s;
7299         int len;
7300
7301         if (ignore_error) {
7302                 r = mono_string_to_utf8_ignore (s);
7303         } else {
7304                 r = mono_string_to_utf8_checked (s, error);
7305                 if (!mono_error_ok (error))
7306                         return NULL;
7307         }
7308
7309         if (!mp && !image)
7310                 return r;
7311
7312         len = strlen (r) + 1;
7313         if (mp)
7314                 mp_s = (char *)mono_mempool_alloc (mp, len);
7315         else
7316                 mp_s = (char *)mono_image_alloc (image, len);
7317
7318         memcpy (mp_s, r, len);
7319
7320         g_free (r);
7321
7322         return mp_s;
7323 }
7324
7325 /**
7326  * mono_string_to_utf8_image:
7327  * @s: a System.String
7328  *
7329  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7330  */
7331 char *
7332 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7333 {
7334         MONO_REQ_GC_UNSAFE_MODE;
7335
7336         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7337 }
7338
7339 /**
7340  * mono_string_to_utf8_mp:
7341  * @s: a System.String
7342  *
7343  * Same as mono_string_to_utf8, but allocate the string from a mempool.
7344  */
7345 char *
7346 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7347 {
7348         MONO_REQ_GC_UNSAFE_MODE;
7349
7350         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7351 }
7352
7353
7354 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7355
7356 void
7357 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7358 {
7359         eh_callbacks = *cbs;
7360 }
7361
7362 MonoRuntimeExceptionHandlingCallbacks *
7363 mono_get_eh_callbacks (void)
7364 {
7365         return &eh_callbacks;
7366 }
7367
7368 /**
7369  * mono_raise_exception:
7370  * @ex: exception object
7371  *
7372  * Signal the runtime that the exception @ex has been raised in unmanaged code.
7373  */
7374 void
7375 mono_raise_exception (MonoException *ex) 
7376 {
7377         MONO_REQ_GC_UNSAFE_MODE;
7378
7379         /*
7380          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7381          * that will cause gcc to omit the function epilog, causing problems when
7382          * the JIT tries to walk the stack, since the return address on the stack
7383          * will point into the next function in the executable, not this one.
7384          */     
7385         eh_callbacks.mono_raise_exception (ex);
7386 }
7387
7388 void
7389 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
7390 {
7391         MONO_REQ_GC_UNSAFE_MODE;
7392
7393         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7394 }
7395
7396 /**
7397  * mono_wait_handle_new:
7398  * @domain: Domain where the object will be created
7399  * @handle: Handle for the wait handle
7400  * @error: set on error.
7401  *
7402  * Returns: A new MonoWaitHandle created in the given domain for the
7403  * given handle.  On failure returns NULL and sets @rror.
7404  */
7405 MonoWaitHandle *
7406 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7407 {
7408         MONO_REQ_GC_UNSAFE_MODE;
7409
7410         MonoWaitHandle *res;
7411         gpointer params [1];
7412         static MonoMethod *handle_set;
7413
7414         mono_error_init (error);
7415         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7416         return_val_if_nok (error, NULL);
7417
7418         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
7419         if (!handle_set)
7420                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7421
7422         params [0] = &handle;
7423
7424         mono_runtime_invoke_checked (handle_set, res, params, error);
7425         return res;
7426 }
7427
7428 HANDLE
7429 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7430 {
7431         MONO_REQ_GC_UNSAFE_MODE;
7432
7433         static MonoClassField *f_safe_handle = NULL;
7434         MonoSafeHandle *sh;
7435
7436         if (!f_safe_handle) {
7437                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7438                 g_assert (f_safe_handle);
7439         }
7440
7441         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7442         return sh->handle;
7443 }
7444
7445
7446 static MonoObject*
7447 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7448 {
7449         MONO_REQ_GC_UNSAFE_MODE;
7450
7451         RuntimeInvokeFunction runtime_invoke;
7452
7453         mono_error_init (error);
7454
7455         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7456                 MonoMethod *method = mono_get_context_capture_method ();
7457                 MonoMethod *wrapper;
7458                 if (!method)
7459                         return NULL;
7460                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7461                 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7462                 return_val_if_nok (error, NULL);
7463                 domain->capture_context_method = mono_compile_method_checked (method, error);
7464                 return_val_if_nok (error, NULL);
7465         }
7466
7467         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7468
7469         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7470 }
7471 /**
7472  * mono_async_result_new:
7473  * @domain:domain where the object will be created.
7474  * @handle: wait handle.
7475  * @state: state to pass to AsyncResult
7476  * @data: C closure data.
7477  * @error: set on error.
7478  *
7479  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7480  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7481  * On failure returns NULL and sets @error.
7482  *
7483  */
7484 MonoAsyncResult *
7485 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7486 {
7487         MONO_REQ_GC_UNSAFE_MODE;
7488
7489         mono_error_init (error);
7490         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7491         return_val_if_nok (error, NULL);
7492         MonoObject *context = mono_runtime_capture_context (domain, error);
7493         return_val_if_nok (error, NULL);
7494         /* we must capture the execution context from the original thread */
7495         if (context) {
7496                 MONO_OBJECT_SETREF (res, execution_context, context);
7497                 /* note: result may be null if the flow is suppressed */
7498         }
7499
7500         res->data = (void **)data;
7501         MONO_OBJECT_SETREF (res, object_data, object_data);
7502         MONO_OBJECT_SETREF (res, async_state, state);
7503         MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7504         return_val_if_nok (error, NULL);
7505         if (handle != NULL)
7506                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7507
7508         res->sync_completed = FALSE;
7509         res->completed = FALSE;
7510
7511         return res;
7512 }
7513
7514 MonoObject *
7515 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7516 {
7517         MONO_REQ_GC_UNSAFE_MODE;
7518
7519         MonoError error;
7520         MonoAsyncCall *ac;
7521         MonoObject *res;
7522
7523         g_assert (ares);
7524         g_assert (ares->async_delegate);
7525
7526         ac = (MonoAsyncCall*) ares->object_data;
7527         if (!ac) {
7528                 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7529                 if (mono_error_set_pending_exception (&error))
7530                         return NULL;
7531         } else {
7532                 gpointer wait_event = NULL;
7533
7534                 ac->msg->exc = NULL;
7535                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7536                 if (mono_error_set_pending_exception (&error))
7537                         return NULL;
7538                 MONO_OBJECT_SETREF (ac, res, res);
7539
7540                 mono_monitor_enter ((MonoObject*) ares);
7541                 ares->completed = 1;
7542                 if (ares->handle)
7543                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7544                 mono_monitor_exit ((MonoObject*) ares);
7545
7546                 if (wait_event != NULL)
7547                         SetEvent (wait_event);
7548
7549                 if (ac->cb_method) {
7550                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7551                         if (mono_error_set_pending_exception (&error))
7552                                 return NULL;
7553                 }
7554         }
7555
7556         return res;
7557 }
7558
7559 gboolean
7560 mono_message_init (MonoDomain *domain,
7561                    MonoMethodMessage *this_obj, 
7562                    MonoReflectionMethod *method,
7563                    MonoArray *out_args,
7564                    MonoError *error)
7565 {
7566         MONO_REQ_GC_UNSAFE_MODE;
7567
7568         static MonoMethod *init_message_method = NULL;
7569
7570         if (!init_message_method) {
7571                 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7572                 g_assert (init_message_method != NULL);
7573         }
7574
7575         mono_error_init (error);
7576         /* FIXME set domain instead? */
7577         g_assert (domain == mono_domain_get ());
7578         
7579         gpointer args[2];
7580
7581         args[0] = method;
7582         args[1] = out_args;
7583
7584         mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7585         return is_ok (error);
7586 }
7587
7588 #ifndef DISABLE_REMOTING
7589 /**
7590  * mono_remoting_invoke:
7591  * @real_proxy: pointer to a RealProxy object
7592  * @msg: The MonoMethodMessage to execute
7593  * @exc: used to store exceptions
7594  * @out_args: used to store output arguments
7595  *
7596  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7597  * IMessage interface and it is not trivial to extract results from there. So
7598  * we call an helper method PrivateInvoke instead of calling
7599  * RealProxy::Invoke() directly.
7600  *
7601  * Returns: the result object.
7602  */
7603 MonoObject *
7604 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7605 {
7606         MONO_REQ_GC_UNSAFE_MODE;
7607
7608         MonoObject *o;
7609         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7610         gpointer pa [4];
7611
7612         g_assert (exc);
7613
7614         mono_error_init (error);
7615
7616         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7617
7618         if (!im) {
7619                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7620                 if (!im) {
7621                         mono_error_set_not_supported (error, "Linked away.");
7622                         return NULL;
7623                 }
7624                 real_proxy->vtable->domain->private_invoke_method = im;
7625         }
7626
7627         pa [0] = real_proxy;
7628         pa [1] = msg;
7629         pa [2] = exc;
7630         pa [3] = out_args;
7631
7632         o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7633         return_val_if_nok (error, NULL);
7634
7635         return o;
7636 }
7637 #endif
7638
7639 MonoObject *
7640 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
7641                      MonoObject **exc, MonoArray **out_args, MonoError *error) 
7642 {
7643         MONO_REQ_GC_UNSAFE_MODE;
7644
7645         static MonoClass *object_array_klass;
7646         mono_error_init (error);
7647
7648         MonoDomain *domain; 
7649         MonoMethod *method;
7650         MonoMethodSignature *sig;
7651         MonoArray *arr;
7652         int i, j, outarg_count = 0;
7653
7654 #ifndef DISABLE_REMOTING
7655         if (target && mono_object_is_transparent_proxy (target)) {
7656                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7657                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7658                         target = tp->rp->unwrapped_server;
7659                 } else {
7660                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7661                 }
7662         }
7663 #endif
7664
7665         domain = mono_domain_get (); 
7666         method = msg->method->method;
7667         sig = mono_method_signature (method);
7668
7669         for (i = 0; i < sig->param_count; i++) {
7670                 if (sig->params [i]->byref) 
7671                         outarg_count++;
7672         }
7673
7674         if (!object_array_klass) {
7675                 MonoClass *klass;
7676
7677                 klass = mono_array_class_get (mono_defaults.object_class, 1);
7678                 g_assert (klass);
7679
7680                 mono_memory_barrier ();
7681                 object_array_klass = klass;
7682         }
7683
7684         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7685         return_val_if_nok (error, NULL);
7686
7687         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7688         *exc = NULL;
7689
7690         MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7691         return_val_if_nok (error, NULL);
7692
7693         for (i = 0, j = 0; i < sig->param_count; i++) {
7694                 if (sig->params [i]->byref) {
7695                         MonoObject* arg;
7696                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7697                         mono_array_setref (*out_args, j, arg);
7698                         j++;
7699                 }
7700         }
7701
7702         return ret;
7703 }
7704
7705 /**
7706  * prepare_to_string_method:
7707  * @obj: The object
7708  * @target: Set to @obj or unboxed value if a valuetype
7709  *
7710  * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7711  */
7712 static MonoMethod *
7713 prepare_to_string_method (MonoObject *obj, void **target)
7714 {
7715         MONO_REQ_GC_UNSAFE_MODE;
7716
7717         static MonoMethod *to_string = NULL;
7718         MonoMethod *method;
7719         g_assert (target);
7720         g_assert (obj);
7721
7722         *target = obj;
7723
7724         if (!to_string)
7725                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7726
7727         method = mono_object_get_virtual_method (obj, to_string);
7728
7729         // Unbox value type if needed
7730         if (mono_class_is_valuetype (mono_method_get_class (method))) {
7731                 *target = mono_object_unbox (obj);
7732         }
7733         return method;
7734 }
7735
7736 /**
7737  * mono_object_to_string:
7738  * @obj: The object
7739  * @exc: Any exception thrown by ToString (). May be NULL.
7740  *
7741  * Returns: the result of calling ToString () on an object.
7742  */
7743 MonoString *
7744 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7745 {
7746         MonoError error;
7747         MonoString *s = NULL;
7748         void *target;
7749         MonoMethod *method = prepare_to_string_method (obj, &target);
7750         if (exc) {
7751                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7752                 if (*exc == NULL && !mono_error_ok (&error))
7753                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7754                 else
7755                         mono_error_cleanup (&error);
7756         } else {
7757                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7758                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7759         }
7760
7761         return s;
7762 }
7763
7764 /**
7765  * mono_object_to_string_checked:
7766  * @obj: The object
7767  * @error: Set on error.
7768  *
7769  * Returns: the result of calling ToString () on an object. If the
7770  * method cannot be invoked or if it raises an exception, sets @error
7771  * and returns NULL.
7772  */
7773 MonoString *
7774 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7775 {
7776         mono_error_init (error);
7777         void *target;
7778         MonoMethod *method = prepare_to_string_method (obj, &target);
7779         return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7780 }
7781
7782 /**
7783  * mono_object_try_to_string:
7784  * @obj: The object
7785  * @exc: Any exception thrown by ToString (). Must not be NULL.
7786  * @error: Set if method cannot be invoked.
7787  *
7788  * Returns: the result of calling ToString () on an object. If the
7789  * method cannot be invoked sets @error, if it raises an exception sets @exc,
7790  * and returns NULL.
7791  */
7792 MonoString *
7793 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7794 {
7795         g_assert (exc);
7796         mono_error_init (error);
7797         void *target;
7798         MonoMethod *method = prepare_to_string_method (obj, &target);
7799         return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7800 }
7801
7802
7803
7804 /**
7805  * mono_print_unhandled_exception:
7806  * @exc: The exception
7807  *
7808  * Prints the unhandled exception.
7809  */
7810 void
7811 mono_print_unhandled_exception (MonoObject *exc)
7812 {
7813         MONO_REQ_GC_UNSAFE_MODE;
7814
7815         MonoString * str;
7816         char *message = (char*)"";
7817         gboolean free_message = FALSE;
7818         MonoError error;
7819
7820         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7821                 message = g_strdup ("OutOfMemoryException");
7822                 free_message = TRUE;
7823         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7824                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7825                 free_message = TRUE;
7826         } else {
7827                 
7828                 if (((MonoException*)exc)->native_trace_ips) {
7829                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
7830                         free_message = TRUE;
7831                 } else {
7832                         MonoObject *other_exc = NULL;
7833                         str = mono_object_try_to_string (exc, &other_exc, &error);
7834                         if (other_exc == NULL && !is_ok (&error))
7835                                 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7836                         else
7837                                 mono_error_cleanup (&error);
7838                         if (other_exc) {
7839                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7840                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7841                                 
7842                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7843                                         original_backtrace, nested_backtrace);
7844
7845                                 g_free (original_backtrace);
7846                                 g_free (nested_backtrace);
7847                                 free_message = TRUE;
7848                         } else if (str) {
7849                                 message = mono_string_to_utf8_checked (str, &error);
7850                                 if (!mono_error_ok (&error)) {
7851                                         mono_error_cleanup (&error);
7852                                         message = (char *) "";
7853                                 } else {
7854                                         free_message = TRUE;
7855                                 }
7856                         }
7857                 }
7858         }
7859
7860         /*
7861          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7862          *         exc->vtable->klass->name, message);
7863          */
7864         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7865         
7866         if (free_message)
7867                 g_free (message);
7868 }
7869
7870 /**
7871  * mono_delegate_ctor_with_method:
7872  * @this: pointer to an uninitialized delegate object
7873  * @target: target object
7874  * @addr: pointer to native code
7875  * @method: method
7876  * @error: set on error.
7877  *
7878  * Initialize a delegate and sets a specific method, not the one
7879  * associated with addr.  This is useful when sharing generic code.
7880  * In that case addr will most probably not be associated with the
7881  * correct instantiation of the method.
7882  * On failure returns FALSE and sets @error.
7883  */
7884 gboolean
7885 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7886 {
7887         MONO_REQ_GC_UNSAFE_MODE;
7888
7889         mono_error_init (error);
7890         MonoDelegate *delegate = (MonoDelegate *)this_obj;
7891
7892         g_assert (this_obj);
7893         g_assert (addr);
7894
7895         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7896
7897         if (method)
7898                 delegate->method = method;
7899
7900         mono_stats.delegate_creations++;
7901
7902 #ifndef DISABLE_REMOTING
7903         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7904                 g_assert (method);
7905                 method = mono_marshal_get_remoting_invoke (method);
7906                 delegate->method_ptr = mono_compile_method_checked (method, error);
7907                 return_val_if_nok (error, FALSE);
7908                 MONO_OBJECT_SETREF (delegate, target, target);
7909         } else
7910 #endif
7911         {
7912                 delegate->method_ptr = addr;
7913                 MONO_OBJECT_SETREF (delegate, target, target);
7914         }
7915
7916         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7917         if (callbacks.init_delegate)
7918                 callbacks.init_delegate (delegate);
7919         return TRUE;
7920 }
7921
7922 /**
7923  * mono_delegate_ctor:
7924  * @this: pointer to an uninitialized delegate object
7925  * @target: target object
7926  * @addr: pointer to native code
7927  * @error: set on error.
7928  *
7929  * This is used to initialize a delegate.
7930  * On failure returns FALSE and sets @error.
7931  */
7932 gboolean
7933 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7934 {
7935         MONO_REQ_GC_UNSAFE_MODE;
7936
7937         mono_error_init (error);
7938         MonoDomain *domain = mono_domain_get ();
7939         MonoJitInfo *ji;
7940         MonoMethod *method = NULL;
7941
7942         g_assert (addr);
7943
7944         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7945         /* Shared code */
7946         if (!ji && domain != mono_get_root_domain ())
7947                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7948         if (ji) {
7949                 method = mono_jit_info_get_method (ji);
7950                 g_assert (!method->klass->generic_container);
7951         }
7952
7953         return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7954 }
7955
7956 /**
7957  * mono_method_call_message_new:
7958  * @method: method to encapsulate
7959  * @params: parameters to the method
7960  * @invoke: optional, delegate invoke.
7961  * @cb: async callback delegate.
7962  * @state: state passed to the async callback.
7963  * @error: set on error.
7964  *
7965  * Translates arguments pointers into a MonoMethodMessage.
7966  * On failure returns NULL and sets @error.
7967  */
7968 MonoMethodMessage *
7969 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7970                               MonoDelegate **cb, MonoObject **state, MonoError *error)
7971 {
7972         MONO_REQ_GC_UNSAFE_MODE;
7973
7974         mono_error_init (error);
7975
7976         MonoDomain *domain = mono_domain_get ();
7977         MonoMethodSignature *sig = mono_method_signature (method);
7978         MonoMethodMessage *msg;
7979         int i, count;
7980
7981         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error); 
7982         return_val_if_nok  (error, NULL);
7983
7984         if (invoke) {
7985                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7986                 return_val_if_nok (error, NULL);
7987                 mono_message_init (domain, msg, rm, NULL, error);
7988                 return_val_if_nok (error, NULL);
7989                 count =  sig->param_count - 2;
7990         } else {
7991                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, 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;
7996         }
7997
7998         for (i = 0; i < count; i++) {
7999                 gpointer vpos;
8000                 MonoClass *klass;
8001                 MonoObject *arg;
8002
8003                 if (sig->params [i]->byref)
8004                         vpos = *((gpointer *)params [i]);
8005                 else 
8006                         vpos = params [i];
8007
8008                 klass = mono_class_from_mono_type (sig->params [i]);
8009
8010                 if (klass->valuetype) {
8011                         arg = mono_value_box_checked (domain, klass, vpos, error);
8012                         return_val_if_nok (error, NULL);
8013                 } else 
8014                         arg = *((MonoObject **)vpos);
8015                       
8016                 mono_array_setref (msg->args, i, arg);
8017         }
8018
8019         if (cb != NULL && state != NULL) {
8020                 *cb = *((MonoDelegate **)params [i]);
8021                 i++;
8022                 *state = *((MonoObject **)params [i]);
8023         }
8024
8025         return msg;
8026 }
8027
8028 /**
8029  * mono_method_return_message_restore:
8030  *
8031  * Restore results from message based processing back to arguments pointers
8032  */
8033 void
8034 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8035 {
8036         MONO_REQ_GC_UNSAFE_MODE;
8037
8038         mono_error_init (error);
8039
8040         MonoMethodSignature *sig = mono_method_signature (method);
8041         int i, j, type, size, out_len;
8042         
8043         if (out_args == NULL)
8044                 return;
8045         out_len = mono_array_length (out_args);
8046         if (out_len == 0)
8047                 return;
8048
8049         for (i = 0, j = 0; i < sig->param_count; i++) {
8050                 MonoType *pt = sig->params [i];
8051
8052                 if (pt->byref) {
8053                         char *arg;
8054                         if (j >= out_len) {
8055                                 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8056                                 return;
8057                         }
8058
8059                         arg = (char *)mono_array_get (out_args, gpointer, j);
8060                         type = pt->type;
8061
8062                         g_assert (type != MONO_TYPE_VOID);
8063
8064                         if (MONO_TYPE_IS_REFERENCE (pt)) {
8065                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8066                         } else {
8067                                 if (arg) {
8068                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8069                                         size = mono_class_value_size (klass, NULL);
8070                                         if (klass->has_references)
8071                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8072                                         else
8073                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8074                                 } else {
8075                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8076                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8077                                 }
8078                         }
8079
8080                         j++;
8081                 }
8082         }
8083 }
8084
8085 #ifndef DISABLE_REMOTING
8086
8087 /**
8088  * mono_load_remote_field:
8089  * @this: pointer to an object
8090  * @klass: klass of the object containing @field
8091  * @field: the field to load
8092  * @res: a storage to store the result
8093  *
8094  * This method is called by the runtime on attempts to load fields of
8095  * transparent proxy objects. @this points to such TP, @klass is the class of
8096  * the object containing @field. @res is a storage location which can be
8097  * used to store the result.
8098  *
8099  * Returns: an address pointing to the value of field.
8100  */
8101 gpointer
8102 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8103 {
8104         MonoError error;
8105         gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8106         mono_error_cleanup (&error);
8107         return result;
8108 }
8109
8110 /**
8111  * mono_load_remote_field_checked:
8112  * @this: pointer to an object
8113  * @klass: klass of the object containing @field
8114  * @field: the field to load
8115  * @res: a storage to store the result
8116  * @error: set on error
8117  *
8118  * This method is called by the runtime on attempts to load fields of
8119  * transparent proxy objects. @this points to such TP, @klass is the class of
8120  * the object containing @field. @res is a storage location which can be
8121  * used to store the result.
8122  *
8123  * Returns: an address pointing to the value of field.  On failure returns NULL and sets @error.
8124  */
8125 gpointer
8126 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8127 {
8128         MONO_REQ_GC_UNSAFE_MODE;
8129
8130         static MonoMethod *getter = NULL;
8131
8132         mono_error_init (error);
8133
8134         MonoDomain *domain = mono_domain_get ();
8135         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8136         MonoClass *field_class;
8137         MonoMethodMessage *msg;
8138         MonoArray *out_args;
8139         MonoObject *exc;
8140         char* full_name;
8141
8142         g_assert (mono_object_is_transparent_proxy (this_obj));
8143         g_assert (res != NULL);
8144
8145         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8146                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8147                 return res;
8148         }
8149         
8150         if (!getter) {
8151                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8152                 if (!getter) {
8153                         mono_error_set_not_supported (error, "Linked away.");
8154                         return NULL;
8155                 }
8156         }
8157         
8158         field_class = mono_class_from_mono_type (field->type);
8159
8160         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8161         return_val_if_nok (error, NULL);
8162         out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8163         return_val_if_nok (error, NULL);
8164         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8165         return_val_if_nok (error, NULL);
8166         mono_message_init (domain, msg, rm, out_args, error);
8167         return_val_if_nok (error, NULL);
8168
8169         full_name = mono_type_get_full_name (klass);
8170         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8171         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8172         g_free (full_name);
8173
8174         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8175         return_val_if_nok (error, NULL);
8176
8177         if (exc) {
8178                 mono_error_set_exception_instance (error, (MonoException *)exc);
8179                 return NULL;
8180         }
8181
8182         if (mono_array_length (out_args) == 0)
8183                 return NULL;
8184
8185         mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8186
8187         if (field_class->valuetype) {
8188                 return ((char *)*res) + sizeof (MonoObject);
8189         } else
8190                 return res;
8191 }
8192
8193 /**
8194  * mono_load_remote_field_new:
8195  * @this: 
8196  * @klass: 
8197  * @field:
8198  *
8199  * Missing documentation.
8200  */
8201 MonoObject *
8202 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8203 {
8204         MonoError error;
8205
8206         MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8207         mono_error_cleanup (&error);
8208         return result;
8209 }
8210
8211 /**
8212  * mono_load_remote_field_new_icall:
8213  * @this: pointer to an object
8214  * @klass: klass of the object containing @field
8215  * @field: the field to load
8216  *
8217  * This method is called by the runtime on attempts to load fields of
8218  * transparent proxy objects. @this points to such TP, @klass is the class of
8219  * the object containing @field.
8220  * 
8221  * Returns: a freshly allocated object containing the value of the
8222  * field.  On failure returns NULL and throws an exception.
8223  */
8224 MonoObject *
8225 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8226 {
8227         MonoError error;
8228         MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8229         mono_error_set_pending_exception (&error);
8230         return result;
8231 }
8232
8233 /**
8234  * mono_load_remote_field_new_checked:
8235  * @this: pointer to an object
8236  * @klass: klass of the object containing @field
8237  * @field: the field to load
8238  * @error: set on error.
8239  *
8240  * This method is called by the runtime on attempts to load fields of
8241  * transparent proxy objects. @this points to such TP, @klass is the class of
8242  * the object containing @field.
8243  * 
8244  * Returns: a freshly allocated object containing the value of the field.  On failure returns NULL and sets @error.
8245  */
8246 MonoObject *
8247 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8248 {
8249         MONO_REQ_GC_UNSAFE_MODE;
8250
8251         mono_error_init (error);
8252
8253         static MonoMethod *getter = NULL;
8254         MonoDomain *domain = mono_domain_get ();
8255         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8256         MonoClass *field_class;
8257         MonoMethodMessage *msg;
8258         MonoArray *out_args;
8259         MonoObject *exc, *res;
8260         char* full_name;
8261
8262         g_assert (mono_object_is_transparent_proxy (this_obj));
8263
8264         field_class = mono_class_from_mono_type (field->type);
8265
8266         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8267                 gpointer val;
8268                 if (field_class->valuetype) {
8269                         res = mono_object_new_checked (domain, field_class, error);
8270                         return_val_if_nok (error, NULL);
8271                         val = ((gchar *) res) + sizeof (MonoObject);
8272                 } else {
8273                         val = &res;
8274                 }
8275                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
8276                 return res;
8277         }
8278
8279         if (!getter) {
8280                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8281                 if (!getter) {
8282                         mono_error_set_not_supported (error, "Linked away.");
8283                         return NULL;
8284                 }
8285         }
8286         
8287         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8288         return_val_if_nok (error, NULL);
8289         out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8290         return_val_if_nok (error, NULL);
8291
8292         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8293         return_val_if_nok (error, NULL);
8294         mono_message_init (domain, msg, rm, out_args, error);
8295         return_val_if_nok (error, NULL);
8296
8297         full_name = mono_type_get_full_name (klass);
8298         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8299         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8300         g_free (full_name);
8301
8302         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8303         return_val_if_nok (error, NULL);
8304
8305         if (exc) {
8306                 mono_error_set_exception_instance (error, (MonoException *)exc);
8307                 return NULL;
8308         }
8309
8310         if (mono_array_length (out_args) == 0)
8311                 res = NULL;
8312         else
8313                 res = mono_array_get (out_args, MonoObject *, 0);
8314
8315         return res;
8316 }
8317
8318 /**
8319  * mono_store_remote_field:
8320  * @this_obj: pointer to an object
8321  * @klass: klass of the object containing @field
8322  * @field: the field to load
8323  * @val: the value/object to store
8324  *
8325  * This method is called by the runtime on attempts to store fields of
8326  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8327  * the object containing @field. @val is the new value to store in @field.
8328  */
8329 void
8330 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8331 {
8332         MonoError error;
8333         (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8334         mono_error_cleanup (&error);
8335 }
8336
8337 /**
8338  * mono_store_remote_field_checked:
8339  * @this_obj: pointer to an object
8340  * @klass: klass of the object containing @field
8341  * @field: the field to load
8342  * @val: the value/object to store
8343  * @error: set on error
8344  *
8345  * This method is called by the runtime on attempts to store fields of
8346  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8347  * the object containing @field. @val is the new value to store in @field.
8348  *
8349  * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8350  */
8351 gboolean
8352 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8353 {
8354         
8355         MONO_REQ_GC_UNSAFE_MODE;
8356
8357         static MonoMethod *setter = NULL;
8358
8359         MonoDomain *domain = mono_domain_get ();
8360         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8361         MonoClass *field_class;
8362         MonoMethodMessage *msg;
8363         MonoArray *out_args;
8364         MonoObject *exc;
8365         MonoObject *arg;
8366         char* full_name;
8367
8368         mono_error_init (error);
8369
8370         g_assert (mono_object_is_transparent_proxy (this_obj));
8371
8372         field_class = mono_class_from_mono_type (field->type);
8373
8374         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8375                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
8376                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
8377                 return TRUE;
8378         }
8379
8380         if (!setter) {
8381                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8382                 if (!setter) {
8383                         mono_error_set_not_supported (error, "Linked away.");
8384                         return FALSE;
8385                 }
8386         }
8387
8388         if (field_class->valuetype) {
8389                 arg = mono_value_box_checked (domain, field_class, val, error);
8390                 return_val_if_nok (error, FALSE);
8391         } else 
8392                 arg = *((MonoObject **)val);
8393                 
8394
8395         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8396         return_val_if_nok (error, FALSE);
8397         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8398         return_val_if_nok (error, FALSE);
8399         mono_message_init (domain, msg, rm, NULL, error);
8400         return_val_if_nok (error, FALSE);
8401
8402         full_name = mono_type_get_full_name (klass);
8403         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8404         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8405         mono_array_setref (msg->args, 2, arg);
8406         g_free (full_name);
8407
8408         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8409         return_val_if_nok (error, FALSE);
8410
8411         if (exc) {
8412                 mono_error_set_exception_instance (error, (MonoException *)exc);
8413                 return FALSE;
8414         }
8415         return TRUE;
8416 }
8417
8418 /**
8419  * mono_store_remote_field_new:
8420  * @this_obj:
8421  * @klass:
8422  * @field:
8423  * @arg:
8424  *
8425  * Missing documentation
8426  */
8427 void
8428 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8429 {
8430         MonoError error;
8431         (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8432         mono_error_cleanup (&error);
8433 }
8434
8435 /**
8436  * mono_store_remote_field_new_icall:
8437  * @this_obj:
8438  * @klass:
8439  * @field:
8440  * @arg:
8441  *
8442  * Missing documentation
8443  */
8444 void
8445 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8446 {
8447         MonoError error;
8448         (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8449         mono_error_set_pending_exception (&error);
8450 }
8451
8452 /**
8453  * mono_store_remote_field_new_checked:
8454  * @this_obj:
8455  * @klass:
8456  * @field:
8457  * @arg:
8458  * @error:
8459  *
8460  * Missing documentation
8461  */
8462 gboolean
8463 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8464 {
8465         MONO_REQ_GC_UNSAFE_MODE;
8466
8467         static MonoMethod *setter = NULL;
8468         MonoDomain *domain = mono_domain_get ();
8469         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8470         MonoClass *field_class;
8471         MonoMethodMessage *msg;
8472         MonoArray *out_args;
8473         MonoObject *exc;
8474         char* full_name;
8475
8476         mono_error_init (error);
8477
8478         g_assert (mono_object_is_transparent_proxy (this_obj));
8479
8480         field_class = mono_class_from_mono_type (field->type);
8481
8482         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8483                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8484                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8485                 return TRUE;
8486         }
8487
8488         if (!setter) {
8489                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8490                 if (!setter) {
8491                         mono_error_set_not_supported (error, "Linked away.");
8492                         return FALSE;
8493                 }
8494         }
8495
8496         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8497         return_val_if_nok (error, FALSE);
8498         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8499         return_val_if_nok (error, FALSE);
8500         mono_message_init (domain, msg, rm, NULL, error);
8501         return_val_if_nok (error, FALSE);
8502
8503         full_name = mono_type_get_full_name (klass);
8504         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8505         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8506         mono_array_setref (msg->args, 2, arg);
8507         g_free (full_name);
8508
8509         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8510         return_val_if_nok (error, FALSE);
8511
8512         if (exc) {
8513                 mono_error_set_exception_instance (error, (MonoException *)exc);
8514                 return FALSE;
8515         }
8516         return TRUE;
8517 }
8518 #endif
8519
8520 /*
8521  * mono_create_ftnptr:
8522  *
8523  *   Given a function address, create a function descriptor for it.
8524  * This is only needed on some platforms.
8525  */
8526 gpointer
8527 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8528 {
8529         return callbacks.create_ftnptr (domain, addr);
8530 }
8531
8532 /*
8533  * mono_get_addr_from_ftnptr:
8534  *
8535  *   Given a pointer to a function descriptor, return the function address.
8536  * This is only needed on some platforms.
8537  */
8538 gpointer
8539 mono_get_addr_from_ftnptr (gpointer descr)
8540 {
8541         return callbacks.get_addr_from_ftnptr (descr);
8542 }       
8543
8544 /**
8545  * mono_string_chars:
8546  * @s: a MonoString
8547  *
8548  * Returns a pointer to the UCS16 characters stored in the MonoString
8549  */
8550 gunichar2 *
8551 mono_string_chars (MonoString *s)
8552 {
8553         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8554
8555         return s->chars;
8556 }
8557
8558 /**
8559  * mono_string_length:
8560  * @s: MonoString
8561  *
8562  * Returns the lenght in characters of the string
8563  */
8564 int
8565 mono_string_length (MonoString *s)
8566 {
8567         MONO_REQ_GC_UNSAFE_MODE;
8568
8569         return s->length;
8570 }
8571
8572 /**
8573  * mono_array_length:
8574  * @array: a MonoArray*
8575  *
8576  * Returns the total number of elements in the array. This works for
8577  * both vectors and multidimensional arrays.
8578  */
8579 uintptr_t
8580 mono_array_length (MonoArray *array)
8581 {
8582         MONO_REQ_GC_UNSAFE_MODE;
8583
8584         return array->max_length;
8585 }
8586
8587 /**
8588  * mono_array_addr_with_size:
8589  * @array: a MonoArray*
8590  * @size: size of the array elements
8591  * @idx: index into the array
8592  *
8593  * Use this function to obtain the address for the @idx item on the
8594  * @array containing elements of size @size.
8595  *
8596  * This method performs no bounds checking or type checking.
8597  *
8598  * Returns the address of the @idx element in the array.
8599  */
8600 char*
8601 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8602 {
8603         MONO_REQ_GC_UNSAFE_MODE;
8604
8605         return ((char*)(array)->vector) + size * idx;
8606 }
8607
8608
8609 MonoArray *
8610 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error) 
8611 {
8612         MonoDomain *domain = mono_domain_get ();
8613         MonoArray *res;
8614         int len, i;
8615
8616         mono_error_init (error);
8617         if (!list)
8618                 return NULL;
8619
8620         len = g_list_length (list);
8621         res = mono_array_new_checked (domain, eclass, len, error);
8622         return_val_if_nok (error, NULL);
8623
8624         for (i = 0; list; list = list->next, i++)
8625                 mono_array_set (res, gpointer, i, list->data);
8626
8627         return res;
8628 }
8629
8630 #if NEVER_DEFINED
8631 /*
8632  * The following section is purely to declare prototypes and
8633  * document the API, as these C files are processed by our
8634  * tool
8635  */
8636
8637 /**
8638  * mono_array_set:
8639  * @array: array to alter
8640  * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8641  * @index: index into the array
8642  * @value: value to set
8643  *
8644  * Value Type version: This sets the @index's element of the @array
8645  * with elements of size sizeof(type) to the provided @value.
8646  *
8647  * This macro does not attempt to perform type checking or bounds checking.
8648  *
8649  * Use this to set value types in a `MonoArray`.
8650  */
8651 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8652 {
8653 }
8654
8655 /**
8656  * mono_array_setref:
8657  * @array: array to alter
8658  * @index: index into the array
8659  * @value: value to set
8660  *
8661  * Reference Type version: This sets the @index's element of the
8662  * @array with elements of size sizeof(type) to the provided @value.
8663  *
8664  * This macro does not attempt to perform type checking or bounds checking.
8665  *
8666  * Use this to reference types in a `MonoArray`.
8667  */
8668 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8669 {
8670 }
8671
8672 /**
8673  * mono_array_get:
8674  * @array: array on which to operate on
8675  * @element_type: C element type (example: MonoString *, int, MonoObject *)
8676  * @index: index into the array
8677  *
8678  * Use this macro to retrieve the @index element of an @array and
8679  * extract the value assuming that the elements of the array match
8680  * the provided type value.
8681  *
8682  * This method can be used with both arrays holding value types and
8683  * reference types.   For reference types, the @type parameter should
8684  * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8685  *
8686  * This macro does not attempt to perform type checking or bounds checking.
8687  *
8688  * Returns: The element at the @index position in the @array.
8689  */
8690 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8691 {
8692 }
8693 #endif
8694