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