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