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