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