01cd68e6417c575dcb80d9a07b9983b099e39b1e
[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  * \c 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 \c 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#: <code>public bool Equals (object obj);</code>
2994  *
2995  * C:  <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2996  *
2997  * The 1st (<code>this</code>) parameter must not be used with static methods:
2998  *
2999  * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3000  *
3001  * C:  <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3002  *
3003  * The last argument must be a non-null \c MonoException* pointer.
3004  * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3005  * exception has been thrown in managed code. Otherwise it will point
3006  * to the \c MonoException* caught by the thunk. In this case, the result of
3007  * the thunk is undefined:
3008  *
3009  * <pre>
3010  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3011  *
3012  * MonoException *ex = NULL;
3013  *
3014  * Equals func = mono_method_get_unmanaged_thunk (method);
3015  *
3016  * MonoBoolean res = func (thisObj, objToCompare, &ex);
3017  *
3018  * if (ex) {
3019  *
3020  *    // handle exception
3021  *
3022  * }
3023  * </pre>
3024  *
3025  * The calling convention of the thunk matches the platform's default
3026  * convention. This means that under Windows, C declarations must
3027  * contain the \c __stdcall attribute:
3028  *
3029  * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3030  *
3031  * LIMITATIONS
3032  *
3033  * Value type arguments and return values are treated as they were objects:
3034  *
3035  * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3036  * C:  <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3037  *
3038  * Arguments must be properly boxed upon trunk's invocation, while return
3039  * values must be unboxed.
3040  */
3041 gpointer
3042 mono_method_get_unmanaged_thunk (MonoMethod *method)
3043 {
3044         MONO_REQ_GC_NEUTRAL_MODE;
3045         MONO_REQ_API_ENTRYPOINT;
3046
3047         MonoError error;
3048         gpointer res;
3049
3050         g_assert (!mono_threads_is_coop_enabled ());
3051
3052         MONO_ENTER_GC_UNSAFE;
3053         method = mono_marshal_get_thunk_invoke_wrapper (method);
3054         res = mono_compile_method_checked (method, &error);
3055         mono_error_cleanup (&error);
3056         MONO_EXIT_GC_UNSAFE;
3057
3058         return res;
3059 }
3060
3061 void
3062 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3063 {
3064         MONO_REQ_GC_UNSAFE_MODE;
3065
3066         int t;
3067         if (type->byref) {
3068                 /* object fields cannot be byref, so we don't need a
3069                    wbarrier here */
3070                 gpointer *p = (gpointer*)dest;
3071                 *p = value;
3072                 return;
3073         }
3074         t = type->type;
3075 handle_enum:
3076         switch (t) {
3077         case MONO_TYPE_BOOLEAN:
3078         case MONO_TYPE_I1:
3079         case MONO_TYPE_U1: {
3080                 guint8 *p = (guint8*)dest;
3081                 *p = value ? *(guint8*)value : 0;
3082                 return;
3083         }
3084         case MONO_TYPE_I2:
3085         case MONO_TYPE_U2:
3086         case MONO_TYPE_CHAR: {
3087                 guint16 *p = (guint16*)dest;
3088                 *p = value ? *(guint16*)value : 0;
3089                 return;
3090         }
3091 #if SIZEOF_VOID_P == 4
3092         case MONO_TYPE_I:
3093         case MONO_TYPE_U:
3094 #endif
3095         case MONO_TYPE_I4:
3096         case MONO_TYPE_U4: {
3097                 gint32 *p = (gint32*)dest;
3098                 *p = value ? *(gint32*)value : 0;
3099                 return;
3100         }
3101 #if SIZEOF_VOID_P == 8
3102         case MONO_TYPE_I:
3103         case MONO_TYPE_U:
3104 #endif
3105         case MONO_TYPE_I8:
3106         case MONO_TYPE_U8: {
3107                 gint64 *p = (gint64*)dest;
3108                 *p = value ? *(gint64*)value : 0;
3109                 return;
3110         }
3111         case MONO_TYPE_R4: {
3112                 float *p = (float*)dest;
3113                 *p = value ? *(float*)value : 0;
3114                 return;
3115         }
3116         case MONO_TYPE_R8: {
3117                 double *p = (double*)dest;
3118                 *p = value ? *(double*)value : 0;
3119                 return;
3120         }
3121         case MONO_TYPE_STRING:
3122         case MONO_TYPE_SZARRAY:
3123         case MONO_TYPE_CLASS:
3124         case MONO_TYPE_OBJECT:
3125         case MONO_TYPE_ARRAY:
3126                 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3127                 return;
3128         case MONO_TYPE_FNPTR:
3129         case MONO_TYPE_PTR: {
3130                 gpointer *p = (gpointer*)dest;
3131                 *p = deref_pointer? *(gpointer*)value: value;
3132                 return;
3133         }
3134         case MONO_TYPE_VALUETYPE:
3135                 /* note that 't' and 'type->type' can be different */
3136                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3137                         t = mono_class_enum_basetype (type->data.klass)->type;
3138                         goto handle_enum;
3139                 } else {
3140                         MonoClass *klass = mono_class_from_mono_type (type);
3141                         int size = mono_class_value_size (klass, NULL);
3142                         if (value == NULL)
3143                                 mono_gc_bzero_atomic (dest, size);
3144                         else
3145                                 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3146                 }
3147                 return;
3148         case MONO_TYPE_GENERICINST:
3149                 t = type->data.generic_class->container_class->byval_arg.type;
3150                 goto handle_enum;
3151         default:
3152                 g_error ("got type %x", type->type);
3153         }
3154 }
3155
3156 /**
3157  * mono_field_set_value:
3158  * \param obj Instance object
3159  * \param field \c MonoClassField describing the field to set
3160  * \param value The value to be set
3161  *
3162  * Sets the value of the field described by \p field in the object instance \p obj
3163  * to the value passed in \p value.   This method should only be used for instance
3164  * fields.   For static fields, use mono_field_static_set_value().
3165  *
3166  * The value must be in the native format of the field type. 
3167  */
3168 void
3169 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3170 {
3171         MONO_REQ_GC_UNSAFE_MODE;
3172
3173         void *dest;
3174
3175         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3176
3177         dest = (char*)obj + field->offset;
3178         mono_copy_value (field->type, dest, value, FALSE);
3179 }
3180
3181 /**
3182  * mono_field_static_set_value:
3183  * \param field \c MonoClassField describing the field to set
3184  * \param value The value to be set
3185  * Sets the value of the static field described by \p field
3186  * to the value passed in \p value.
3187  * The value must be in the native format of the field type. 
3188  */
3189 void
3190 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3191 {
3192         MONO_REQ_GC_UNSAFE_MODE;
3193
3194         void *dest;
3195
3196         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3197         /* you cant set a constant! */
3198         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3199
3200         if (field->offset == -1) {
3201                 /* Special static */
3202                 gpointer addr;
3203
3204                 mono_domain_lock (vt->domain);
3205                 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3206                 mono_domain_unlock (vt->domain);
3207                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3208         } else {
3209                 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3210         }
3211         mono_copy_value (field->type, dest, value, FALSE);
3212 }
3213
3214 /**
3215  * mono_vtable_get_static_field_data:
3216  *
3217  * Internal use function: return a pointer to the memory holding the static fields
3218  * for a class or NULL if there are no static fields.
3219  * This is exported only for use by the debugger.
3220  */
3221 void *
3222 mono_vtable_get_static_field_data (MonoVTable *vt)
3223 {
3224         MONO_REQ_GC_NEUTRAL_MODE
3225
3226         if (!vt->has_static_fields)
3227                 return NULL;
3228         return vt->vtable [vt->klass->vtable_size];
3229 }
3230
3231 static guint8*
3232 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3233 {
3234         MONO_REQ_GC_UNSAFE_MODE;
3235
3236         guint8 *src;
3237
3238         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3239                 if (field->offset == -1) {
3240                         /* Special static */
3241                         gpointer addr;
3242
3243                         mono_domain_lock (vt->domain);
3244                         addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3245                         mono_domain_unlock (vt->domain);
3246                         src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3247                 } else {
3248                         src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3249                 }
3250         } else {
3251                 src = (guint8*)obj + field->offset;
3252         }
3253
3254         return src;
3255 }
3256
3257 /**
3258  * mono_field_get_value:
3259  * \param obj Object instance
3260  * \param field \c MonoClassField describing the field to fetch information from
3261  * \param value pointer to the location where the value will be stored
3262  * Use this routine to get the value of the field \p field in the object
3263  * passed.
3264  *
3265  * The pointer provided by value must be of the field type, for reference
3266  * types this is a \c MonoObject*, for value types its the actual pointer to
3267  * the value type.
3268  *
3269  * For example:
3270  *     int i;
3271  *     mono_field_get_value (obj, int_field, &i);
3272  */
3273 void
3274 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3275 {
3276         MONO_REQ_GC_UNSAFE_MODE;
3277
3278         void *src;
3279
3280         g_assert (obj);
3281
3282         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3283
3284         src = (char*)obj + field->offset;
3285         mono_copy_value (field->type, value, src, TRUE);
3286 }
3287
3288 /**
3289  * mono_field_get_value_object:
3290  * \param domain domain where the object will be created (if boxing)
3291  * \param field \c MonoClassField describing the field to fetch information from
3292  * \param obj The object instance for the field.
3293  * \returns a new \c MonoObject with the value from the given field.  If the
3294  * field represents a value type, the value is boxed.
3295  */
3296 MonoObject *
3297 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3298 {       
3299         MonoError error;
3300         MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3301         mono_error_assert_ok (&error);
3302         return result;
3303 }
3304
3305 /**
3306  * mono_field_get_value_object_checked:
3307  * \param domain domain where the object will be created (if boxing)
3308  * \param field \c MonoClassField describing the field to fetch information from
3309  * \param obj The object instance for the field.
3310  * \param error Set on error.
3311  * \returns a new \c MonoObject with the value from the given field.  If the
3312  * field represents a value type, the value is boxed.  On error returns NULL and sets \p error.
3313  */
3314 MonoObject *
3315 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3316 {
3317         MONO_REQ_GC_UNSAFE_MODE;
3318
3319         error_init (error);
3320
3321         MonoObject *o;
3322         MonoClass *klass;
3323         MonoVTable *vtable = NULL;
3324         gchar *v;
3325         gboolean is_static = FALSE;
3326         gboolean is_ref = FALSE;
3327         gboolean is_literal = FALSE;
3328         gboolean is_ptr = FALSE;
3329         MonoType *type = mono_field_get_type_checked (field, error);
3330
3331         return_val_if_nok (error, NULL);
3332
3333         switch (type->type) {
3334         case MONO_TYPE_STRING:
3335         case MONO_TYPE_OBJECT:
3336         case MONO_TYPE_CLASS:
3337         case MONO_TYPE_ARRAY:
3338         case MONO_TYPE_SZARRAY:
3339                 is_ref = TRUE;
3340                 break;
3341         case MONO_TYPE_U1:
3342         case MONO_TYPE_I1:
3343         case MONO_TYPE_BOOLEAN:
3344         case MONO_TYPE_U2:
3345         case MONO_TYPE_I2:
3346         case MONO_TYPE_CHAR:
3347         case MONO_TYPE_U:
3348         case MONO_TYPE_I:
3349         case MONO_TYPE_U4:
3350         case MONO_TYPE_I4:
3351         case MONO_TYPE_R4:
3352         case MONO_TYPE_U8:
3353         case MONO_TYPE_I8:
3354         case MONO_TYPE_R8:
3355         case MONO_TYPE_VALUETYPE:
3356                 is_ref = type->byref;
3357                 break;
3358         case MONO_TYPE_GENERICINST:
3359                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3360                 break;
3361         case MONO_TYPE_PTR:
3362                 is_ptr = TRUE;
3363                 break;
3364         default:
3365                 g_error ("type 0x%x not handled in "
3366                          "mono_field_get_value_object", type->type);
3367                 return NULL;
3368         }
3369
3370         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3371                 is_literal = TRUE;
3372
3373         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3374                 is_static = TRUE;
3375
3376                 if (!is_literal) {
3377                         vtable = mono_class_vtable_full (domain, field->parent, error);
3378                         return_val_if_nok (error, NULL);
3379
3380                         if (!vtable->initialized) {
3381                                 mono_runtime_class_init_full (vtable, error);
3382                                 return_val_if_nok (error, NULL);
3383                         }
3384                 }
3385         } else {
3386                 g_assert (obj);
3387         }
3388         
3389         if (is_ref) {
3390                 if (is_literal) {
3391                         get_default_field_value (domain, field, &o, error);
3392                         return_val_if_nok (error, NULL);
3393                 } else if (is_static) {
3394                         mono_field_static_get_value_checked (vtable, field, &o, error);
3395                         return_val_if_nok (error, NULL);
3396                 } else {
3397                         mono_field_get_value (obj, field, &o);
3398                 }
3399                 return o;
3400         }
3401
3402         if (is_ptr) {
3403                 static MonoMethod *m;
3404                 gpointer args [2];
3405                 gpointer *ptr;
3406                 gpointer v;
3407
3408                 if (!m) {
3409                         MonoClass *ptr_klass = mono_class_get_pointer_class ();
3410                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3411                         g_assert (m);
3412                 }
3413
3414                 v = &ptr;
3415                 if (is_literal) {
3416                         get_default_field_value (domain, field, v, error);
3417                         return_val_if_nok (error, NULL);
3418                 } else if (is_static) {
3419                         mono_field_static_get_value_checked (vtable, field, v, error);
3420                         return_val_if_nok (error, NULL);
3421                 } else {
3422                         mono_field_get_value (obj, field, v);
3423                 }
3424
3425                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3426                 args [0] = ptr ? *ptr : NULL;
3427                 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3428                 return_val_if_nok (error, NULL);
3429
3430                 o = mono_runtime_invoke_checked (m, NULL, args, error);
3431                 return_val_if_nok (error, NULL);
3432
3433                 return o;
3434         }
3435
3436         /* boxed value type */
3437         klass = mono_class_from_mono_type (type);
3438
3439         if (mono_class_is_nullable (klass))
3440                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3441
3442         o = mono_object_new_checked (domain, klass, error);
3443         return_val_if_nok (error, NULL);
3444         v = ((gchar *) o) + sizeof (MonoObject);
3445
3446         if (is_literal) {
3447                 get_default_field_value (domain, field, v, error);
3448                 return_val_if_nok (error, NULL);
3449         } else if (is_static) {
3450                 mono_field_static_get_value_checked (vtable, field, v, error);
3451                 return_val_if_nok (error, NULL);
3452         } else {
3453                 mono_field_get_value (obj, field, v);
3454         }
3455
3456         return o;
3457 }
3458
3459 int
3460 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3461 {
3462         MONO_REQ_GC_UNSAFE_MODE;
3463
3464         error_init (error);
3465         int retval = 0;
3466         const char *p = blob;
3467         mono_metadata_decode_blob_size (p, &p);
3468
3469         switch (type) {
3470         case MONO_TYPE_BOOLEAN:
3471         case MONO_TYPE_U1:
3472         case MONO_TYPE_I1:
3473                 *(guint8 *) value = *p;
3474                 break;
3475         case MONO_TYPE_CHAR:
3476         case MONO_TYPE_U2:
3477         case MONO_TYPE_I2:
3478                 *(guint16*) value = read16 (p);
3479                 break;
3480         case MONO_TYPE_U4:
3481         case MONO_TYPE_I4:
3482                 *(guint32*) value = read32 (p);
3483                 break;
3484         case MONO_TYPE_U8:
3485         case MONO_TYPE_I8:
3486                 *(guint64*) value = read64 (p);
3487                 break;
3488         case MONO_TYPE_R4:
3489                 readr4 (p, (float*) value);
3490                 break;
3491         case MONO_TYPE_R8:
3492                 readr8 (p, (double*) value);
3493                 break;
3494         case MONO_TYPE_STRING:
3495                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3496                 break;
3497         case MONO_TYPE_CLASS:
3498                 *(gpointer*) value = NULL;
3499                 break;
3500         default:
3501                 retval = -1;
3502                 g_warning ("type 0x%02x should not be in constant table", type);
3503         }
3504         return retval;
3505 }
3506
3507 static void
3508 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3509 {
3510         MONO_REQ_GC_NEUTRAL_MODE;
3511
3512         MonoTypeEnum def_type;
3513         const char* data;
3514
3515         error_init (error);
3516         
3517         data = mono_class_get_field_default_value (field, &def_type);
3518         mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3519 }
3520
3521 void
3522 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3523 {
3524         MONO_REQ_GC_UNSAFE_MODE;
3525
3526         void *src;
3527
3528         error_init (error);
3529
3530         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3531         
3532         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3533                 get_default_field_value (vt->domain, field, value, error);
3534                 return;
3535         }
3536
3537         if (field->offset == -1) {
3538                 /* Special static */
3539                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3540                 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3541         } else {
3542                 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3543         }
3544         mono_copy_value (field->type, value, src, TRUE);
3545 }
3546
3547 /**
3548  * mono_field_static_get_value:
3549  * \param vt vtable to the object
3550  * \param field \c MonoClassField describing the field to fetch information from
3551  * \param value where the value is returned
3552  * Use this routine to get the value of the static field \p field value.
3553  *
3554  * The pointer provided by value must be of the field type, for reference
3555  * types this is a \c MonoObject*, for value types its the actual pointer to
3556  * the value type.
3557  *
3558  * For example:
3559  *     int i;
3560  *     mono_field_static_get_value (vt, int_field, &i);
3561  */
3562 void
3563 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3564 {
3565         MONO_REQ_GC_NEUTRAL_MODE;
3566
3567         MonoError error;
3568         mono_field_static_get_value_checked (vt, field, value, &error);
3569         mono_error_cleanup (&error);
3570 }
3571
3572 /**
3573  * mono_field_static_get_value_checked:
3574  * \param vt vtable to the object
3575  * \param field \c MonoClassField describing the field to fetch information from
3576  * \param value where the value is returned
3577  * \param error set on error
3578  * Use this routine to get the value of the static field \p field value.
3579  *
3580  * The pointer provided by value must be of the field type, for reference
3581  * types this is a \c MonoObject*, for value types its the actual pointer to
3582  * the value type.
3583  *
3584  * For example:
3585  *     int i;
3586  *     mono_field_static_get_value_checked (vt, int_field, &i, error);
3587  *     if (!is_ok (error)) { ... }
3588  *
3589  * On failure sets \p error.
3590  */
3591 void
3592 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3593 {
3594         MONO_REQ_GC_NEUTRAL_MODE;
3595
3596         mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3597 }
3598
3599 /**
3600  * mono_property_set_value:
3601  * \param prop MonoProperty to set
3602  * \param obj instance object on which to act
3603  * \param params parameters to pass to the propery
3604  * \param exc optional exception
3605  * Invokes the property's set method with the given arguments on the
3606  * object instance obj (or NULL for static properties). 
3607  * 
3608  * You can pass NULL as the exc argument if you don't want to
3609  * catch exceptions, otherwise, \c *exc will be set to the exception
3610  * thrown, if any.  if an exception is thrown, you can't use the
3611  * \c MonoObject* result from the function.
3612  */
3613 void
3614 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3615 {
3616         MONO_REQ_GC_UNSAFE_MODE;
3617
3618         MonoError error;
3619         do_runtime_invoke (prop->set, obj, params, exc, &error);
3620         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3621                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3622         } else {
3623                 mono_error_cleanup (&error);
3624         }
3625 }
3626
3627 /**
3628  * mono_property_set_value_checked:
3629  * \param prop \c MonoProperty to set
3630  * \param obj instance object on which to act
3631  * \param params parameters to pass to the propery
3632  * \param error set on error
3633  * Invokes the property's set method with the given arguments on the
3634  * object instance \p obj (or NULL for static properties). 
3635  * \returns TRUE on success.  On failure returns FALSE and sets \p error.
3636  * If an exception is thrown, it will be caught and returned via \p error.
3637  */
3638 gboolean
3639 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3640 {
3641         MONO_REQ_GC_UNSAFE_MODE;
3642
3643         MonoObject *exc;
3644
3645         error_init (error);
3646         do_runtime_invoke (prop->set, obj, params, &exc, error);
3647         if (exc != NULL && is_ok (error))
3648                 mono_error_set_exception_instance (error, (MonoException*)exc);
3649         return is_ok (error);
3650 }
3651
3652 /**
3653  * mono_property_get_value:
3654  * \param prop \c MonoProperty to fetch
3655  * \param obj instance object on which to act
3656  * \param params parameters to pass to the propery
3657  * \param exc optional exception
3658  * Invokes the property's \c get method with the given arguments on the
3659  * object instance \p obj (or NULL for static properties). 
3660  * 
3661  * You can pass NULL as the \p exc argument if you don't want to
3662  * catch exceptions, otherwise, \c *exc will be set to the exception
3663  * thrown, if any.  if an exception is thrown, you can't use the
3664  * \c MonoObject* result from the function.
3665  *
3666  * \returns the value from invoking the \c get method on the property.
3667  */
3668 MonoObject*
3669 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3670 {
3671         MONO_REQ_GC_UNSAFE_MODE;
3672
3673         MonoError error;
3674         MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3675         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3676                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3677         } else {
3678                 mono_error_cleanup (&error); /* FIXME don't raise here */
3679         }
3680
3681         return val;
3682 }
3683
3684 /**
3685  * mono_property_get_value_checked:
3686  * \param prop \c MonoProperty to fetch
3687  * \param obj instance object on which to act
3688  * \param params parameters to pass to the propery
3689  * \param error set on error
3690  * Invokes the property's \c get method with the given arguments on the
3691  * object instance obj (or NULL for static properties). 
3692  * 
3693  * If an exception is thrown, you can't use the
3694  * \c MonoObject* result from the function.  The exception will be propagated via \p error.
3695  *
3696  * \returns the value from invoking the get method on the property. On
3697  * failure returns NULL and sets \p error.
3698  */
3699 MonoObject*
3700 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3701 {
3702         MONO_REQ_GC_UNSAFE_MODE;
3703
3704         MonoObject *exc;
3705         MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3706         if (exc != NULL && !is_ok (error))
3707                 mono_error_set_exception_instance (error, (MonoException*) exc);
3708         if (!is_ok (error))
3709                 val = NULL;
3710         return val;
3711 }
3712
3713
3714 /*
3715  * mono_nullable_init:
3716  * @buf: The nullable structure to initialize.
3717  * @value: the value to initialize from
3718  * @klass: the type for the object
3719  *
3720  * Initialize the nullable structure pointed to by @buf from @value which
3721  * should be a boxed value type.   The size of @buf should be able to hold
3722  * as much data as the @klass->instance_size (which is the number of bytes
3723  * that will be copies).
3724  *
3725  * Since Nullables have variable structure, we can not define a C
3726  * structure for them.
3727  */
3728 void
3729 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3730 {
3731         MONO_REQ_GC_UNSAFE_MODE;
3732
3733         MonoClass *param_class = klass->cast_class;
3734
3735         mono_class_setup_fields (klass);
3736         g_assert (klass->fields_inited);
3737                                 
3738         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3739         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3740
3741         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3742         if (value) {
3743                 if (param_class->has_references)
3744                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3745                 else
3746                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3747         } else {
3748                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3749         }
3750 }
3751
3752 /**
3753  * mono_nullable_box:
3754  * \param buf The buffer representing the data to be boxed
3755  * \param klass the type to box it as.
3756  * \param error set on error
3757  *
3758  * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3759  * \p buf.  On failure returns NULL and sets \p error.
3760  */
3761 MonoObject*
3762 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3763 {
3764         MONO_REQ_GC_UNSAFE_MODE;
3765
3766         error_init (error);
3767         MonoClass *param_class = klass->cast_class;
3768
3769         mono_class_setup_fields (klass);
3770         g_assert (klass->fields_inited);
3771
3772         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3773         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3774
3775         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3776                 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3777                 return_val_if_nok (error, NULL);
3778                 if (param_class->has_references)
3779                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3780                 else
3781                         mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3782                 return o;
3783         }
3784         else
3785                 return NULL;
3786 }
3787
3788 /**
3789  * mono_get_delegate_invoke:
3790  * \param klass The delegate class
3791  * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3792  */
3793 MonoMethod *
3794 mono_get_delegate_invoke (MonoClass *klass)
3795 {
3796         MONO_REQ_GC_NEUTRAL_MODE;
3797
3798         MonoMethod *im;
3799
3800         /* This is called at runtime, so avoid the slower search in metadata */
3801         mono_class_setup_methods (klass);
3802         if (mono_class_has_failure (klass))
3803                 return NULL;
3804         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3805         return im;
3806 }
3807
3808 /**
3809  * mono_get_delegate_begin_invoke:
3810  * \param klass The delegate class
3811  * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3812  */
3813 MonoMethod *
3814 mono_get_delegate_begin_invoke (MonoClass *klass)
3815 {
3816         MONO_REQ_GC_NEUTRAL_MODE;
3817
3818         MonoMethod *im;
3819
3820         /* This is called at runtime, so avoid the slower search in metadata */
3821         mono_class_setup_methods (klass);
3822         if (mono_class_has_failure (klass))
3823                 return NULL;
3824         im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3825         return im;
3826 }
3827
3828 /**
3829  * mono_get_delegate_end_invoke:
3830  * \param klass The delegate class
3831  * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3832  */
3833 MonoMethod *
3834 mono_get_delegate_end_invoke (MonoClass *klass)
3835 {
3836         MONO_REQ_GC_NEUTRAL_MODE;
3837
3838         MonoMethod *im;
3839
3840         /* This is called at runtime, so avoid the slower search in metadata */
3841         mono_class_setup_methods (klass);
3842         if (mono_class_has_failure (klass))
3843                 return NULL;
3844         im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3845         return im;
3846 }
3847
3848 /**
3849  * mono_runtime_delegate_invoke:
3850  * \param delegate pointer to a delegate object.
3851  * \param params parameters for the delegate.
3852  * \param exc Pointer to the exception result.
3853  *
3854  * Invokes the delegate method \p delegate with the parameters provided.
3855  *
3856  * You can pass NULL as the \p exc argument if you don't want to
3857  * catch exceptions, otherwise, \c *exc will be set to the exception
3858  * thrown, if any.  if an exception is thrown, you can't use the
3859  * \c MonoObject* result from the function.
3860  */
3861 MonoObject*
3862 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3863 {
3864         MONO_REQ_GC_UNSAFE_MODE;
3865
3866         MonoError error;
3867         if (exc) {
3868                 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3869                 if (*exc) {
3870                         mono_error_cleanup (&error);
3871                         return NULL;
3872                 } else {
3873                         if (!is_ok (&error))
3874                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3875                         return result;
3876                 }
3877         } else {
3878                 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3879                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3880                 return result;
3881         }
3882 }
3883
3884 /**
3885  * mono_runtime_delegate_try_invoke:
3886  * \param delegate pointer to a delegate object.
3887  * \param params parameters for the delegate.
3888  * \param exc Pointer to the exception result.
3889  * \param error set on error
3890  * Invokes the delegate method \p delegate with the parameters provided.
3891  *
3892  * You can pass NULL as the \p exc argument if you don't want to
3893  * catch exceptions, otherwise, \c *exc will be set to the exception
3894  * thrown, if any.  On failure to execute, \p error will be set.
3895  * if an exception is thrown, you can't use the
3896  * \c MonoObject* result from the function.
3897  */
3898 MonoObject*
3899 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3900 {
3901         MONO_REQ_GC_UNSAFE_MODE;
3902
3903         error_init (error);
3904         MonoMethod *im;
3905         MonoClass *klass = delegate->vtable->klass;
3906         MonoObject *o;
3907
3908         im = mono_get_delegate_invoke (klass);
3909         if (!im)
3910                 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3911
3912         if (exc) {
3913                 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3914         } else {
3915                 o = mono_runtime_invoke_checked (im, delegate, params, error);
3916         }
3917
3918         return o;
3919 }
3920
3921 /**
3922  * mono_runtime_delegate_invoke_checked:
3923  * \param delegate pointer to a delegate object.
3924  * \param params parameters for the delegate.
3925  * \param error set on error
3926  * Invokes the delegate method \p delegate with the parameters provided.
3927  * On failure \p error will be set and you can't use the \c MonoObject*
3928  * result from the function.
3929  */
3930 MonoObject*
3931 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3932 {
3933         error_init (error);
3934         return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3935 }
3936
3937 static char **main_args = NULL;
3938 static int num_main_args = 0;
3939
3940 /**
3941  * mono_runtime_get_main_args:
3942  *
3943  * Returns: a MonoArray with the arguments passed to the main program
3944  */
3945 MonoArray*
3946 mono_runtime_get_main_args (void)
3947 {
3948         MONO_REQ_GC_UNSAFE_MODE;
3949         MonoError error;
3950         MonoArray *result = mono_runtime_get_main_args_checked (&error);
3951         mono_error_assert_ok (&error);
3952         return result;
3953 }
3954
3955 /**
3956  * mono_runtime_get_main_args_checked:
3957  * \param error set on error
3958  * \returns a \c MonoArray with the arguments passed to the main
3959  * program. On failure returns NULL and sets \p error.
3960  */
3961 MonoArray*
3962 mono_runtime_get_main_args_checked (MonoError *error)
3963 {
3964         MonoArray *res;
3965         int i;
3966         MonoDomain *domain = mono_domain_get ();
3967
3968         error_init (error);
3969
3970         res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3971         return_val_if_nok (error, NULL);
3972
3973         for (i = 0; i < num_main_args; ++i)
3974                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3975
3976         return res;
3977 }
3978
3979 static void
3980 free_main_args (void)
3981 {
3982         MONO_REQ_GC_NEUTRAL_MODE;
3983
3984         int i;
3985
3986         for (i = 0; i < num_main_args; ++i)
3987                 g_free (main_args [i]);
3988         g_free (main_args);
3989         num_main_args = 0;
3990         main_args = NULL;
3991 }
3992
3993 /**
3994  * mono_runtime_set_main_args:
3995  * \param argc number of arguments from the command line
3996  * \param argv array of strings from the command line
3997  * Set the command line arguments from an embedding application that doesn't otherwise call
3998  * \c mono_runtime_run_main.
3999  */
4000 int
4001 mono_runtime_set_main_args (int argc, char* argv[])
4002 {
4003         MONO_REQ_GC_NEUTRAL_MODE;
4004
4005         int i;
4006
4007         free_main_args ();
4008         main_args = g_new0 (char*, argc);
4009         num_main_args = argc;
4010
4011         for (i = 0; i < argc; ++i) {
4012                 gchar *utf8_arg;
4013
4014                 utf8_arg = mono_utf8_from_external (argv[i]);
4015                 if (utf8_arg == NULL) {
4016                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4017                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4018                         exit (-1);
4019                 }
4020
4021                 main_args [i] = utf8_arg;
4022         }
4023
4024         return 0;
4025 }
4026
4027 /*
4028  * Prepare an array of arguments in order to execute a standard Main()
4029  * method (argc/argv contains the executable name). This method also
4030  * sets the command line argument value needed by System.Environment.
4031  * 
4032  */
4033 static MonoArray*
4034 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4035 {
4036         MONO_REQ_GC_UNSAFE_MODE;
4037
4038         MonoError error;
4039         int i;
4040         MonoArray *args = NULL;
4041         MonoDomain *domain = mono_domain_get ();
4042         gchar *utf8_fullpath;
4043         MonoMethodSignature *sig;
4044
4045         g_assert (method != NULL);
4046         
4047         mono_thread_set_main (mono_thread_current ());
4048
4049         main_args = g_new0 (char*, argc);
4050         num_main_args = argc;
4051
4052         if (!g_path_is_absolute (argv [0])) {
4053                 gchar *basename = g_path_get_basename (argv [0]);
4054                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4055                                                     basename,
4056                                                     NULL);
4057
4058                 utf8_fullpath = mono_utf8_from_external (fullpath);
4059                 if(utf8_fullpath == NULL) {
4060                         /* Printing the arg text will cause glib to
4061                          * whinge about "Invalid UTF-8", but at least
4062                          * its relevant, and shows the problem text
4063                          * string.
4064                          */
4065                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4066                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4067                         exit (-1);
4068                 }
4069
4070                 g_free (fullpath);
4071                 g_free (basename);
4072         } else {
4073                 utf8_fullpath = mono_utf8_from_external (argv[0]);
4074                 if(utf8_fullpath == NULL) {
4075                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4076                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4077                         exit (-1);
4078                 }
4079         }
4080
4081         main_args [0] = utf8_fullpath;
4082
4083         for (i = 1; i < argc; ++i) {
4084                 gchar *utf8_arg;
4085
4086                 utf8_arg=mono_utf8_from_external (argv[i]);
4087                 if(utf8_arg==NULL) {
4088                         /* Ditto the comment about Invalid UTF-8 here */
4089                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4090                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4091                         exit (-1);
4092                 }
4093
4094                 main_args [i] = utf8_arg;
4095         }
4096         argc--;
4097         argv++;
4098
4099         sig = mono_method_signature (method);
4100         if (!sig) {
4101                 g_print ("Unable to load Main method.\n");
4102                 exit (-1);
4103         }
4104
4105         if (sig->param_count) {
4106                 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4107                 mono_error_assert_ok (&error);
4108                 for (i = 0; i < argc; ++i) {
4109                         /* The encodings should all work, given that
4110                          * we've checked all these args for the
4111                          * main_args array.
4112                          */
4113                         gchar *str = mono_utf8_from_external (argv [i]);
4114                         MonoString *arg = mono_string_new (domain, str);
4115                         mono_array_setref (args, i, arg);
4116                         g_free (str);
4117                 }
4118         } else {
4119                 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4120                 mono_error_assert_ok (&error);
4121         }
4122         
4123         mono_assembly_set_main (method->klass->image->assembly);
4124
4125         return args;
4126 }
4127
4128 /**
4129  * mono_runtime_run_main:
4130  * \param method the method to start the application with (usually \c Main)
4131  * \param argc number of arguments from the command line
4132  * \param argv array of strings from the command line
4133  * \param exc excetption results
4134  * Execute a standard \c Main method (\p argc / \p argv contains the
4135  * executable name). This method also sets the command line argument value
4136  * needed by \c System.Environment.
4137  */
4138 int
4139 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4140                        MonoObject **exc)
4141 {
4142         MONO_REQ_GC_UNSAFE_MODE;
4143
4144         MonoError error;
4145         MonoArray *args = prepare_run_main (method, argc, argv);
4146         int res;
4147         if (exc) {
4148                 res = mono_runtime_try_exec_main (method, args, exc);
4149         } else {
4150                 res = mono_runtime_exec_main_checked (method, args, &error);
4151                 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4152         }
4153         return res;
4154 }
4155
4156 /**
4157  * mono_runtime_run_main_checked:
4158  * \param method the method to start the application with (usually \c Main)
4159  * \param argc number of arguments from the command line
4160  * \param argv array of strings from the command line
4161  * \param error set on error
4162  *
4163  * Execute a standard \c Main method (\p argc / \p argv contains the
4164  * executable name). This method also sets the command line argument value
4165  * needed by \c System.Environment.  On failure sets \p error.
4166  */
4167 int
4168 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4169                                MonoError *error)
4170 {
4171         error_init (error);
4172         MonoArray *args = prepare_run_main (method, argc, argv);
4173         return mono_runtime_exec_main_checked (method, args, error);
4174 }
4175
4176 /**
4177  * mono_runtime_try_run_main:
4178  * \param method the method to start the application with (usually \c Main)
4179  * \param argc number of arguments from the command line
4180  * \param argv array of strings from the command line
4181  * \param exc set if \c Main throws an exception
4182  * \param error set if \c Main can't be executed
4183  * Execute a standard \c Main method (\p argc / \p argv contains the executable
4184  * name). This method also sets the command line argument value needed
4185  * by \c System.Environment.  On failure sets \p error if Main can't be
4186  * executed or \p exc if it threw an exception.
4187  */
4188 int
4189 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4190                            MonoObject **exc)
4191 {
4192         g_assert (exc);
4193         MonoArray *args = prepare_run_main (method, argc, argv);
4194         return mono_runtime_try_exec_main (method, args, exc);
4195 }
4196
4197
4198 static MonoObject*
4199 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4200 {
4201         static MonoMethod *serialize_method;
4202
4203         MonoError error;
4204         void *params [1];
4205         MonoObject *array;
4206
4207         if (!serialize_method) {
4208                 MonoClass *klass = mono_class_get_remoting_services_class ();
4209                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4210         }
4211
4212         if (!serialize_method) {
4213                 *failure = TRUE;
4214                 return NULL;
4215         }
4216
4217         g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4218
4219         params [0] = obj;
4220         *exc = NULL;
4221
4222         array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4223         if (*exc == NULL && !mono_error_ok (&error))
4224                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4225         else
4226                 mono_error_cleanup (&error);
4227
4228         if (*exc)
4229                 *failure = TRUE;
4230
4231         return array;
4232 }
4233
4234 static MonoObject*
4235 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4236 {
4237         MONO_REQ_GC_UNSAFE_MODE;
4238
4239         static MonoMethod *deserialize_method;
4240
4241         MonoError error;
4242         void *params [1];
4243         MonoObject *result;
4244
4245         if (!deserialize_method) {
4246                 MonoClass *klass = mono_class_get_remoting_services_class ();
4247                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4248         }
4249         if (!deserialize_method) {
4250                 *failure = TRUE;
4251                 return NULL;
4252         }
4253
4254         params [0] = obj;
4255         *exc = NULL;
4256
4257         result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4258         if (*exc == NULL && !mono_error_ok (&error))
4259                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4260         else
4261                 mono_error_cleanup (&error);
4262
4263         if (*exc)
4264                 *failure = TRUE;
4265
4266         return result;
4267 }
4268
4269 #ifndef DISABLE_REMOTING
4270 static MonoObject*
4271 make_transparent_proxy (MonoObject *obj, MonoError *error)
4272 {
4273         MONO_REQ_GC_UNSAFE_MODE;
4274
4275         static MonoMethod *get_proxy_method;
4276
4277         MonoDomain *domain = mono_domain_get ();
4278         MonoRealProxy *real_proxy;
4279         MonoReflectionType *reflection_type;
4280         MonoTransparentProxy *transparent_proxy;
4281
4282         error_init (error);
4283
4284         if (!get_proxy_method)
4285                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4286
4287         g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4288
4289         real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4290         return_val_if_nok (error, NULL);
4291         reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4292         return_val_if_nok (error, NULL);
4293
4294         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4295         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4296
4297         MonoObject *exc = NULL;
4298
4299         transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4300         if (exc != NULL && is_ok (error))
4301                 mono_error_set_exception_instance (error, (MonoException*)exc);
4302
4303         return (MonoObject*) transparent_proxy;
4304 }
4305 #endif /* DISABLE_REMOTING */
4306
4307 /**
4308  * mono_object_xdomain_representation
4309  * \param obj an object
4310  * \param target_domain a domain
4311  * \param error set on error.
4312  * Creates a representation of obj in the domain \p target_domain.  This
4313  * is either a copy of \p obj arrived through via serialization and
4314  * deserialization or a proxy, depending on whether the object is
4315  * serializable or marshal by ref.  \p obj must not be in \p target_domain.
4316  * If the object cannot be represented in \p target_domain, NULL is
4317  * returned and \p error is set appropriately.
4318  */
4319 MonoObject*
4320 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4321 {
4322         MONO_REQ_GC_UNSAFE_MODE;
4323
4324         error_init (error);
4325         MonoObject *deserialized = NULL;
4326
4327 #ifndef DISABLE_REMOTING
4328         if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4329                 deserialized = make_transparent_proxy (obj, error);
4330         } 
4331         else
4332 #endif
4333         {
4334                 gboolean failure = FALSE;
4335                 MonoDomain *domain = mono_domain_get ();
4336                 MonoObject *serialized;
4337                 MonoObject *exc = NULL;
4338
4339                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4340                 serialized = serialize_object (obj, &failure, &exc);
4341                 mono_domain_set_internal_with_options (target_domain, FALSE);
4342                 if (!failure)
4343                         deserialized = deserialize_object (serialized, &failure, &exc);
4344                 if (domain != target_domain)
4345                         mono_domain_set_internal_with_options (domain, FALSE);
4346                 if (failure)
4347                         mono_error_set_exception_instance (error, (MonoException*)exc);
4348         }
4349
4350         return deserialized;
4351 }
4352
4353 /* Used in call_unhandled_exception_delegate */
4354 static MonoObject *
4355 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4356 {
4357         MONO_REQ_GC_UNSAFE_MODE;
4358
4359         error_init (error);
4360         MonoClass *klass;
4361         gpointer args [2];
4362         MonoMethod *method = NULL;
4363         MonoBoolean is_terminating = TRUE;
4364         MonoObject *obj;
4365
4366         klass = mono_class_get_unhandled_exception_event_args_class ();
4367         mono_class_init (klass);
4368
4369         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4370         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4371         g_assert (method);
4372
4373         args [0] = exc;
4374         args [1] = &is_terminating;
4375
4376         obj = mono_object_new_checked (mono_domain_get (), klass, error);
4377         return_val_if_nok (error, NULL);
4378
4379         mono_runtime_invoke_checked (method, obj, args, error);
4380         return_val_if_nok (error, NULL);
4381
4382         return obj;
4383 }
4384
4385 /* Used in mono_unhandled_exception */
4386 static void
4387 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4388         MONO_REQ_GC_UNSAFE_MODE;
4389
4390         MonoError error;
4391         MonoObject *e = NULL;
4392         gpointer pa [2];
4393         MonoDomain *current_domain = mono_domain_get ();
4394
4395         if (domain != current_domain)
4396                 mono_domain_set_internal_with_options (domain, FALSE);
4397
4398         g_assert (domain == mono_object_domain (domain->domain));
4399
4400         if (mono_object_domain (exc) != domain) {
4401
4402                 exc = mono_object_xdomain_representation (exc, domain, &error);
4403                 if (!exc) {
4404                         if (!is_ok (&error)) {
4405                                 MonoError inner_error;
4406                                 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4407                                 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4408                                 mono_error_assert_ok (&inner_error);
4409                         } else {
4410                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4411                                                 "System.Runtime.Serialization", "SerializationException",
4412                                                 "Could not serialize unhandled exception.");
4413                         }
4414                 }
4415         }
4416         g_assert (mono_object_domain (exc) == domain);
4417
4418         pa [0] = domain->domain;
4419         pa [1] = create_unhandled_exception_eventargs (exc, &error);
4420         mono_error_assert_ok (&error);
4421         mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4422         if (!is_ok (&error)) {
4423                 if (e == NULL)
4424                         e = (MonoObject*)mono_error_convert_to_exception (&error);
4425                 else
4426                         mono_error_cleanup (&error);
4427         }
4428
4429         if (domain != current_domain)
4430                 mono_domain_set_internal_with_options (current_domain, FALSE);
4431
4432         if (e) {
4433                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4434                 if (!mono_error_ok (&error)) {
4435                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4436                         mono_error_cleanup (&error);
4437                 } else {
4438                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
4439                         g_free (msg);
4440                 }
4441         }
4442 }
4443
4444 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4445
4446 /**
4447  * mono_runtime_unhandled_exception_policy_set:
4448  * \param policy the new policy
4449  * This is a VM internal routine.
4450  * Sets the runtime policy for handling unhandled exceptions.
4451  */
4452 void
4453 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4454         runtime_unhandled_exception_policy = policy;
4455 }
4456
4457 /**
4458  * mono_runtime_unhandled_exception_policy_get:
4459  *
4460  * This is a VM internal routine.
4461  *
4462  * Gets the runtime policy for handling unhandled exceptions.
4463  */
4464 MonoRuntimeUnhandledExceptionPolicy
4465 mono_runtime_unhandled_exception_policy_get (void) {
4466         return runtime_unhandled_exception_policy;
4467 }
4468
4469 /**
4470  * mono_unhandled_exception:
4471  * \param exc exception thrown
4472  * This is a VM internal routine.
4473  *
4474  * We call this function when we detect an unhandled exception
4475  * in the default domain.
4476  *
4477  * It invokes the \c UnhandledException event in \c AppDomain or prints
4478  * a warning to the console 
4479  */
4480 void
4481 mono_unhandled_exception (MonoObject *exc)
4482 {
4483         MONO_REQ_GC_UNSAFE_MODE;
4484
4485         MonoError error;
4486         MonoClassField *field;
4487         MonoDomain *current_domain, *root_domain;
4488         MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4489
4490         if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4491                 return;
4492
4493         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4494         g_assert (field);
4495
4496         current_domain = mono_domain_get ();
4497         root_domain = mono_get_root_domain ();
4498
4499         root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4500         mono_error_assert_ok (&error);
4501         if (current_domain != root_domain) {
4502                 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4503                 mono_error_assert_ok (&error);
4504         }
4505
4506         if (!current_appdomain_delegate && !root_appdomain_delegate) {
4507                 mono_print_unhandled_exception (exc);
4508         } else {
4509                 /* unhandled exception callbacks must not be aborted */
4510                 mono_threads_begin_abort_protected_block ();
4511                 if (root_appdomain_delegate)
4512                         call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4513                 if (current_appdomain_delegate)
4514                         call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4515                 mono_threads_end_abort_protected_block ();
4516         }
4517
4518         /* set exitcode only if we will abort the process */
4519         if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4520                  || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4521         {
4522                 mono_environment_exitcode_set (1);
4523         }
4524 }
4525
4526 /**
4527  * mono_runtime_exec_managed_code:
4528  * \param domain Application domain
4529  * \param main_func function to invoke from the execution thread
4530  * \param main_args parameter to the main_func
4531  * Launch a new thread to execute a function
4532  *
4533  * \p main_func is called back from the thread with main_args as the
4534  * parameter.  The callback function is expected to start \c Main
4535  * eventually.  This function then waits for all managed threads to
4536  * finish.
4537  * It is not necessary anymore to execute managed code in a subthread,
4538  * so this function should not be used anymore by default: just
4539  * execute the code and then call mono_thread_manage().
4540  */
4541 void
4542 mono_runtime_exec_managed_code (MonoDomain *domain,
4543                                 MonoMainThreadFunc main_func,
4544                                 gpointer main_args)
4545 {
4546         MonoError error;
4547         mono_thread_create_checked (domain, main_func, main_args, &error);
4548         mono_error_assert_ok (&error);
4549
4550         mono_thread_manage ();
4551 }
4552
4553 static void
4554 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4555 {
4556         MonoInternalThread* thread = mono_thread_internal_current ();
4557         MonoCustomAttrInfo* cinfo;
4558         gboolean has_stathread_attribute;
4559
4560         if (!domain->entry_assembly) {
4561                 gchar *str;
4562                 MonoAssembly *assembly;
4563
4564                 assembly = method->klass->image->assembly;
4565                 domain->entry_assembly = assembly;
4566                 /* Domains created from another domain already have application_base and configuration_file set */
4567                 if (domain->setup->application_base == NULL) {
4568                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4569                 }
4570
4571                 if (domain->setup->configuration_file == NULL) {
4572                         str = g_strconcat (assembly->image->name, ".config", NULL);
4573                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4574                         g_free (str);
4575                         mono_domain_set_options_from_config (domain);
4576                 }
4577         }
4578
4579         MonoError cattr_error;
4580         cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4581         mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4582         if (cinfo) {
4583                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4584                 if (!cinfo->cached)
4585                         mono_custom_attrs_free (cinfo);
4586         } else {
4587                 has_stathread_attribute = FALSE;
4588         }
4589         if (has_stathread_attribute) {
4590                 thread->apartment_state = ThreadApartmentState_STA;
4591         } else {
4592                 thread->apartment_state = ThreadApartmentState_MTA;
4593         }
4594         mono_thread_init_apartment_state ();
4595
4596 }
4597
4598 static int
4599 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4600 {
4601         MONO_REQ_GC_UNSAFE_MODE;
4602
4603         gpointer pa [1];
4604         int rval;
4605
4606         error_init (error);
4607         g_assert (args);
4608
4609         pa [0] = args;
4610
4611         /* FIXME: check signature of method */
4612         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4613                 MonoObject *res;
4614                 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4615                 if (is_ok (error))
4616                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4617                 else
4618                         rval = -1;
4619                 mono_environment_exitcode_set (rval);
4620         } else {
4621                 mono_runtime_invoke_checked (method, NULL, pa, error);
4622
4623                 if (is_ok (error))
4624                         rval = 0;
4625                 else {
4626                         rval = -1;
4627                 }
4628         }
4629         return rval;
4630 }
4631
4632 static int
4633 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4634 {
4635         MONO_REQ_GC_UNSAFE_MODE;
4636
4637         gpointer pa [1];
4638         int rval;
4639
4640         g_assert (args);
4641         g_assert (exc);
4642
4643         pa [0] = args;
4644
4645         /* FIXME: check signature of method */
4646         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4647                 MonoError inner_error;
4648                 MonoObject *res;
4649                 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4650                 if (*exc == NULL && !mono_error_ok (&inner_error))
4651                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4652                 else
4653                         mono_error_cleanup (&inner_error);
4654
4655                 if (*exc == NULL)
4656                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4657                 else
4658                         rval = -1;
4659
4660                 mono_environment_exitcode_set (rval);
4661         } else {
4662                 MonoError inner_error;
4663                 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4664                 if (*exc == NULL && !mono_error_ok (&inner_error))
4665                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4666                 else
4667                         mono_error_cleanup (&inner_error);
4668
4669                 if (*exc == NULL)
4670                         rval = 0;
4671                 else {
4672                         /* If the return type of Main is void, only
4673                          * set the exitcode if an exception was thrown
4674                          * (we don't want to blow away an
4675                          * explicitly-set exit code)
4676                          */
4677                         rval = -1;
4678                         mono_environment_exitcode_set (rval);
4679                 }
4680         }
4681
4682         return rval;
4683 }
4684
4685 /*
4686  * Execute a standard Main() method (args doesn't contain the
4687  * executable name).
4688  */
4689 int
4690 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4691 {
4692         MonoError error;
4693         prepare_thread_to_exec_main (mono_object_domain (args), method);
4694         if (exc) {
4695                 int rval = do_try_exec_main (method, args, exc);
4696                 return rval;
4697         } else {
4698                 int rval = do_exec_main_checked (method, args, &error);
4699                 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4700                 return rval;
4701         }
4702 }
4703
4704 /*
4705  * Execute a standard Main() method (args doesn't contain the
4706  * executable name).
4707  *
4708  * On failure sets @error
4709  */
4710 int
4711 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4712 {
4713         error_init (error);
4714         prepare_thread_to_exec_main (mono_object_domain (args), method);
4715         return do_exec_main_checked (method, args, error);
4716 }
4717
4718 /*
4719  * Execute a standard Main() method (args doesn't contain the
4720  * executable name).
4721  *
4722  * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4723  */
4724 int
4725 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4726 {
4727         prepare_thread_to_exec_main (mono_object_domain (args), method);
4728         return do_try_exec_main (method, args, exc);
4729 }
4730
4731
4732
4733 /** invoke_array_extract_argument:
4734  * @params: array of arguments to the method.
4735  * @i: the index of the argument to extract.
4736  * @t: ith type from the method signature.
4737  * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4738  * @error: set on error.
4739  *
4740  * Given an array of method arguments, return the ith one using the corresponding type
4741  * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4742  *
4743  * On failure sets @error and returns NULL.
4744  */
4745 static gpointer
4746 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4747 {
4748         MonoType *t_orig = t;
4749         gpointer result = NULL;
4750         error_init (error);
4751                 again:
4752                         switch (t->type) {
4753                         case MONO_TYPE_U1:
4754                         case MONO_TYPE_I1:
4755                         case MONO_TYPE_BOOLEAN:
4756                         case MONO_TYPE_U2:
4757                         case MONO_TYPE_I2:
4758                         case MONO_TYPE_CHAR:
4759                         case MONO_TYPE_U:
4760                         case MONO_TYPE_I:
4761                         case MONO_TYPE_U4:
4762                         case MONO_TYPE_I4:
4763                         case MONO_TYPE_U8:
4764                         case MONO_TYPE_I8:
4765                         case MONO_TYPE_R4:
4766                         case MONO_TYPE_R8:
4767                         case MONO_TYPE_VALUETYPE:
4768                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4769                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4770                                         result = mono_array_get (params, MonoObject*, i);
4771                                         if (t->byref)
4772                                                 *has_byref_nullables = TRUE;
4773                                 } else {
4774                                         /* MS seems to create the objects if a null is passed in */
4775                                         gboolean was_null = FALSE;
4776                                         if (!mono_array_get (params, MonoObject*, i)) {
4777                                                 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4778                                                 return_val_if_nok (error, NULL);
4779                                                 mono_array_setref (params, i, o); 
4780                                                 was_null = TRUE;
4781                                         }
4782
4783                                         if (t->byref) {
4784                                                 /*
4785                                                  * We can't pass the unboxed vtype byref to the callee, since
4786                                                  * that would mean the callee would be able to modify boxed
4787                                                  * primitive types. So we (and MS) make a copy of the boxed
4788                                                  * object, pass that to the callee, and replace the original
4789                                                  * boxed object in the arg array with the copy.
4790                                                  */
4791                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4792                                                 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4793                                                 return_val_if_nok (error, NULL);
4794                                                 mono_array_setref (params, i, copy);
4795                                         }
4796                                                 
4797                                         result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4798                                         if (!t->byref && was_null)
4799                                                 mono_array_setref (params, i, NULL);
4800                                 }
4801                                 break;
4802                         case MONO_TYPE_STRING:
4803                         case MONO_TYPE_OBJECT:
4804                         case MONO_TYPE_CLASS:
4805                         case MONO_TYPE_ARRAY:
4806                         case MONO_TYPE_SZARRAY:
4807                                 if (t->byref)
4808                                         result = mono_array_addr (params, MonoObject*, i);
4809                                         // FIXME: I need to check this code path
4810                                 else
4811                                         result = mono_array_get (params, MonoObject*, i);
4812                                 break;
4813                         case MONO_TYPE_GENERICINST:
4814                                 if (t->byref)
4815                                         t = &t->data.generic_class->container_class->this_arg;
4816                                 else
4817                                         t = &t->data.generic_class->container_class->byval_arg;
4818                                 goto again;
4819                         case MONO_TYPE_PTR: {
4820                                 MonoObject *arg;
4821
4822                                 /* The argument should be an IntPtr */
4823                                 arg = mono_array_get (params, MonoObject*, i);
4824                                 if (arg == NULL) {
4825                                         result = NULL;
4826                                 } else {
4827                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4828                                         result = ((MonoIntPtr*)arg)->m_value;
4829                                 }
4830                                 break;
4831                         }
4832                         default:
4833                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4834                         }
4835         return result;
4836 }
4837 /**
4838  * mono_runtime_invoke_array:
4839  * \param method method to invoke
4840  * \param obj object instance
4841  * \param params arguments to the method
4842  * \param exc exception information.
4843  * Invokes the method represented by \p method on the object \p obj.
4844  *
4845  * \p obj is the \c this pointer, it should be NULL for static
4846  * methods, a \c MonoObject* for object instances and a pointer to
4847  * the value type for value types.
4848  *
4849  * The \p params array contains the arguments to the method with the
4850  * same convention: \c MonoObject* pointers for object instances and
4851  * pointers to the value type otherwise. The \c _invoke_array
4852  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4853  * in this case the value types are boxed inside the
4854  * respective reference representation.
4855  * 
4856  * From unmanaged code you'll usually use the
4857  * mono_runtime_invoke_checked() variant.
4858  *
4859  * Note that this function doesn't handle virtual methods for
4860  * you, it will exec the exact method you pass: we still need to
4861  * expose a function to lookup the derived class implementation
4862  * of a virtual method (there are examples of this in the code,
4863  * though).
4864  * 
4865  * You can pass NULL as the \p exc argument if you don't want to
4866  * catch exceptions, otherwise, \c *exc will be set to the exception
4867  * thrown, if any.  if an exception is thrown, you can't use the
4868  * \c MonoObject* result from the function.
4869  * 
4870  * If the method returns a value type, it is boxed in an object
4871  * reference.
4872  */
4873 MonoObject*
4874 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4875                            MonoObject **exc)
4876 {
4877         MonoError error;
4878         if (exc) {
4879                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4880                 if (*exc) {
4881                         mono_error_cleanup (&error);
4882                         return NULL;
4883                 } else {
4884                         if (!is_ok (&error))
4885                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4886                         return result;
4887                 }
4888         } else {
4889                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4890                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4891                 return result;
4892         }
4893 }
4894
4895 /**
4896  * mono_runtime_invoke_array_checked:
4897  * \param method method to invoke
4898  * \param obj object instance
4899  * \param params arguments to the method
4900  * \param error set on failure.
4901  * Invokes the method represented by \p method on the object \p obj.
4902  *
4903  * \p obj is the \c this pointer, it should be NULL for static
4904  * methods, a \c MonoObject* for object instances and a pointer to
4905  * the value type for value types.
4906  *
4907  * The \p params array contains the arguments to the method with the
4908  * same convention: \c MonoObject* pointers for object instances and
4909  * pointers to the value type otherwise. The \c _invoke_array
4910  * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4911  * in this case the value types are boxed inside the
4912  * respective reference representation.
4913  *
4914  * From unmanaged code you'll usually use the
4915  * mono_runtime_invoke_checked() variant.
4916  *
4917  * Note that this function doesn't handle virtual methods for
4918  * you, it will exec the exact method you pass: we still need to
4919  * expose a function to lookup the derived class implementation
4920  * of a virtual method (there are examples of this in the code,
4921  * though).
4922  *
4923  * On failure or exception, \p error will be set. In that case, you
4924  * can't use the \c MonoObject* result from the function.
4925  *
4926  * If the method returns a value type, it is boxed in an object
4927  * reference.
4928  */
4929 MonoObject*
4930 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4931                                    MonoError *error)
4932 {
4933         error_init (error);
4934         return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4935 }
4936
4937 /**
4938  * mono_runtime_try_invoke_array:
4939  * \param method method to invoke
4940  * \param obj object instance
4941  * \param params arguments to the method
4942  * \param exc exception information.
4943  * \param error set on failure.
4944  * Invokes the method represented by \p method on the object \p obj.
4945  *
4946  * \p obj is the \c this pointer, it should be NULL for static
4947  * methods, a \c MonoObject* for object instances and a pointer to
4948  * the value type for value types.
4949  *
4950  * The \p params array contains the arguments to the method with the
4951  * same convention: \c MonoObject* pointers for object instances and
4952  * pointers to the value type otherwise. The \c _invoke_array
4953  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4954  * in this case the value types are boxed inside the
4955  * respective reference representation.
4956  *
4957  * From unmanaged code you'll usually use the
4958  * mono_runtime_invoke_checked() variant.
4959  *
4960  * Note that this function doesn't handle virtual methods for
4961  * you, it will exec the exact method you pass: we still need to
4962  * expose a function to lookup the derived class implementation
4963  * of a virtual method (there are examples of this in the code,
4964  * though).
4965  *
4966  * You can pass NULL as the \p exc argument if you don't want to catch
4967  * exceptions, otherwise, \c *exc will be set to the exception thrown, if
4968  * any.  On other failures, \p error will be set. If an exception is
4969  * thrown or there's an error, you can't use the \c MonoObject* result
4970  * from the function.
4971  *
4972  * If the method returns a value type, it is boxed in an object
4973  * reference.
4974  */
4975 MonoObject*
4976 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4977                                MonoObject **exc, MonoError *error)
4978 {
4979         MONO_REQ_GC_UNSAFE_MODE;
4980
4981         error_init (error);
4982
4983         MonoMethodSignature *sig = mono_method_signature (method);
4984         gpointer *pa = NULL;
4985         MonoObject *res;
4986         int i;
4987         gboolean has_byref_nullables = FALSE;
4988
4989         if (NULL != params) {
4990                 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4991                 for (i = 0; i < mono_array_length (params); i++) {
4992                         MonoType *t = sig->params [i];
4993                         pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4994                         return_val_if_nok (error, NULL);
4995                 }
4996         }
4997
4998         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4999                 void *o = obj;
5000
5001                 if (mono_class_is_nullable (method->klass)) {
5002                         /* Need to create a boxed vtype instead */
5003                         g_assert (!obj);
5004
5005                         if (!params)
5006                                 return NULL;
5007                         else {
5008                                 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5009                         }
5010                 }
5011
5012                 if (!obj) {
5013                         obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5014                         mono_error_assert_ok (error);
5015                         g_assert (obj); /*maybe we should raise a TLE instead?*/
5016 #ifndef DISABLE_REMOTING
5017                         if (mono_object_is_transparent_proxy (obj)) {
5018                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5019                         }
5020 #endif
5021                         if (method->klass->valuetype)
5022                                 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5023                         else
5024                                 o = obj;
5025                 } else if (method->klass->valuetype) {
5026                         obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5027                         return_val_if_nok (error, NULL);
5028                 }
5029
5030                 if (exc) {
5031                         mono_runtime_try_invoke (method, o, pa, exc, error);
5032                 } else {
5033                         mono_runtime_invoke_checked (method, o, pa, error);
5034                 }
5035
5036                 return (MonoObject *)obj;
5037         } else {
5038                 if (mono_class_is_nullable (method->klass)) {
5039                         MonoObject *nullable;
5040
5041                         /* Convert the unboxed vtype into a Nullable structure */
5042                         nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5043                         return_val_if_nok (error, NULL);
5044
5045                         MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5046                         return_val_if_nok (error, NULL);
5047                         mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5048                         obj = mono_object_unbox (nullable);
5049                 }
5050
5051                 /* obj must be already unboxed if needed */
5052                 if (exc) {
5053                         res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5054                 } else {
5055                         res = mono_runtime_invoke_checked (method, obj, pa, error);
5056                 }
5057                 return_val_if_nok (error, NULL);
5058
5059                 if (sig->ret->type == MONO_TYPE_PTR) {
5060                         MonoClass *pointer_class;
5061                         static MonoMethod *box_method;
5062                         void *box_args [2];
5063                         MonoObject *box_exc;
5064
5065                         /* 
5066                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
5067                          * convert it to a Pointer object.
5068                          */
5069                         pointer_class = mono_class_get_pointer_class ();
5070                         if (!box_method)
5071                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5072
5073                         g_assert (res->vtable->klass == mono_defaults.int_class);
5074                         box_args [0] = ((MonoIntPtr*)res)->m_value;
5075                         box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5076                         return_val_if_nok (error, NULL);
5077
5078                         res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5079                         g_assert (box_exc == NULL);
5080                         mono_error_assert_ok (error);
5081                 }
5082
5083                 if (has_byref_nullables) {
5084                         /* 
5085                          * The runtime invoke wrapper already converted byref nullables back,
5086                          * and stored them in pa, we just need to copy them back to the
5087                          * managed array.
5088                          */
5089                         for (i = 0; i < mono_array_length (params); i++) {
5090                                 MonoType *t = sig->params [i];
5091
5092                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5093                                         mono_array_setref (params, i, pa [i]);
5094                         }
5095                 }
5096
5097                 return res;
5098         }
5099 }
5100
5101 /**
5102  * mono_object_new:
5103  * \param klass the class of the object that we want to create
5104  * \returns a newly created object whose definition is
5105  * looked up using \p klass.   This will not invoke any constructors, 
5106  * so the consumer of this routine has to invoke any constructors on
5107  * its own to initialize the object.
5108  * 
5109  * It returns NULL on failure.
5110  */
5111 MonoObject *
5112 mono_object_new (MonoDomain *domain, MonoClass *klass)
5113 {
5114         MONO_REQ_GC_UNSAFE_MODE;
5115
5116         MonoError error;
5117
5118         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5119
5120         mono_error_cleanup (&error);
5121         return result;
5122 }
5123
5124 MonoObject *
5125 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5126 {
5127         MONO_REQ_GC_UNSAFE_MODE;
5128
5129         MonoError error;
5130
5131         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5132
5133         mono_error_set_pending_exception (&error);
5134         return result;
5135 }
5136
5137 /**
5138  * mono_object_new_checked:
5139  * \param klass the class of the object that we want to create
5140  * \param error set on error
5141  * \returns a newly created object whose definition is
5142  * looked up using \p klass.   This will not invoke any constructors,
5143  * so the consumer of this routine has to invoke any constructors on
5144  * its own to initialize the object.
5145  *
5146  * It returns NULL on failure and sets \p error.
5147  */
5148 MonoObject *
5149 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5150 {
5151         MONO_REQ_GC_UNSAFE_MODE;
5152
5153         MonoVTable *vtable;
5154
5155         vtable = mono_class_vtable (domain, klass);
5156         g_assert (vtable); /* FIXME don't swallow the error */
5157
5158         MonoObject *o = mono_object_new_specific_checked (vtable, error);
5159         return o;
5160 }
5161
5162 /**
5163  * mono_object_new_pinned:
5164  *
5165  *   Same as mono_object_new, but the returned object will be pinned.
5166  * For SGEN, these objects will only be freed at appdomain unload.
5167  */
5168 MonoObject *
5169 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5170 {
5171         MONO_REQ_GC_UNSAFE_MODE;
5172
5173         MonoVTable *vtable;
5174
5175         error_init (error);
5176
5177         vtable = mono_class_vtable (domain, klass);
5178         g_assert (vtable); /* FIXME don't swallow the error */
5179
5180         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5181
5182         if (G_UNLIKELY (!o))
5183                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5184         else if (G_UNLIKELY (vtable->klass->has_finalize))
5185                 mono_object_register_finalizer (o);
5186
5187         return o;
5188 }
5189
5190 /**
5191  * mono_object_new_specific:
5192  * \param vtable the vtable of the object that we want to create
5193  * \returns A newly created object with class and domain specified
5194  * by \p vtable
5195  */
5196 MonoObject *
5197 mono_object_new_specific (MonoVTable *vtable)
5198 {
5199         MonoError error;
5200         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5201         mono_error_cleanup (&error);
5202
5203         return o;
5204 }
5205
5206 MonoObject *
5207 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5208 {
5209         MONO_REQ_GC_UNSAFE_MODE;
5210
5211         MonoObject *o;
5212
5213         error_init (error);
5214
5215         /* check for is_com_object for COM Interop */
5216         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5217         {
5218                 gpointer pa [1];
5219                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5220
5221                 if (im == NULL) {
5222                         MonoClass *klass = mono_class_get_activation_services_class ();
5223
5224                         if (!klass->inited)
5225                                 mono_class_init (klass);
5226
5227                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5228                         if (!im) {
5229                                 mono_error_set_not_supported (error, "Linked away.");
5230                                 return NULL;
5231                         }
5232                         vtable->domain->create_proxy_for_type_method = im;
5233                 }
5234         
5235                 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5236                 if (!mono_error_ok (error))
5237                         return NULL;
5238
5239                 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5240                 if (!mono_error_ok (error))
5241                         return NULL;
5242
5243                 if (o != NULL)
5244                         return o;
5245         }
5246
5247         return mono_object_new_alloc_specific_checked (vtable, error);
5248 }
5249
5250 MonoObject *
5251 ves_icall_object_new_specific (MonoVTable *vtable)
5252 {
5253         MonoError error;
5254         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5255         mono_error_set_pending_exception (&error);
5256
5257         return o;
5258 }
5259
5260 /**
5261  * mono_object_new_alloc_specific:
5262  * \param vtable virtual table for the object.
5263  * This function allocates a new \c MonoObject with the type derived
5264  * from the \p vtable information.   If the class of this object has a 
5265  * finalizer, then the object will be tracked for finalization.
5266  *
5267  * This method might raise an exception on errors.  Use the
5268  * \c mono_object_new_fast_checked method if you want to manually raise
5269  * the exception.
5270  *
5271  * \returns the allocated object.   
5272  */
5273 MonoObject *
5274 mono_object_new_alloc_specific (MonoVTable *vtable)
5275 {
5276         MonoError error;
5277         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5278         mono_error_cleanup (&error);
5279
5280         return o;
5281 }
5282
5283 /**
5284  * mono_object_new_alloc_specific_checked:
5285  * \param vtable virtual table for the object.
5286  * \param error holds the error return value.  
5287  *
5288  * This function allocates a new \c MonoObject with the type derived
5289  * from the \p vtable information. If the class of this object has a 
5290  * finalizer, then the object will be tracked for finalization.
5291  *
5292  * If there is not enough memory, the \p error parameter will be set
5293  * and will contain a user-visible message with the amount of bytes
5294  * that were requested.
5295  *
5296  * \returns the allocated object, or NULL if there is not enough memory
5297  */
5298 MonoObject *
5299 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5300 {
5301         MONO_REQ_GC_UNSAFE_MODE;
5302
5303         MonoObject *o;
5304
5305         error_init (error);
5306
5307         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5308
5309         if (G_UNLIKELY (!o))
5310                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5311         else if (G_UNLIKELY (vtable->klass->has_finalize))
5312                 mono_object_register_finalizer (o);
5313
5314         return o;
5315 }
5316
5317 /**
5318  * mono_object_new_fast:
5319  * \param vtable virtual table for the object.
5320  *
5321  * This function allocates a new \c MonoObject with the type derived
5322  * from the \p vtable information.   The returned object is not tracked
5323  * for finalization.   If your object implements a finalizer, you should
5324  * use \c mono_object_new_alloc_specific instead.
5325  *
5326  * This method might raise an exception on errors.  Use the
5327  * \c mono_object_new_fast_checked method if you want to manually raise
5328  * the exception.
5329  *
5330  * \returns the allocated object.   
5331  */
5332 MonoObject*
5333 mono_object_new_fast (MonoVTable *vtable)
5334 {
5335         MonoError error;
5336         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5337         mono_error_cleanup (&error);
5338
5339         return o;
5340 }
5341
5342 /**
5343  * mono_object_new_fast_checked:
5344  * \param vtable virtual table for the object.
5345  * \param error holds the error return value.
5346  *
5347  * This function allocates a new \c MonoObject with the type derived
5348  * from the \p vtable information. The returned object is not tracked
5349  * for finalization.   If your object implements a finalizer, you should
5350  * use \c mono_object_new_alloc_specific_checked instead.
5351  *
5352  * If there is not enough memory, the \p error parameter will be set
5353  * and will contain a user-visible message with the amount of bytes
5354  * that were requested.
5355  *
5356  * \returns the allocated object, or NULL if there is not enough memory
5357  */
5358 MonoObject*
5359 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5360 {
5361         MONO_REQ_GC_UNSAFE_MODE;
5362
5363         MonoObject *o;
5364
5365         error_init (error);
5366
5367         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5368
5369         if (G_UNLIKELY (!o))
5370                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5371
5372         return o;
5373 }
5374
5375 MonoObject *
5376 ves_icall_object_new_fast (MonoVTable *vtable)
5377 {
5378         MonoError error;
5379         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5380         mono_error_set_pending_exception (&error);
5381
5382         return o;
5383 }
5384
5385 MonoObject*
5386 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5387 {
5388         MONO_REQ_GC_UNSAFE_MODE;
5389
5390         MonoObject *o;
5391
5392         error_init (error);
5393
5394         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5395
5396         if (G_UNLIKELY (!o))
5397                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5398         else if (G_UNLIKELY (vtable->klass->has_finalize))
5399                 mono_object_register_finalizer (o);
5400
5401         return o;
5402 }
5403
5404 /**
5405  * mono_class_get_allocation_ftn:
5406  * \param vtable vtable
5407  * \param for_box the object will be used for boxing
5408  * \param pass_size_in_words Unused
5409  * \returns the allocation function appropriate for the given class.
5410  */
5411 void*
5412 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5413 {
5414         MONO_REQ_GC_NEUTRAL_MODE;
5415
5416         *pass_size_in_words = FALSE;
5417
5418         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5419                 return ves_icall_object_new_specific;
5420
5421         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5422
5423                 return ves_icall_object_new_fast;
5424
5425                 /* 
5426                  * FIXME: This is actually slower than ves_icall_object_new_fast, because
5427                  * of the overhead of parameter passing.
5428                  */
5429                 /*
5430                 *pass_size_in_words = TRUE;
5431 #ifdef GC_REDIRECT_TO_LOCAL
5432                 return GC_local_gcj_fast_malloc;
5433 #else
5434                 return GC_gcj_fast_malloc;
5435 #endif
5436                 */
5437         }
5438
5439         return ves_icall_object_new_specific;
5440 }
5441
5442 /**
5443  * mono_object_new_from_token:
5444  * \param image Context where the type_token is hosted
5445  * \param token a token of the type that we want to create
5446  * \returns A newly created object whose definition is
5447  * looked up using \p token in the \p image image
5448  */
5449 MonoObject *
5450 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
5451 {
5452         MONO_REQ_GC_UNSAFE_MODE;
5453
5454         MonoError error;
5455         MonoObject *result;
5456         MonoClass *klass;
5457
5458         klass = mono_class_get_checked (image, token, &error);
5459         mono_error_assert_ok (&error);
5460         
5461         result = mono_object_new_checked (domain, klass, &error);
5462
5463         mono_error_cleanup (&error);
5464         return result;
5465         
5466 }
5467
5468
5469 /**
5470  * mono_object_clone:
5471  * \param obj the object to clone
5472  * \returns A newly created object who is a shallow copy of \p obj
5473  */
5474 MonoObject *
5475 mono_object_clone (MonoObject *obj)
5476 {
5477         MonoError error;
5478         MonoObject *o = mono_object_clone_checked (obj, &error);
5479         mono_error_cleanup (&error);
5480
5481         return o;
5482 }
5483
5484 MonoObject *
5485 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5486 {
5487         MONO_REQ_GC_UNSAFE_MODE;
5488
5489         MonoObject *o;
5490         int size;
5491
5492         error_init (error);
5493
5494         size = obj->vtable->klass->instance_size;
5495
5496         if (obj->vtable->klass->rank)
5497                 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5498
5499         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5500
5501         if (G_UNLIKELY (!o)) {
5502                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5503                 return NULL;
5504         }
5505
5506         /* If the object doesn't contain references this will do a simple memmove. */
5507         mono_gc_wbarrier_object_copy (o, obj);
5508
5509         if (obj->vtable->klass->has_finalize)
5510                 mono_object_register_finalizer (o);
5511         return o;
5512 }
5513
5514 /**
5515  * mono_array_full_copy:
5516  * \param src source array to copy
5517  * \param dest destination array
5518  * Copies the content of one array to another with exactly the same type and size.
5519  */
5520 void
5521 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5522 {
5523         MONO_REQ_GC_UNSAFE_MODE;
5524
5525         uintptr_t size;
5526         MonoClass *klass = src->obj.vtable->klass;
5527
5528         g_assert (klass == dest->obj.vtable->klass);
5529
5530         size = mono_array_length (src);
5531         g_assert (size == mono_array_length (dest));
5532         size *= mono_array_element_size (klass);
5533
5534         array_full_copy_unchecked_size (src, dest, klass, size);
5535 }
5536
5537 static void
5538 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5539 {
5540 #ifdef HAVE_SGEN_GC
5541         if (klass->element_class->valuetype) {
5542                 if (klass->element_class->has_references)
5543                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5544                 else
5545                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5546         } else {
5547                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5548         }
5549 #else
5550         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5551 #endif
5552 }
5553
5554 /**
5555  * mono_array_clone_in_domain:
5556  * \param domain the domain in which the array will be cloned into
5557  * \param array the array to clone
5558  * \param error set on error
5559  * This routine returns a copy of the array that is hosted on the
5560  * specified \c MonoDomain.  On failure returns NULL and sets \p error.
5561  */
5562 MonoArrayHandle
5563 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5564 {
5565         MONO_REQ_GC_UNSAFE_MODE;
5566
5567         MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5568         uintptr_t size = 0;
5569         MonoClass *klass = mono_handle_class (array_handle);
5570
5571         error_init (error);
5572
5573         /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5574         uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5575         
5576         MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5577         MonoArrayHandle o;
5578         if (array_bounds == NULL) {
5579                 size = mono_array_handle_length (array_handle);
5580                 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5581                 if (!is_ok (error))
5582                         goto leave;
5583                 size *= mono_array_element_size (klass);
5584         } else {
5585                 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5586                 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5587                 size = mono_array_element_size (klass);
5588                 for (int i = 0; i < klass->rank; ++i) {
5589                         sizes [i] = array_bounds [i].length;
5590                         size *= array_bounds [i].length;
5591                         lower_bounds [i] = array_bounds [i].lower_bound;
5592                 }
5593                 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5594                 if (!is_ok (error))
5595                         goto leave;
5596         }
5597
5598         uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5599         array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5600         mono_gchandle_free (dst_handle);
5601
5602         MONO_HANDLE_ASSIGN (result, o);
5603
5604 leave:
5605         mono_gchandle_free (src_handle);
5606         return result;
5607 }
5608
5609 /**
5610  * mono_array_clone:
5611  * \param array the array to clone
5612  * \returns A newly created array who is a shallow copy of \p array
5613  */
5614 MonoArray*
5615 mono_array_clone (MonoArray *array)
5616 {
5617         MONO_REQ_GC_UNSAFE_MODE;
5618
5619         MonoError error;
5620         MonoArray *result = mono_array_clone_checked (array, &error);
5621         mono_error_cleanup (&error);
5622         return result;
5623 }
5624
5625 /**
5626  * mono_array_clone_checked:
5627  * \param array the array to clone
5628  * \param error set on error
5629  * \returns A newly created array who is a shallow copy of \p array.  On
5630  * failure returns NULL and sets \p error.
5631  */
5632 MonoArray*
5633 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5634 {
5635         MONO_REQ_GC_UNSAFE_MODE;
5636         HANDLE_FUNCTION_ENTER ();
5637         /* FIXME: callers of mono_array_clone_checked should use handles */
5638         error_init (error);
5639         MONO_HANDLE_DCL (MonoArray, array);
5640         MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5641         HANDLE_FUNCTION_RETURN_OBJ (result);
5642 }
5643
5644 /* helper macros to check for overflow when calculating the size of arrays */
5645 #ifdef MONO_BIG_ARRAYS
5646 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5647 #define MYGUINT_MAX MYGUINT64_MAX
5648 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5649             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5650 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5651             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
5652                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5653 #else
5654 #define MYGUINT32_MAX 4294967295U
5655 #define MYGUINT_MAX MYGUINT32_MAX
5656 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5657             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5658 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5659             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
5660                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5661 #endif
5662
5663 gboolean
5664 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5665 {
5666         MONO_REQ_GC_NEUTRAL_MODE;
5667
5668         uintptr_t byte_len;
5669
5670         byte_len = mono_array_element_size (klass);
5671         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5672                 return FALSE;
5673         byte_len *= len;
5674         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5675                 return FALSE;
5676         byte_len += MONO_SIZEOF_MONO_ARRAY;
5677
5678         *res = byte_len;
5679
5680         return TRUE;
5681 }
5682
5683 /**
5684  * mono_array_new_full:
5685  * \param domain domain where the object is created
5686  * \param array_class array class
5687  * \param lengths lengths for each dimension in the array
5688  * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5689  * This routine creates a new array object with the given dimensions,
5690  * lower bounds and type.
5691  */
5692 MonoArray*
5693 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5694 {
5695         MonoError error;
5696         MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5697         mono_error_cleanup (&error);
5698
5699         return array;
5700 }
5701
5702 MonoArray*
5703 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5704 {
5705         MONO_REQ_GC_UNSAFE_MODE;
5706
5707         uintptr_t byte_len = 0, len, bounds_size;
5708         MonoObject *o;
5709         MonoArray *array;
5710         MonoArrayBounds *bounds;
5711         MonoVTable *vtable;
5712         int i;
5713
5714         error_init (error);
5715
5716         if (!array_class->inited)
5717                 mono_class_init (array_class);
5718
5719         len = 1;
5720
5721         /* A single dimensional array with a 0 lower bound is the same as an szarray */
5722         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5723                 len = lengths [0];
5724                 if (len > MONO_ARRAY_MAX_INDEX) {
5725                         mono_error_set_generic_error (error, "System", "OverflowException", "");
5726                         return NULL;
5727                 }
5728                 bounds_size = 0;
5729         } else {
5730                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5731
5732                 for (i = 0; i < array_class->rank; ++i) {
5733                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5734                                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5735                                 return NULL;
5736                         }
5737                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5738                                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5739                                 return NULL;
5740                         }
5741                         len *= lengths [i];
5742                 }
5743         }
5744
5745         if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5746                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5747                 return NULL;
5748         }
5749
5750         if (bounds_size) {
5751                 /* align */
5752                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5753                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5754                         return NULL;
5755                 }
5756                 byte_len = (byte_len + 3) & ~3;
5757                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5758                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5759                         return NULL;
5760                 }
5761                 byte_len += bounds_size;
5762         }
5763         /* 
5764          * Following three lines almost taken from mono_object_new ():
5765          * they need to be kept in sync.
5766          */
5767         vtable = mono_class_vtable_full (domain, array_class, error);
5768         return_val_if_nok (error, NULL);
5769
5770         if (bounds_size)
5771                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5772         else
5773                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5774
5775         if (G_UNLIKELY (!o)) {
5776                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5777                 return NULL;
5778         }
5779
5780         array = (MonoArray*)o;
5781
5782         bounds = array->bounds;
5783
5784         if (bounds_size) {
5785                 for (i = 0; i < array_class->rank; ++i) {
5786                         bounds [i].length = lengths [i];
5787                         if (lower_bounds)
5788                                 bounds [i].lower_bound = lower_bounds [i];
5789                 }
5790         }
5791
5792         return array;
5793 }
5794
5795 /**
5796  * mono_array_new:
5797  * \param domain domain where the object is created
5798  * \param eclass element class
5799  * \param n number of array elements
5800  * This routine creates a new szarray with \p n elements of type \p eclass.
5801  */
5802 MonoArray *
5803 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5804 {
5805         MONO_REQ_GC_UNSAFE_MODE;
5806
5807         MonoError error;
5808         MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5809         mono_error_cleanup (&error);
5810         return result;
5811 }
5812
5813 /**
5814  * mono_array_new_checked:
5815  * \param domain domain where the object is created
5816  * \param eclass element class
5817  * \param n number of array elements
5818  * \param error set on error
5819  * This routine creates a new szarray with \p n elements of type \p eclass.
5820  * On failure returns NULL and sets \p error.
5821  */
5822 MonoArray *
5823 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5824 {
5825         MonoClass *ac;
5826
5827         error_init (error);
5828
5829         ac = mono_array_class_get (eclass, 1);
5830         g_assert (ac);
5831
5832         MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5833         return_val_if_nok (error, NULL);
5834
5835         return mono_array_new_specific_checked (vtable, n, error);
5836 }
5837
5838 MonoArray*
5839 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5840 {
5841         MonoError error;
5842         MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5843         mono_error_set_pending_exception (&error);
5844
5845         return arr;
5846 }
5847
5848 /**
5849  * mono_array_new_specific:
5850  * \param vtable a vtable in the appropriate domain for an initialized class
5851  * \param n number of array elements
5852  * This routine is a fast alternative to \c mono_array_new for code which
5853  * can be sure about the domain it operates in.
5854  */
5855 MonoArray *
5856 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5857 {
5858         MonoError error;
5859         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5860         mono_error_cleanup (&error);
5861
5862         return arr;
5863 }
5864
5865 MonoArray*
5866 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5867 {
5868         MONO_REQ_GC_UNSAFE_MODE;
5869
5870         MonoObject *o;
5871         uintptr_t byte_len;
5872
5873         error_init (error);
5874
5875         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5876                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5877                 return NULL;
5878         }
5879
5880         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5881                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5882                 return NULL;
5883         }
5884         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5885
5886         if (G_UNLIKELY (!o)) {
5887                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5888                 return NULL;
5889         }
5890
5891         return (MonoArray*)o;
5892 }
5893
5894 MonoArray*
5895 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5896 {
5897         MonoError error;
5898         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5899         mono_error_set_pending_exception (&error);
5900
5901         return arr;
5902 }
5903
5904 /**
5905  * mono_string_empty_wrapper:
5906  *
5907  * Returns: The same empty string instance as the managed string.Empty
5908  */
5909 MonoString*
5910 mono_string_empty_wrapper (void)
5911 {
5912         MonoDomain *domain = mono_domain_get ();
5913         return mono_string_empty (domain);
5914 }
5915
5916 /**
5917  * mono_string_empty:
5918  *
5919  * Returns: The same empty string instance as the managed string.Empty
5920  */
5921 MonoString*
5922 mono_string_empty (MonoDomain *domain)
5923 {
5924         g_assert (domain);
5925         g_assert (domain->empty_string);
5926         return domain->empty_string;
5927 }
5928
5929 /**
5930  * mono_string_new_utf16:
5931  * \param text a pointer to an utf16 string
5932  * \param len the length of the string
5933  * \returns A newly created string object which contains \p text.
5934  */
5935 MonoString *
5936 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5937 {
5938         MONO_REQ_GC_UNSAFE_MODE;
5939
5940         MonoError error;
5941         MonoString *res = NULL;
5942         res = mono_string_new_utf16_checked (domain, text, len, &error);
5943         mono_error_cleanup (&error);
5944
5945         return res;
5946 }
5947
5948 /**
5949  * mono_string_new_utf16_checked:
5950  * \param text a pointer to an utf16 string
5951  * \param len the length of the string
5952  * \param error written on error.
5953  * \returns A newly created string object which contains \p text.
5954  * On error, returns NULL and sets \p error.
5955  */
5956 MonoString *
5957 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5958 {
5959         MONO_REQ_GC_UNSAFE_MODE;
5960
5961         MonoString *s;
5962         
5963         error_init (error);
5964         
5965         s = mono_string_new_size_checked (domain, len, error);
5966         if (s != NULL)
5967                 memcpy (mono_string_chars (s), text, len * 2);
5968
5969         return s;
5970 }
5971
5972 /**
5973  * mono_string_new_utf16_handle:
5974  * \param text a pointer to an utf16 string
5975  * \param len the length of the string
5976  * \param error written on error.
5977  * \returns A newly created string object which contains \p text.
5978  * On error, returns NULL and sets \p error.
5979  */
5980 MonoStringHandle
5981 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5982 {
5983         return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
5984 }
5985
5986 /**
5987  * mono_string_new_utf32_checked:
5988  * \param text a pointer to an utf32 string
5989  * \param len the length of the string
5990  * \param error set on failure.
5991  * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
5992  */
5993 static MonoString *
5994 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5995 {
5996         MONO_REQ_GC_UNSAFE_MODE;
5997
5998         MonoString *s;
5999         mono_unichar2 *utf16_output = NULL;
6000         gint32 utf16_len = 0;
6001         GError *gerror = NULL;
6002         glong items_written;
6003         
6004         error_init (error);
6005         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6006         
6007         if (gerror)
6008                 g_error_free (gerror);
6009
6010         while (utf16_output [utf16_len]) utf16_len++;
6011         
6012         s = mono_string_new_size_checked (domain, utf16_len, error);
6013         return_val_if_nok (error, NULL);
6014
6015         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6016
6017         g_free (utf16_output);
6018         
6019         return s;
6020 }
6021
6022 /**
6023  * mono_string_new_utf32:
6024  * \param text a pointer to a UTF-32 string
6025  * \param len the length of the string
6026  * \returns A newly created string object which contains \p text.
6027  */
6028 MonoString *
6029 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6030 {
6031         MonoError error;
6032         MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6033         mono_error_cleanup (&error);
6034         return result;
6035 }
6036
6037 /**
6038  * mono_string_new_size:
6039  * \param text a pointer to a UTF-16 string
6040  * \param len the length of the string
6041  * \returns A newly created string object of \p len
6042  */
6043 MonoString *
6044 mono_string_new_size (MonoDomain *domain, gint32 len)
6045 {
6046         MonoError error;
6047         MonoString *str = mono_string_new_size_checked (domain, len, &error);
6048         mono_error_cleanup (&error);
6049
6050         return str;
6051 }
6052
6053 MonoString *
6054 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6055 {
6056         MONO_REQ_GC_UNSAFE_MODE;
6057
6058         MonoString *s;
6059         MonoVTable *vtable;
6060         size_t size;
6061
6062         error_init (error);
6063
6064         /* check for overflow */
6065         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6066                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6067                 return NULL;
6068         }
6069
6070         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6071         g_assert (size > 0);
6072
6073         vtable = mono_class_vtable (domain, mono_defaults.string_class);
6074         g_assert (vtable);
6075
6076         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6077
6078         if (G_UNLIKELY (!s)) {
6079                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6080                 return NULL;
6081         }
6082
6083         return s;
6084 }
6085
6086 /**
6087  * mono_string_new_len:
6088  * \param text a pointer to an utf8 string
6089  * \param length number of bytes in \p text to consider
6090  * \returns A newly created string object which contains \p text.
6091  */
6092 MonoString*
6093 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6094 {
6095         MONO_REQ_GC_UNSAFE_MODE;
6096
6097         MonoError error;
6098         MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6099         mono_error_cleanup (&error);
6100         return result;
6101 }
6102
6103 /**
6104  * mono_string_new_len_checked:
6105  * \param text a pointer to an utf8 string
6106  * \param length number of bytes in \p text to consider
6107  * \param error set on error
6108  * \returns A newly created string object which contains \p text. On
6109  * failure returns NULL and sets \p error.
6110  */
6111 MonoString*
6112 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6113 {
6114         MONO_REQ_GC_UNSAFE_MODE;
6115
6116         error_init (error);
6117
6118         GError *eg_error = NULL;
6119         MonoString *o = NULL;
6120         guint16 *ut = NULL;
6121         glong items_written;
6122
6123         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6124
6125         if (!eg_error)
6126                 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6127         else 
6128                 g_error_free (eg_error);
6129
6130         g_free (ut);
6131
6132         return o;
6133 }
6134
6135 /**
6136  * mono_string_new:
6137  * \param text a pointer to a UTF-8 string
6138  * \deprecated Use \c mono_string_new_checked in new code.
6139  * This function asserts if it cannot allocate a new string.
6140  * \returns A newly created string object which contains \p text.
6141  */
6142 MonoString*
6143 mono_string_new (MonoDomain *domain, const char *text)
6144 {
6145         MonoError error;
6146         MonoString *res = NULL;
6147         res = mono_string_new_checked (domain, text, &error);
6148         mono_error_assert_ok (&error);
6149         return res;
6150 }
6151
6152 /**
6153  * mono_string_new_checked:
6154  * \param text a pointer to an utf8 string
6155  * \param merror set on error
6156  * \returns A newly created string object which contains \p text.
6157  * On error returns NULL and sets \p merror.
6158  */
6159 MonoString*
6160 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6161 {
6162         MONO_REQ_GC_UNSAFE_MODE;
6163
6164     GError *eg_error = NULL;
6165     MonoString *o = NULL;
6166     guint16 *ut;
6167     glong items_written;
6168     int l;
6169
6170     error_init (error);
6171
6172     l = strlen (text);
6173    
6174     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6175
6176     if (!eg_error)
6177             o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6178     else
6179         g_error_free (eg_error);
6180
6181     g_free (ut);
6182     
6183 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6184 #if 0
6185         gunichar2 *str;
6186         const gchar *end;
6187         int len;
6188         MonoString *o = NULL;
6189
6190         if (!g_utf8_validate (text, -1, &end)) {
6191                 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6192                 goto leave;
6193         }
6194
6195         len = g_utf8_strlen (text, -1);
6196         o = mono_string_new_size_checked (domain, len, error);
6197         if (!o)
6198                 goto leave;
6199         str = mono_string_chars (o);
6200
6201         while (text < end) {
6202                 *str++ = g_utf8_get_char (text);
6203                 text = g_utf8_next_char (text);
6204         }
6205
6206 leave:
6207 #endif
6208         return o;
6209 }
6210
6211 /**
6212  * mono_string_new_wrapper:
6213  * \param text pointer to UTF-8 characters.
6214  * Helper function to create a string object from \p text in the current domain.
6215  */
6216 MonoString*
6217 mono_string_new_wrapper (const char *text)
6218 {
6219         MONO_REQ_GC_UNSAFE_MODE;
6220
6221         MonoDomain *domain = mono_domain_get ();
6222
6223         if (text)
6224                 return mono_string_new (domain, text);
6225
6226         return NULL;
6227 }
6228
6229 /**
6230  * mono_value_box:
6231  * \param class the class of the value
6232  * \param value a pointer to the unboxed data
6233  * \returns A newly created object which contains \p value.
6234  */
6235 MonoObject *
6236 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6237 {
6238         MonoError error;
6239         MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6240         mono_error_cleanup (&error);
6241         return result;
6242 }
6243
6244 /**
6245  * mono_value_box_checked:
6246  * \param domain the domain of the new object
6247  * \param class the class of the value
6248  * \param value a pointer to the unboxed data
6249  * \param error set on error
6250  * \returns A newly created object which contains \p value. On failure
6251  * returns NULL and sets \p error.
6252  */
6253 MonoObject *
6254 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6255 {
6256         MONO_REQ_GC_UNSAFE_MODE;
6257         MonoObject *res;
6258         int size;
6259         MonoVTable *vtable;
6260
6261         error_init (error);
6262
6263         g_assert (klass->valuetype);
6264         if (mono_class_is_nullable (klass))
6265                 return mono_nullable_box ((guint8 *)value, klass, error);
6266
6267         vtable = mono_class_vtable (domain, klass);
6268         if (!vtable)
6269                 return NULL;
6270         size = mono_class_instance_size (klass);
6271         res = mono_object_new_alloc_specific_checked (vtable, error);
6272         return_val_if_nok (error, NULL);
6273
6274         size = size - sizeof (MonoObject);
6275
6276 #ifdef HAVE_SGEN_GC
6277         g_assert (size == mono_class_value_size (klass, NULL));
6278         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6279 #else
6280 #if NO_UNALIGNED_ACCESS
6281         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6282 #else
6283         switch (size) {
6284         case 1:
6285                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6286                 break;
6287         case 2:
6288                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6289                 break;
6290         case 4:
6291                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6292                 break;
6293         case 8:
6294                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6295                 break;
6296         default:
6297                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6298         }
6299 #endif
6300 #endif
6301         if (klass->has_finalize) {
6302                 mono_object_register_finalizer (res);
6303                 return_val_if_nok (error, NULL);
6304         }
6305         return res;
6306 }
6307
6308 /**
6309  * mono_value_copy:
6310  * \param dest destination pointer
6311  * \param src source pointer
6312  * \param klass a valuetype class
6313  * Copy a valuetype from \p src to \p dest. This function must be used
6314  * when \p klass contains reference fields.
6315  */
6316 void
6317 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6318 {
6319         MONO_REQ_GC_UNSAFE_MODE;
6320
6321         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6322 }
6323
6324 /**
6325  * mono_value_copy_array:
6326  * \param dest destination array
6327  * \param dest_idx index in the \p dest array
6328  * \param src source pointer
6329  * \param count number of items
6330  * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx. 
6331  * This function must be used when \p klass contains references fields.
6332  * Overlap is handled.
6333  */
6334 void
6335 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6336 {
6337         MONO_REQ_GC_UNSAFE_MODE;
6338
6339         int size = mono_array_element_size (dest->obj.vtable->klass);
6340         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6341         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6342         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6343 }
6344
6345 /**
6346  * mono_object_get_domain:
6347  * \param obj object to query
6348  * \returns the \c MonoDomain where the object is hosted
6349  */
6350 MonoDomain*
6351 mono_object_get_domain (MonoObject *obj)
6352 {
6353         MONO_REQ_GC_UNSAFE_MODE;
6354
6355         return mono_object_domain (obj);
6356 }
6357
6358 /**
6359  * mono_object_get_class:
6360  * \param obj object to query
6361  * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6362  * \returns the \c MonoClass of the object.
6363  */
6364 MonoClass*
6365 mono_object_get_class (MonoObject *obj)
6366 {
6367         MONO_REQ_GC_UNSAFE_MODE;
6368
6369         return mono_object_class (obj);
6370 }
6371 /**
6372  * mono_object_get_size:
6373  * \param o object to query
6374  * \returns the size, in bytes, of \p o
6375  */
6376 guint
6377 mono_object_get_size (MonoObject* o)
6378 {
6379         MONO_REQ_GC_UNSAFE_MODE;
6380
6381         MonoClass* klass = mono_object_class (o);
6382         if (klass == mono_defaults.string_class) {
6383                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6384         } else if (o->vtable->rank) {
6385                 MonoArray *array = (MonoArray*)o;
6386                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6387                 if (array->bounds) {
6388                         size += 3;
6389                         size &= ~3;
6390                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
6391                 }
6392                 return size;
6393         } else {
6394                 return mono_class_instance_size (klass);
6395         }
6396 }
6397
6398 /**
6399  * mono_object_unbox:
6400  * \param obj object to unbox
6401  * \returns a pointer to the start of the valuetype boxed in this
6402  * object.
6403  *
6404  * This method will assert if the object passed is not a valuetype.
6405  */
6406 gpointer
6407 mono_object_unbox (MonoObject *obj)
6408 {
6409         MONO_REQ_GC_UNSAFE_MODE;
6410
6411         /* add assert for valuetypes? */
6412         g_assert (obj->vtable->klass->valuetype);
6413         return ((char*)obj) + sizeof (MonoObject);
6414 }
6415
6416 /**
6417  * mono_object_isinst:
6418  * \param obj an object
6419  * \param klass a pointer to a class 
6420  * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6421  */
6422 MonoObject *
6423 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6424 {
6425         MONO_REQ_GC_UNSAFE_MODE;
6426
6427         HANDLE_FUNCTION_ENTER ();
6428         MONO_HANDLE_DCL (MonoObject, obj);
6429         MonoError error;
6430         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6431         mono_error_cleanup (&error);
6432         HANDLE_FUNCTION_RETURN_OBJ (result);
6433 }
6434         
6435
6436 /**
6437  * mono_object_isinst_checked:
6438  * \param obj an object
6439  * \param klass a pointer to a class 
6440  * \param error set on error
6441  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6442  * On failure returns NULL and sets \p error.
6443  */
6444 MonoObject *
6445 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6446 {
6447         MONO_REQ_GC_UNSAFE_MODE;
6448
6449         HANDLE_FUNCTION_ENTER ();
6450         error_init (error);
6451         MONO_HANDLE_DCL (MonoObject, obj);
6452         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6453         HANDLE_FUNCTION_RETURN_OBJ (result);
6454 }
6455
6456 /**
6457  * mono_object_handle_isinst:
6458  * \param obj an object
6459  * \param klass a pointer to a class 
6460  * \param error set on error
6461  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6462  * On failure returns NULL and sets \p error.
6463  */
6464 MonoObjectHandle
6465 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6466 {
6467         error_init (error);
6468         
6469         if (!klass->inited)
6470                 mono_class_init (klass);
6471
6472         if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6473                 return mono_object_handle_isinst_mbyref (obj, klass, error);
6474         }
6475
6476         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6477
6478         if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6479                 MONO_HANDLE_ASSIGN (result, obj);
6480         return result;
6481 }
6482
6483 MonoObject *
6484 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6485 {
6486         MONO_REQ_GC_UNSAFE_MODE;
6487
6488         HANDLE_FUNCTION_ENTER ();
6489         MonoError error;
6490         MONO_HANDLE_DCL (MonoObject, obj);
6491         MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6492         mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6493         HANDLE_FUNCTION_RETURN_OBJ (result);
6494 }
6495
6496 MonoObjectHandle
6497 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6498 {
6499         error_init (error);
6500
6501         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6502
6503         if (MONO_HANDLE_IS_NULL (obj))
6504                 goto leave;
6505
6506         MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6507         
6508         if (mono_class_is_interface (klass)) {
6509                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6510                         MONO_HANDLE_ASSIGN (result, obj);
6511                         goto leave;
6512                 }
6513
6514                 /* casting an array one of the invariant interfaces that must act as such */
6515                 if (klass->is_array_special_interface) {
6516                         if (mono_class_is_assignable_from (klass, vt->klass)) {
6517                                 MONO_HANDLE_ASSIGN (result, obj);
6518                                 goto leave;
6519                         }
6520                 }
6521
6522                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6523                 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6524                         MONO_HANDLE_ASSIGN (result, obj);
6525                         goto leave;
6526                 }
6527         } else {
6528                 MonoClass *oklass = vt->klass;
6529                 if (mono_class_is_transparent_proxy (oklass)){
6530                         MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6531                         oklass = remote_class->proxy_class;
6532                 }
6533
6534                 mono_class_setup_supertypes (klass);    
6535                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6536                         MONO_HANDLE_ASSIGN (result, obj);
6537                         goto leave;
6538                 }
6539         }
6540 #ifndef DISABLE_REMOTING
6541         if (mono_class_is_transparent_proxy (vt->klass)) 
6542         {
6543                 MonoBoolean custom_type_info =  MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6544                 if (!custom_type_info)
6545                         goto leave;
6546                 MonoDomain *domain = mono_domain_get ();
6547                 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6548                 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6549                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6550                 MonoMethod *im = NULL;
6551                 gpointer pa [2];
6552
6553                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6554                 if (!im) {
6555                         mono_error_set_not_supported (error, "Linked away.");
6556                         goto leave;
6557                 }
6558                 im = mono_object_handle_get_virtual_method (rp, im, error);
6559                 if (!is_ok (error))
6560                         goto leave;
6561                 g_assert (im);
6562         
6563                 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6564                 if (!is_ok (error))
6565                         goto leave;
6566
6567                 pa [0] = MONO_HANDLE_RAW (reftype);
6568                 pa [1] = MONO_HANDLE_RAW (obj);
6569                 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6570                 if (!is_ok (error))
6571                         goto leave;
6572
6573                 if (*(MonoBoolean *) mono_object_unbox(res)) {
6574                         /* Update the vtable of the remote type, so it can safely cast to this new type */
6575                         mono_upgrade_remote_class (domain, obj, klass, error);
6576                         if (!is_ok (error))
6577                                 goto leave;
6578                         MONO_HANDLE_ASSIGN (result, obj);
6579                 }
6580         }
6581 #endif /* DISABLE_REMOTING */
6582 leave:
6583         return result;
6584 }
6585
6586 /**
6587  * mono_object_castclass_mbyref:
6588  * \param obj an object
6589  * \param klass a pointer to a class 
6590  * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6591  */
6592 MonoObject *
6593 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6594 {
6595         MONO_REQ_GC_UNSAFE_MODE;
6596         HANDLE_FUNCTION_ENTER ();
6597         MonoError error;
6598         MONO_HANDLE_DCL (MonoObject, obj);
6599         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6600         if (MONO_HANDLE_IS_NULL (obj))
6601                 goto leave;
6602         MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6603         mono_error_cleanup (&error);
6604 leave:
6605         HANDLE_FUNCTION_RETURN_OBJ (result);
6606 }
6607
6608 typedef struct {
6609         MonoDomain *orig_domain;
6610         MonoString *ins;
6611         MonoString *res;
6612 } LDStrInfo;
6613
6614 static void
6615 str_lookup (MonoDomain *domain, gpointer user_data)
6616 {
6617         MONO_REQ_GC_UNSAFE_MODE;
6618
6619         LDStrInfo *info = (LDStrInfo *)user_data;
6620         if (info->res || domain == info->orig_domain)
6621                 return;
6622         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6623 }
6624
6625 static MonoString*
6626 mono_string_get_pinned (MonoString *str, MonoError *error)
6627 {
6628         MONO_REQ_GC_UNSAFE_MODE;
6629
6630         error_init (error);
6631
6632         /* We only need to make a pinned version of a string if this is a moving GC */
6633         if (!mono_gc_is_moving ())
6634                 return str;
6635         int size;
6636         MonoString *news;
6637         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6638         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6639         if (news) {
6640                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6641                 news->length = mono_string_length (str);
6642         } else {
6643                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6644         }
6645         return news;
6646 }
6647
6648 static MonoString*
6649 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6650 {
6651         MONO_REQ_GC_UNSAFE_MODE;
6652
6653         MonoGHashTable *ldstr_table;
6654         MonoString *s, *res;
6655         MonoDomain *domain;
6656         
6657         error_init (error);
6658
6659         domain = ((MonoObject *)str)->vtable->domain;
6660         ldstr_table = domain->ldstr_table;
6661         ldstr_lock ();
6662         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6663         if (res) {
6664                 ldstr_unlock ();
6665                 return res;
6666         }
6667         if (insert) {
6668                 /* Allocate outside the lock */
6669                 ldstr_unlock ();
6670                 s = mono_string_get_pinned (str, error);
6671                 return_val_if_nok (error, NULL);
6672                 if (s) {
6673                         ldstr_lock ();
6674                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6675                         if (res) {
6676                                 ldstr_unlock ();
6677                                 return res;
6678                         }
6679                         mono_g_hash_table_insert (ldstr_table, s, s);
6680                         ldstr_unlock ();
6681                 }
6682                 return s;
6683         } else {
6684                 LDStrInfo ldstr_info;
6685                 ldstr_info.orig_domain = domain;
6686                 ldstr_info.ins = str;
6687                 ldstr_info.res = NULL;
6688
6689                 mono_domain_foreach (str_lookup, &ldstr_info);
6690                 if (ldstr_info.res) {
6691                         /* 
6692                          * the string was already interned in some other domain:
6693                          * intern it in the current one as well.
6694                          */
6695                         mono_g_hash_table_insert (ldstr_table, str, str);
6696                         ldstr_unlock ();
6697                         return str;
6698                 }
6699         }
6700         ldstr_unlock ();
6701         return NULL;
6702 }
6703
6704 /**
6705  * mono_string_is_interned:
6706  * \param o String to probe
6707  * \returns Whether the string has been interned.
6708  */
6709 MonoString*
6710 mono_string_is_interned (MonoString *o)
6711 {
6712         MonoError error;
6713         MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6714         /* This function does not fail. */
6715         mono_error_assert_ok (&error);
6716         return result;
6717 }
6718
6719 /**
6720  * mono_string_intern:
6721  * \param o String to intern
6722  * Interns the string passed.  
6723  * \returns The interned string.
6724  */
6725 MonoString*
6726 mono_string_intern (MonoString *str)
6727 {
6728         MonoError error;
6729         MonoString *result = mono_string_intern_checked (str, &error);
6730         mono_error_assert_ok (&error);
6731         return result;
6732 }
6733
6734 /**
6735  * mono_string_intern_checked:
6736  * \param o String to intern
6737  * \param error set on error.
6738  * Interns the string passed.
6739  * \returns The interned string.  On failure returns NULL and sets \p error
6740  */
6741 MonoString*
6742 mono_string_intern_checked (MonoString *str, MonoError *error)
6743 {
6744         MONO_REQ_GC_UNSAFE_MODE;
6745
6746         error_init (error);
6747
6748         return mono_string_is_interned_lookup (str, TRUE, error);
6749 }
6750
6751 /**
6752  * mono_ldstr:
6753  * \param domain the domain where the string will be used.
6754  * \param image a metadata context
6755  * \param idx index into the user string table.
6756  * Implementation for the \c ldstr opcode.
6757  * \returns a loaded string from the \p image / \p idx combination.
6758  */
6759 MonoString*
6760 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6761 {
6762         MonoError error;
6763         MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6764         mono_error_cleanup (&error);
6765         return result;
6766 }
6767
6768 /**
6769  * mono_ldstr_checked:
6770  * \param domain the domain where the string will be used.
6771  * \param image a metadata context
6772  * \param idx index into the user string table.
6773  * \param error set on error.
6774  * Implementation for the \c ldstr opcode.
6775  * \returns A loaded string from the \p image / \p idx combination.
6776  * On failure returns NULL and sets \p error.
6777  */
6778 MonoString*
6779 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6780 {
6781         MONO_REQ_GC_UNSAFE_MODE;
6782         error_init (error);
6783
6784         if (image->dynamic) {
6785                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6786                 return str;
6787         } else {
6788                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6789                         return NULL; /*FIXME we should probably be raising an exception here*/
6790                 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6791                 return str;
6792         }
6793 }
6794
6795 /**
6796  * mono_ldstr_metadata_sig
6797  * \param domain the domain for the string
6798  * \param sig the signature of a metadata string
6799  * \param error set on error
6800  * \returns a \c MonoString for a string stored in the metadata. On
6801  * failure returns NULL and sets \p error.
6802  */
6803 static MonoString*
6804 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6805 {
6806         MONO_REQ_GC_UNSAFE_MODE;
6807
6808         error_init (error);
6809         const char *str = sig;
6810         MonoString *o, *interned;
6811         size_t len2;
6812
6813         len2 = mono_metadata_decode_blob_size (str, &str);
6814         len2 >>= 1;
6815
6816         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6817         return_val_if_nok (error, NULL);
6818 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6819         {
6820                 int i;
6821                 guint16 *p2 = (guint16*)mono_string_chars (o);
6822                 for (i = 0; i < len2; ++i) {
6823                         *p2 = GUINT16_FROM_LE (*p2);
6824                         ++p2;
6825                 }
6826         }
6827 #endif
6828         ldstr_lock ();
6829         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6830         ldstr_unlock ();
6831         if (interned)
6832                 return interned; /* o will get garbage collected */
6833
6834         o = mono_string_get_pinned (o, error);
6835         if (o) {
6836                 ldstr_lock ();
6837                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6838                 if (!interned) {
6839                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6840                         interned = o;
6841                 }
6842                 ldstr_unlock ();
6843         }
6844
6845         return interned;
6846 }
6847
6848 /*
6849  * mono_ldstr_utf8:
6850  *
6851  *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
6852  * of an object.
6853  */
6854 char*
6855 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6856 {
6857         const char *str;
6858         size_t len2;
6859         long written = 0;
6860         char *as;
6861         GError *gerror = NULL;
6862
6863         error_init (error);
6864
6865         if (!mono_verifier_verify_string_signature (image, idx, NULL))
6866                 return NULL; /*FIXME we should probably be raising an exception here*/
6867         str = mono_metadata_user_string (image, idx);
6868
6869         len2 = mono_metadata_decode_blob_size (str, &str);
6870         len2 >>= 1;
6871
6872         as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6873         if (gerror) {
6874                 mono_error_set_argument (error, "string", "%s", gerror->message);
6875                 g_error_free (gerror);
6876                 return NULL;
6877         }
6878         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6879         if (len2 > written) {
6880                 /* allocate the total length and copy the part of the string that has been converted */
6881                 char *as2 = (char *)g_malloc0 (len2);
6882                 memcpy (as2, as, written);
6883                 g_free (as);
6884                 as = as2;
6885         }
6886
6887         return as;
6888 }
6889
6890 /**
6891  * mono_string_to_utf8:
6892  * \param s a \c System.String
6893  * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6894  * \returns the UTF-8 representation for \p s.
6895  * The resulting buffer needs to be freed with \c mono_free().
6896  */
6897 char *
6898 mono_string_to_utf8 (MonoString *s)
6899 {
6900         MONO_REQ_GC_UNSAFE_MODE;
6901
6902         MonoError error;
6903         char *result = mono_string_to_utf8_checked (s, &error);
6904         
6905         if (!is_ok (&error)) {
6906                 mono_error_cleanup (&error);
6907                 return NULL;
6908         }
6909         return result;
6910 }
6911
6912 /**
6913  * mono_string_to_utf8_checked:
6914  * \param s a \c System.String
6915  * \param error a \c MonoError.
6916  * Converts a \c MonoString to its UTF-8 representation. May fail; check 
6917  * \p error to determine whether the conversion was successful.
6918  * The resulting buffer should be freed with \c mono_free().
6919  */
6920 char *
6921 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6922 {
6923         MONO_REQ_GC_UNSAFE_MODE;
6924
6925         long written = 0;
6926         char *as;
6927         GError *gerror = NULL;
6928
6929         error_init (error);
6930
6931         if (s == NULL)
6932                 return NULL;
6933
6934         if (!s->length)
6935                 return g_strdup ("");
6936
6937         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6938         if (gerror) {
6939                 mono_error_set_argument (error, "string", "%s", gerror->message);
6940                 g_error_free (gerror);
6941                 return NULL;
6942         }
6943         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6944         if (s->length > written) {
6945                 /* allocate the total length and copy the part of the string that has been converted */
6946                 char *as2 = (char *)g_malloc0 (s->length);
6947                 memcpy (as2, as, written);
6948                 g_free (as);
6949                 as = as2;
6950         }
6951
6952         return as;
6953 }
6954
6955 char *
6956 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6957 {
6958         return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6959 }
6960
6961 /**
6962  * mono_string_to_utf8_ignore:
6963  * \param s a MonoString
6964  * Converts a \c MonoString to its UTF-8 representation. Will ignore
6965  * invalid surrogate pairs.
6966  * The resulting buffer should be freed with \c mono_free().
6967  */
6968 char *
6969 mono_string_to_utf8_ignore (MonoString *s)
6970 {
6971         MONO_REQ_GC_UNSAFE_MODE;
6972
6973         long written = 0;
6974         char *as;
6975
6976         if (s == NULL)
6977                 return NULL;
6978
6979         if (!s->length)
6980                 return g_strdup ("");
6981
6982         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6983
6984         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6985         if (s->length > written) {
6986                 /* allocate the total length and copy the part of the string that has been converted */
6987                 char *as2 = (char *)g_malloc0 (s->length);
6988                 memcpy (as2, as, written);
6989                 g_free (as);
6990                 as = as2;
6991         }
6992
6993         return as;
6994 }
6995
6996 /**
6997  * mono_string_to_utf8_image_ignore:
6998  * \param s a \c System.String
6999  * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7000  */
7001 char *
7002 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7003 {
7004         MONO_REQ_GC_UNSAFE_MODE;
7005
7006         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7007 }
7008
7009 /**
7010  * mono_string_to_utf8_mp_ignore:
7011  * \param s a \c System.String
7012  * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7013  */
7014 char *
7015 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7016 {
7017         MONO_REQ_GC_UNSAFE_MODE;
7018
7019         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7020 }
7021
7022
7023 /**
7024  * mono_string_to_utf16:
7025  * \param s a \c MonoString
7026  * \returns a null-terminated array of the UTF-16 chars
7027  * contained in \param s. The result must be freed with \c g_free().
7028  * This is a temporary helper until our string implementation
7029  * is reworked to always include the null-terminating char.
7030  */
7031 mono_unichar2*
7032 mono_string_to_utf16 (MonoString *s)
7033 {
7034         MONO_REQ_GC_UNSAFE_MODE;
7035
7036         char *as;
7037
7038         if (s == NULL)
7039                 return NULL;
7040
7041         as = (char *)g_malloc ((s->length * 2) + 2);
7042         as [(s->length * 2)] = '\0';
7043         as [(s->length * 2) + 1] = '\0';
7044
7045         if (!s->length) {
7046                 return (gunichar2 *)(as);
7047         }
7048         
7049         memcpy (as, mono_string_chars(s), s->length * 2);
7050         return (gunichar2 *)(as);
7051 }
7052
7053 /**
7054  * mono_string_to_utf32:
7055  * \param s a \c MonoString
7056  * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7057  * contained in \p s. The result must be freed with \c g_free().
7058  */
7059 mono_unichar4*
7060 mono_string_to_utf32 (MonoString *s)
7061 {
7062         MONO_REQ_GC_UNSAFE_MODE;
7063
7064         mono_unichar4 *utf32_output = NULL; 
7065         GError *error = NULL;
7066         glong items_written;
7067         
7068         if (s == NULL)
7069                 return NULL;
7070                 
7071         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7072         
7073         if (error)
7074                 g_error_free (error);
7075
7076         return utf32_output;
7077 }
7078
7079 /**
7080  * mono_string_from_utf16:
7081  * \param data the UTF-16 string (LPWSTR) to convert
7082  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7083  * \returns a \c MonoString.
7084  */
7085 MonoString *
7086 mono_string_from_utf16 (gunichar2 *data)
7087 {
7088         MonoError error;
7089         MonoString *result = mono_string_from_utf16_checked (data, &error);
7090         mono_error_cleanup (&error);
7091         return result;
7092 }
7093
7094 /**
7095  * mono_string_from_utf16_checked:
7096  * \param data the UTF-16 string (LPWSTR) to convert
7097  * \param error set on error
7098  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7099  * \returns a \c MonoString. On failure sets \p error and returns NULL.
7100  */
7101 MonoString *
7102 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7103 {
7104
7105         MONO_REQ_GC_UNSAFE_MODE;
7106
7107         error_init (error);
7108         MonoDomain *domain = mono_domain_get ();
7109         int len = 0;
7110
7111         if (!data)
7112                 return NULL;
7113
7114         while (data [len]) len++;
7115
7116         return mono_string_new_utf16_checked (domain, data, len, error);
7117 }
7118
7119 /**
7120  * mono_string_from_utf32:
7121  * \param data the UTF-32 string (LPWSTR) to convert
7122  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7123  * \returns a \c MonoString.
7124  */
7125 MonoString *
7126 mono_string_from_utf32 (mono_unichar4 *data)
7127 {
7128         MonoError error;
7129         MonoString *result = mono_string_from_utf32_checked (data, &error);
7130         mono_error_cleanup (&error);
7131         return result;
7132 }
7133
7134 /**
7135  * mono_string_from_utf32_checked:
7136  * \param data the UTF-32 string (LPWSTR) to convert
7137  * \param error set on error
7138  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7139  * \returns a \c MonoString. On failure returns NULL and sets \p error.
7140  */
7141 MonoString *
7142 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7143 {
7144         MONO_REQ_GC_UNSAFE_MODE;
7145
7146         error_init (error);
7147         MonoString* result = NULL;
7148         mono_unichar2 *utf16_output = NULL;
7149         GError *gerror = NULL;
7150         glong items_written;
7151         int len = 0;
7152
7153         if (!data)
7154                 return NULL;
7155
7156         while (data [len]) len++;
7157
7158         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7159
7160         if (gerror)
7161                 g_error_free (gerror);
7162
7163         result = mono_string_from_utf16_checked (utf16_output, error);
7164         g_free (utf16_output);
7165         return result;
7166 }
7167
7168 static char *
7169 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7170 {
7171         MONO_REQ_GC_UNSAFE_MODE;
7172
7173         char *r;
7174         char *mp_s;
7175         int len;
7176
7177         if (ignore_error) {
7178                 r = mono_string_to_utf8_ignore (s);
7179         } else {
7180                 r = mono_string_to_utf8_checked (s, error);
7181                 if (!mono_error_ok (error))
7182                         return NULL;
7183         }
7184
7185         if (!mp && !image)
7186                 return r;
7187
7188         len = strlen (r) + 1;
7189         if (mp)
7190                 mp_s = (char *)mono_mempool_alloc (mp, len);
7191         else
7192                 mp_s = (char *)mono_image_alloc (image, len);
7193
7194         memcpy (mp_s, r, len);
7195
7196         g_free (r);
7197
7198         return mp_s;
7199 }
7200
7201 /**
7202  * mono_string_to_utf8_image:
7203  * \param s a \c System.String
7204  * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7205  */
7206 char *
7207 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7208 {
7209         MONO_REQ_GC_UNSAFE_MODE;
7210
7211         return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7212 }
7213
7214 /**
7215  * mono_string_to_utf8_mp:
7216  * \param s a \c System.String
7217  * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7218  */
7219 char *
7220 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7221 {
7222         MONO_REQ_GC_UNSAFE_MODE;
7223
7224         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7225 }
7226
7227
7228 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7229
7230 void
7231 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7232 {
7233         eh_callbacks = *cbs;
7234 }
7235
7236 MonoRuntimeExceptionHandlingCallbacks *
7237 mono_get_eh_callbacks (void)
7238 {
7239         return &eh_callbacks;
7240 }
7241
7242 /**
7243  * mono_raise_exception:
7244  * \param ex exception object
7245  * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7246  */
7247 void
7248 mono_raise_exception (MonoException *ex) 
7249 {
7250         MONO_REQ_GC_UNSAFE_MODE;
7251
7252         /*
7253          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7254          * that will cause gcc to omit the function epilog, causing problems when
7255          * the JIT tries to walk the stack, since the return address on the stack
7256          * will point into the next function in the executable, not this one.
7257          */     
7258         eh_callbacks.mono_raise_exception (ex);
7259 }
7260
7261 void
7262 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
7263 {
7264         MONO_REQ_GC_UNSAFE_MODE;
7265
7266         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7267 }
7268
7269 /**
7270  * mono_wait_handle_new:
7271  * \param domain Domain where the object will be created
7272  * \param handle Handle for the wait handle
7273  * \param error set on error.
7274  * \returns A new \c MonoWaitHandle created in the given domain for the
7275  * given handle.  On failure returns NULL and sets \p error.
7276  */
7277 MonoWaitHandle *
7278 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7279 {
7280         MONO_REQ_GC_UNSAFE_MODE;
7281
7282         MonoWaitHandle *res;
7283         gpointer params [1];
7284         static MonoMethod *handle_set;
7285
7286         error_init (error);
7287         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7288         return_val_if_nok (error, NULL);
7289
7290         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
7291         if (!handle_set)
7292                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7293
7294         params [0] = &handle;
7295
7296         mono_runtime_invoke_checked (handle_set, res, params, error);
7297         return res;
7298 }
7299
7300 HANDLE
7301 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7302 {
7303         MONO_REQ_GC_UNSAFE_MODE;
7304
7305         static MonoClassField *f_safe_handle = NULL;
7306         MonoSafeHandle *sh;
7307
7308         if (!f_safe_handle) {
7309                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7310                 g_assert (f_safe_handle);
7311         }
7312
7313         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7314         return sh->handle;
7315 }
7316
7317
7318 static MonoObject*
7319 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7320 {
7321         MONO_REQ_GC_UNSAFE_MODE;
7322
7323         RuntimeInvokeFunction runtime_invoke;
7324
7325         error_init (error);
7326
7327         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7328                 MonoMethod *method = mono_get_context_capture_method ();
7329                 MonoMethod *wrapper;
7330                 if (!method)
7331                         return NULL;
7332                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7333                 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7334                 return_val_if_nok (error, NULL);
7335                 domain->capture_context_method = mono_compile_method_checked (method, error);
7336                 return_val_if_nok (error, NULL);
7337         }
7338
7339         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7340
7341         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7342 }
7343 /**
7344  * mono_async_result_new:
7345  * \param domain domain where the object will be created.
7346  * \param handle wait handle.
7347  * \param state state to pass to AsyncResult
7348  * \param data C closure data.
7349  * \param error set on error.
7350  * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7351  * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7352  * On failure returns NULL and sets \p error.
7353  */
7354 MonoAsyncResult *
7355 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7356 {
7357         MONO_REQ_GC_UNSAFE_MODE;
7358
7359         error_init (error);
7360         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7361         return_val_if_nok (error, NULL);
7362         MonoObject *context = mono_runtime_capture_context (domain, error);
7363         return_val_if_nok (error, NULL);
7364         /* we must capture the execution context from the original thread */
7365         if (context) {
7366                 MONO_OBJECT_SETREF (res, execution_context, context);
7367                 /* note: result may be null if the flow is suppressed */
7368         }
7369
7370         res->data = (void **)data;
7371         MONO_OBJECT_SETREF (res, object_data, object_data);
7372         MONO_OBJECT_SETREF (res, async_state, state);
7373         MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7374         return_val_if_nok (error, NULL);
7375         if (handle != NULL)
7376                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7377
7378         res->sync_completed = FALSE;
7379         res->completed = FALSE;
7380
7381         return res;
7382 }
7383
7384 MonoObject *
7385 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7386 {
7387         MONO_REQ_GC_UNSAFE_MODE;
7388
7389         MonoError error;
7390         MonoAsyncCall *ac;
7391         MonoObject *res;
7392
7393         g_assert (ares);
7394         g_assert (ares->async_delegate);
7395
7396         ac = (MonoAsyncCall*) ares->object_data;
7397         if (!ac) {
7398                 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7399                 if (mono_error_set_pending_exception (&error))
7400                         return NULL;
7401         } else {
7402                 gpointer wait_event = NULL;
7403
7404                 ac->msg->exc = NULL;
7405
7406                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7407
7408                 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7409                 mono_threads_begin_abort_protected_block ();
7410
7411                 if (!ac->msg->exc) {
7412                         MonoException *ex = mono_error_convert_to_exception (&error);
7413                         ac->msg->exc = (MonoObject *)ex;
7414                 } else {
7415                         mono_error_cleanup (&error);
7416                 }
7417
7418                 MONO_OBJECT_SETREF (ac, res, res);
7419
7420                 mono_monitor_enter ((MonoObject*) ares);
7421                 ares->completed = 1;
7422                 if (ares->handle)
7423                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7424                 mono_monitor_exit ((MonoObject*) ares);
7425
7426                 if (wait_event != NULL)
7427                         mono_w32event_set (wait_event);
7428
7429                 error_init (&error); //the else branch would leave it in an undefined state
7430                 if (ac->cb_method)
7431                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7432
7433                 mono_threads_end_abort_protected_block ();
7434
7435                 if (mono_error_set_pending_exception (&error))
7436                         return NULL;
7437         }
7438
7439         return res;
7440 }
7441
7442 gboolean
7443 mono_message_init (MonoDomain *domain,
7444                    MonoMethodMessage *this_obj, 
7445                    MonoReflectionMethod *method,
7446                    MonoArray *out_args,
7447                    MonoError *error)
7448 {
7449         MONO_REQ_GC_UNSAFE_MODE;
7450
7451         static MonoMethod *init_message_method = NULL;
7452
7453         if (!init_message_method) {
7454                 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7455                 g_assert (init_message_method != NULL);
7456         }
7457
7458         error_init (error);
7459         /* FIXME set domain instead? */
7460         g_assert (domain == mono_domain_get ());
7461         
7462         gpointer args[2];
7463
7464         args[0] = method;
7465         args[1] = out_args;
7466
7467         mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7468         return is_ok (error);
7469 }
7470
7471 #ifndef DISABLE_REMOTING
7472 /**
7473  * mono_remoting_invoke:
7474  * \param real_proxy pointer to a \c RealProxy object
7475  * \param msg The \c MonoMethodMessage to execute
7476  * \param exc used to store exceptions
7477  * \param out_args used to store output arguments
7478  * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7479  * \c IMessage interface and it is not trivial to extract results from there. So
7480  * we call an helper method \c PrivateInvoke instead of calling
7481  * \c RealProxy::Invoke() directly.
7482  * \returns the result object.
7483  */
7484 MonoObject *
7485 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7486 {
7487         MONO_REQ_GC_UNSAFE_MODE;
7488
7489         MonoObject *o;
7490         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7491         gpointer pa [4];
7492
7493         g_assert (exc);
7494
7495         error_init (error);
7496
7497         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7498
7499         if (!im) {
7500                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7501                 if (!im) {
7502                         mono_error_set_not_supported (error, "Linked away.");
7503                         return NULL;
7504                 }
7505                 real_proxy->vtable->domain->private_invoke_method = im;
7506         }
7507
7508         pa [0] = real_proxy;
7509         pa [1] = msg;
7510         pa [2] = exc;
7511         pa [3] = out_args;
7512
7513         o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7514         return_val_if_nok (error, NULL);
7515
7516         return o;
7517 }
7518 #endif
7519
7520 MonoObject *
7521 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
7522                      MonoObject **exc, MonoArray **out_args, MonoError *error) 
7523 {
7524         MONO_REQ_GC_UNSAFE_MODE;
7525
7526         static MonoClass *object_array_klass;
7527         error_init (error);
7528
7529         MonoDomain *domain; 
7530         MonoMethod *method;
7531         MonoMethodSignature *sig;
7532         MonoArray *arr;
7533         int i, j, outarg_count = 0;
7534
7535 #ifndef DISABLE_REMOTING
7536         if (target && mono_object_is_transparent_proxy (target)) {
7537                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7538                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7539                         target = tp->rp->unwrapped_server;
7540                 } else {
7541                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7542                 }
7543         }
7544 #endif
7545
7546         domain = mono_domain_get (); 
7547         method = msg->method->method;
7548         sig = mono_method_signature (method);
7549
7550         for (i = 0; i < sig->param_count; i++) {
7551                 if (sig->params [i]->byref) 
7552                         outarg_count++;
7553         }
7554
7555         if (!object_array_klass) {
7556                 MonoClass *klass;
7557
7558                 klass = mono_array_class_get (mono_defaults.object_class, 1);
7559                 g_assert (klass);
7560
7561                 mono_memory_barrier ();
7562                 object_array_klass = klass;
7563         }
7564
7565         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7566         return_val_if_nok (error, NULL);
7567
7568         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7569         *exc = NULL;
7570
7571         MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7572         return_val_if_nok (error, NULL);
7573
7574         for (i = 0, j = 0; i < sig->param_count; i++) {
7575                 if (sig->params [i]->byref) {
7576                         MonoObject* arg;
7577                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7578                         mono_array_setref (*out_args, j, arg);
7579                         j++;
7580                 }
7581         }
7582
7583         return ret;
7584 }
7585
7586 /**
7587  * prepare_to_string_method:
7588  * @obj: The object
7589  * @target: Set to @obj or unboxed value if a valuetype
7590  *
7591  * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7592  */
7593 static MonoMethod *
7594 prepare_to_string_method (MonoObject *obj, void **target)
7595 {
7596         MONO_REQ_GC_UNSAFE_MODE;
7597
7598         static MonoMethod *to_string = NULL;
7599         MonoMethod *method;
7600         g_assert (target);
7601         g_assert (obj);
7602
7603         *target = obj;
7604
7605         if (!to_string)
7606                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7607
7608         method = mono_object_get_virtual_method (obj, to_string);
7609
7610         // Unbox value type if needed
7611         if (mono_class_is_valuetype (mono_method_get_class (method))) {
7612                 *target = mono_object_unbox (obj);
7613         }
7614         return method;
7615 }
7616
7617 /**
7618  * mono_object_to_string:
7619  * \param obj The object
7620  * \param exc Any exception thrown by \c ToString(). May be NULL.
7621  * \returns the result of calling \c ToString() on an object.
7622  */
7623 MonoString *
7624 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7625 {
7626         MonoError error;
7627         MonoString *s = NULL;
7628         void *target;
7629         MonoMethod *method = prepare_to_string_method (obj, &target);
7630         if (exc) {
7631                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7632                 if (*exc == NULL && !mono_error_ok (&error))
7633                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7634                 else
7635                         mono_error_cleanup (&error);
7636         } else {
7637                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7638                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7639         }
7640
7641         return s;
7642 }
7643
7644 /**
7645  * mono_object_to_string_checked:
7646  * \param obj The object
7647  * \param error Set on error.
7648  * \returns the result of calling \c ToString() on an object. If the
7649  * method cannot be invoked or if it raises an exception, sets \p error
7650  * and returns NULL.
7651  */
7652 MonoString *
7653 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7654 {
7655         error_init (error);
7656         void *target;
7657         MonoMethod *method = prepare_to_string_method (obj, &target);
7658         return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7659 }
7660
7661 /**
7662  * mono_object_try_to_string:
7663  * \param obj The object
7664  * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7665  * \param error Set if method cannot be invoked.
7666  * \returns the result of calling \c ToString() on an object. If the
7667  * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7668  * and returns NULL.
7669  */
7670 MonoString *
7671 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7672 {
7673         g_assert (exc);
7674         error_init (error);
7675         void *target;
7676         MonoMethod *method = prepare_to_string_method (obj, &target);
7677         return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7678 }
7679
7680
7681
7682 static char *
7683 get_native_backtrace (MonoException *exc_raw)
7684 {
7685         HANDLE_FUNCTION_ENTER ();
7686         MONO_HANDLE_DCL(MonoException, exc);
7687         char * trace = mono_exception_handle_get_native_backtrace (exc);
7688         HANDLE_FUNCTION_RETURN_VAL (trace);
7689 }
7690
7691 /**
7692  * mono_print_unhandled_exception:
7693  * \param exc The exception
7694  * Prints the unhandled exception.
7695  */
7696 void
7697 mono_print_unhandled_exception (MonoObject *exc)
7698 {
7699         MONO_REQ_GC_UNSAFE_MODE;
7700
7701         MonoString * str;
7702         char *message = (char*)"";
7703         gboolean free_message = FALSE;
7704         MonoError error;
7705
7706         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7707                 message = g_strdup ("OutOfMemoryException");
7708                 free_message = TRUE;
7709         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7710                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7711                 free_message = TRUE;
7712         } else {
7713                 
7714                 if (((MonoException*)exc)->native_trace_ips) {
7715                         message = get_native_backtrace ((MonoException*)exc);
7716                         free_message = TRUE;
7717                 } else {
7718                         MonoObject *other_exc = NULL;
7719                         str = mono_object_try_to_string (exc, &other_exc, &error);
7720                         if (other_exc == NULL && !is_ok (&error))
7721                                 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7722                         else
7723                                 mono_error_cleanup (&error);
7724                         if (other_exc) {
7725                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7726                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7727                                 
7728                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7729                                         original_backtrace, nested_backtrace);
7730
7731                                 g_free (original_backtrace);
7732                                 g_free (nested_backtrace);
7733                                 free_message = TRUE;
7734                         } else if (str) {
7735                                 message = mono_string_to_utf8_checked (str, &error);
7736                                 if (!mono_error_ok (&error)) {
7737                                         mono_error_cleanup (&error);
7738                                         message = (char *) "";
7739                                 } else {
7740                                         free_message = TRUE;
7741                                 }
7742                         }
7743                 }
7744         }
7745
7746         /*
7747          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7748          *         exc->vtable->klass->name, message);
7749          */
7750         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7751         
7752         if (free_message)
7753                 g_free (message);
7754 }
7755
7756 /**
7757  * mono_delegate_ctor_with_method:
7758  * \param this pointer to an uninitialized delegate object
7759  * \param target target object
7760  * \param addr pointer to native code
7761  * \param method method
7762  * \param error set on error.
7763  * Initialize a delegate and sets a specific method, not the one
7764  * associated with \p addr.  This is useful when sharing generic code.
7765  * In that case \p addr will most probably not be associated with the
7766  * correct instantiation of the method.
7767  * On failure returns FALSE and sets \p error.
7768  */
7769 gboolean
7770 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7771 {
7772         MONO_REQ_GC_UNSAFE_MODE;
7773
7774         error_init (error);
7775         MonoDelegate *delegate = (MonoDelegate *)this_obj;
7776
7777         g_assert (this_obj);
7778         g_assert (addr);
7779
7780         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7781
7782         if (method)
7783                 delegate->method = method;
7784
7785         mono_stats.delegate_creations++;
7786
7787 #ifndef DISABLE_REMOTING
7788         if (target && mono_object_is_transparent_proxy (target)) {
7789                 g_assert (method);
7790                 method = mono_marshal_get_remoting_invoke (method);
7791 #ifdef ENABLE_INTERPRETER
7792                 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7793 #endif
7794                 delegate->method_ptr = mono_compile_method_checked (method, error);
7795                 return_val_if_nok (error, FALSE);
7796                 MONO_OBJECT_SETREF (delegate, target, target);
7797         } else
7798 #endif
7799         {
7800                 delegate->method_ptr = addr;
7801                 MONO_OBJECT_SETREF (delegate, target, target);
7802         }
7803
7804         delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7805         if (callbacks.init_delegate)
7806                 callbacks.init_delegate (delegate);
7807         return TRUE;
7808 }
7809
7810 /**
7811  * mono_delegate_ctor:
7812  * \param this pointer to an uninitialized delegate object
7813  * \param target target object
7814  * \param addr pointer to native code
7815  * \param error set on error.
7816  * This is used to initialize a delegate.
7817  * On failure returns FALSE and sets \p error.
7818  */
7819 gboolean
7820 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7821 {
7822         MONO_REQ_GC_UNSAFE_MODE;
7823
7824         error_init (error);
7825         MonoDomain *domain = mono_domain_get ();
7826         MonoJitInfo *ji;
7827         MonoMethod *method = NULL;
7828
7829         g_assert (addr);
7830
7831         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7832         /* Shared code */
7833         if (!ji && domain != mono_get_root_domain ())
7834                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7835         if (ji) {
7836                 method = mono_jit_info_get_method (ji);
7837                 g_assert (!mono_class_is_gtd (method->klass));
7838         }
7839
7840         return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7841 }
7842
7843 /**
7844  * mono_method_call_message_new:
7845  * \param method method to encapsulate
7846  * \param params parameters to the method
7847  * \param invoke optional, delegate invoke.
7848  * \param cb async callback delegate.
7849  * \param state state passed to the async callback.
7850  * \param error set on error.
7851   * Translates arguments pointers into a \c MonoMethodMessage.
7852  * On failure returns NULL and sets \p error.
7853  */
7854 MonoMethodMessage *
7855 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7856                               MonoDelegate **cb, MonoObject **state, MonoError *error)
7857 {
7858         MONO_REQ_GC_UNSAFE_MODE;
7859
7860         error_init (error);
7861
7862         MonoDomain *domain = mono_domain_get ();
7863         MonoMethodSignature *sig = mono_method_signature (method);
7864         MonoMethodMessage *msg;
7865         int i, count;
7866
7867         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error); 
7868         return_val_if_nok  (error, NULL);
7869
7870         if (invoke) {
7871                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7872                 return_val_if_nok (error, NULL);
7873                 mono_message_init (domain, msg, rm, NULL, error);
7874                 return_val_if_nok (error, NULL);
7875                 count =  sig->param_count - 2;
7876         } else {
7877                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7878                 return_val_if_nok (error, NULL);
7879                 mono_message_init (domain, msg, rm, NULL, error);
7880                 return_val_if_nok (error, NULL);
7881                 count =  sig->param_count;
7882         }
7883
7884         for (i = 0; i < count; i++) {
7885                 gpointer vpos;
7886                 MonoClass *klass;
7887                 MonoObject *arg;
7888
7889                 if (sig->params [i]->byref)
7890                         vpos = *((gpointer *)params [i]);
7891                 else 
7892                         vpos = params [i];
7893
7894                 klass = mono_class_from_mono_type (sig->params [i]);
7895
7896                 if (klass->valuetype) {
7897                         arg = mono_value_box_checked (domain, klass, vpos, error);
7898                         return_val_if_nok (error, NULL);
7899                 } else 
7900                         arg = *((MonoObject **)vpos);
7901                       
7902                 mono_array_setref (msg->args, i, arg);
7903         }
7904
7905         if (cb != NULL && state != NULL) {
7906                 *cb = *((MonoDelegate **)params [i]);
7907                 i++;
7908                 *state = *((MonoObject **)params [i]);
7909         }
7910
7911         return msg;
7912 }
7913
7914 /**
7915  * mono_method_return_message_restore:
7916  *
7917  * Restore results from message based processing back to arguments pointers
7918  */
7919 void
7920 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7921 {
7922         MONO_REQ_GC_UNSAFE_MODE;
7923
7924         error_init (error);
7925
7926         MonoMethodSignature *sig = mono_method_signature (method);
7927         int i, j, type, size, out_len;
7928         
7929         if (out_args == NULL)
7930                 return;
7931         out_len = mono_array_length (out_args);
7932         if (out_len == 0)
7933                 return;
7934
7935         for (i = 0, j = 0; i < sig->param_count; i++) {
7936                 MonoType *pt = sig->params [i];
7937
7938                 if (pt->byref) {
7939                         char *arg;
7940                         if (j >= out_len) {
7941                                 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7942                                 return;
7943                         }
7944
7945                         arg = (char *)mono_array_get (out_args, gpointer, j);
7946                         type = pt->type;
7947
7948                         g_assert (type != MONO_TYPE_VOID);
7949
7950                         if (MONO_TYPE_IS_REFERENCE (pt)) {
7951                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7952                         } else {
7953                                 if (arg) {
7954                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7955                                         size = mono_class_value_size (klass, NULL);
7956                                         if (klass->has_references)
7957                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7958                                         else
7959                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7960                                 } else {
7961                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7962                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7963                                 }
7964                         }
7965
7966                         j++;
7967                 }
7968         }
7969 }
7970
7971 #ifndef DISABLE_REMOTING
7972
7973 /**
7974  * mono_load_remote_field:
7975  * \param this pointer to an object
7976  * \param klass klass of the object containing \p field
7977  * \param field the field to load
7978  * \param res a storage to store the result
7979  * This method is called by the runtime on attempts to load fields of
7980  * transparent proxy objects. \p this points to such TP, \p klass is the class of
7981  * the object containing \p field. \p res is a storage location which can be
7982  * used to store the result.
7983  * \returns an address pointing to the value of field.
7984  */
7985 gpointer
7986 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7987 {
7988         MonoError error;
7989         gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7990         mono_error_cleanup (&error);
7991         return result;
7992 }
7993
7994 /**
7995  * mono_load_remote_field_checked:
7996  * \param this pointer to an object
7997  * \param klass klass of the object containing \p field
7998  * \param field the field to load
7999  * \param res a storage to store the result
8000  * \param error set on error
8001  * This method is called by the runtime on attempts to load fields of
8002  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8003  * the object containing \p field. \p res is a storage location which can be
8004  * used to store the result.
8005  * \returns an address pointing to the value of field.  On failure returns NULL and sets \p error.
8006  */
8007 gpointer
8008 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8009 {
8010         MONO_REQ_GC_UNSAFE_MODE;
8011
8012         static MonoMethod *getter = NULL;
8013
8014         error_init (error);
8015
8016         MonoDomain *domain = mono_domain_get ();
8017         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8018         MonoClass *field_class;
8019         MonoMethodMessage *msg;
8020         MonoArray *out_args;
8021         MonoObject *exc;
8022         char* full_name;
8023
8024         g_assert (mono_object_is_transparent_proxy (this_obj));
8025         g_assert (res != NULL);
8026
8027         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8028                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8029                 return res;
8030         }
8031         
8032         if (!getter) {
8033                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8034                 if (!getter) {
8035                         mono_error_set_not_supported (error, "Linked away.");
8036                         return NULL;
8037                 }
8038         }
8039         
8040         field_class = mono_class_from_mono_type (field->type);
8041
8042         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8043         return_val_if_nok (error, NULL);
8044         out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8045         return_val_if_nok (error, NULL);
8046         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8047         return_val_if_nok (error, NULL);
8048         mono_message_init (domain, msg, rm, out_args, error);
8049         return_val_if_nok (error, NULL);
8050
8051         full_name = mono_type_get_full_name (klass);
8052         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8053         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8054         g_free (full_name);
8055
8056         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8057         return_val_if_nok (error, NULL);
8058
8059         if (exc) {
8060                 mono_error_set_exception_instance (error, (MonoException *)exc);
8061                 return NULL;
8062         }
8063
8064         if (mono_array_length (out_args) == 0)
8065                 return NULL;
8066
8067         mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8068
8069         if (field_class->valuetype) {
8070                 return ((char *)*res) + sizeof (MonoObject);
8071         } else
8072                 return res;
8073 }
8074
8075 /**
8076  * mono_load_remote_field_new:
8077  * \param this
8078  * \param klass
8079  * \param field
8080  * Missing documentation.
8081  */
8082 MonoObject *
8083 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8084 {
8085         MonoError error;
8086
8087         MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8088         mono_error_cleanup (&error);
8089         return result;
8090 }
8091
8092 /**
8093  * mono_load_remote_field_new_checked:
8094  * \param this pointer to an object
8095  * \param klass klass of the object containing \p field
8096  * \param field the field to load
8097  * \param error set on error.
8098  * This method is called by the runtime on attempts to load fields of
8099  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8100  * the object containing \p field.
8101  * \returns a freshly allocated object containing the value of the field.  On failure returns NULL and sets \p error.
8102  */
8103 MonoObject *
8104 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8105 {
8106         MONO_REQ_GC_UNSAFE_MODE;
8107
8108         error_init (error);
8109
8110         static MonoMethod *tp_load = NULL;
8111
8112         g_assert (mono_object_is_transparent_proxy (this_obj));
8113
8114         if (!tp_load) {
8115                 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8116                 if (!tp_load) {
8117                         mono_error_set_not_supported (error, "Linked away.");
8118                         return NULL;
8119                 }
8120         }
8121         
8122         /* MonoType *type = mono_class_get_type (klass); */
8123
8124         gpointer args[2];
8125         args [0] = &klass;
8126         args [1] = &field;
8127
8128         return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8129 }
8130
8131 /**
8132  * mono_store_remote_field:
8133  * \param this_obj pointer to an object
8134  * \param klass klass of the object containing \p field
8135  * \param field the field to load
8136  * \param val the value/object to store
8137  * This method is called by the runtime on attempts to store fields of
8138  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8139  * the object containing \p field. \p val is the new value to store in \p field.
8140  */
8141 void
8142 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8143 {
8144         MonoError error;
8145         (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8146         mono_error_cleanup (&error);
8147 }
8148
8149 /**
8150  * mono_store_remote_field_checked:
8151  * \param this_obj pointer to an object
8152  * \param klass klass of the object containing \p field
8153  * \param field the field to load
8154  * \param val the value/object to store
8155  * \param error set on error
8156  * This method is called by the runtime on attempts to store fields of
8157  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8158  * the object containing \p field. \p val is the new value to store in \p field.
8159  * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8160  */
8161 gboolean
8162 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8163 {
8164         
8165         MONO_REQ_GC_UNSAFE_MODE;
8166
8167         error_init (error);
8168
8169         MonoDomain *domain = mono_domain_get ();
8170         MonoClass *field_class;
8171         MonoObject *arg;
8172
8173         g_assert (mono_object_is_transparent_proxy (this_obj));
8174
8175         field_class = mono_class_from_mono_type (field->type);
8176
8177         if (field_class->valuetype) {
8178                 arg = mono_value_box_checked (domain, field_class, val, error);
8179                 return_val_if_nok (error, FALSE);
8180         } else {
8181                 arg = *((MonoObject**)val);
8182         }
8183
8184         return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8185 }
8186
8187 /**
8188  * mono_store_remote_field_new:
8189  * \param this_obj
8190  * \param klass
8191  * \param field
8192  * \param arg
8193  * Missing documentation
8194  */
8195 void
8196 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8197 {
8198         MonoError error;
8199         (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8200         mono_error_cleanup (&error);
8201 }
8202
8203 /**
8204  * mono_store_remote_field_new_checked:
8205  * \param this_obj
8206  * \param klass
8207  * \param field
8208  * \param arg
8209  * \param error
8210  * Missing documentation
8211  */
8212 gboolean
8213 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8214 {
8215         MONO_REQ_GC_UNSAFE_MODE;
8216
8217         static MonoMethod *tp_store = NULL;
8218
8219         error_init (error);
8220
8221         g_assert (mono_object_is_transparent_proxy (this_obj));
8222
8223         if (!tp_store) {
8224                 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8225                 if (!tp_store) {
8226                         mono_error_set_not_supported (error, "Linked away.");
8227                         return FALSE;
8228                 }
8229         }
8230
8231         gpointer args[3];
8232         args [0] = &klass;
8233         args [1] = &field;
8234         args [2] = arg;
8235
8236         mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8237         return is_ok (error);
8238 }
8239 #endif
8240
8241 /**
8242  * mono_create_ftnptr:
8243  *
8244  * Given a function address, create a function descriptor for it.
8245  * This is only needed on some platforms.
8246  */
8247 gpointer
8248 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8249 {
8250         return callbacks.create_ftnptr (domain, addr);
8251 }
8252
8253 /*
8254  * mono_get_addr_from_ftnptr:
8255  *
8256  *   Given a pointer to a function descriptor, return the function address.
8257  * This is only needed on some platforms.
8258  */
8259 gpointer
8260 mono_get_addr_from_ftnptr (gpointer descr)
8261 {
8262         return callbacks.get_addr_from_ftnptr (descr);
8263 }       
8264
8265 /**
8266  * mono_string_chars:
8267  * \param s a \c MonoString
8268  * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8269  */
8270 gunichar2 *
8271 mono_string_chars (MonoString *s)
8272 {
8273         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8274
8275         return s->chars;
8276 }
8277
8278 /**
8279  * mono_string_length:
8280  * \param s MonoString
8281  * \returns the length in characters of the string
8282  */
8283 int
8284 mono_string_length (MonoString *s)
8285 {
8286         MONO_REQ_GC_UNSAFE_MODE;
8287
8288         return s->length;
8289 }
8290
8291 /**
8292  * mono_string_handle_length:
8293  * \param s \c MonoString
8294  * \returns the length in characters of the string
8295  */
8296 int
8297 mono_string_handle_length (MonoStringHandle s)
8298 {
8299         MONO_REQ_GC_UNSAFE_MODE;
8300
8301         return MONO_HANDLE_GETVAL (s, length);
8302 }
8303
8304
8305 /**
8306  * mono_array_length:
8307  * \param array a \c MonoArray*
8308  * \returns the total number of elements in the array. This works for
8309  * both vectors and multidimensional arrays.
8310  */
8311 uintptr_t
8312 mono_array_length (MonoArray *array)
8313 {
8314         MONO_REQ_GC_UNSAFE_MODE;
8315
8316         return array->max_length;
8317 }
8318
8319 /**
8320  * mono_array_addr_with_size:
8321  * \param array a \c MonoArray*
8322  * \param size size of the array elements
8323  * \param idx index into the array
8324  * Use this function to obtain the address for the \p idx item on the
8325  * \p array containing elements of size \p size.
8326  *
8327  * This method performs no bounds checking or type checking.
8328  * \returns the address of the \p idx element in the array.
8329  */
8330 char*
8331 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8332 {
8333         MONO_REQ_GC_UNSAFE_MODE;
8334
8335         return ((char*)(array)->vector) + size * idx;
8336 }
8337
8338
8339 MonoArray *
8340 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error) 
8341 {
8342         MonoDomain *domain = mono_domain_get ();
8343         MonoArray *res;
8344         int len, i;
8345
8346         error_init (error);
8347         if (!list)
8348                 return NULL;
8349
8350         len = g_list_length (list);
8351         res = mono_array_new_checked (domain, eclass, len, error);
8352         return_val_if_nok (error, NULL);
8353
8354         for (i = 0; list; list = list->next, i++)
8355                 mono_array_set (res, gpointer, i, list->data);
8356
8357         return res;
8358 }
8359
8360 #if NEVER_DEFINED
8361 /*
8362  * The following section is purely to declare prototypes and
8363  * document the API, as these C files are processed by our
8364  * tool
8365  */
8366
8367 /**
8368  * mono_array_set:
8369  * \param array array to alter
8370  * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8371  * \param index index into the array
8372  * \param value value to set
8373  * Value Type version: This sets the \p index's element of the \p array
8374  * with elements of size sizeof(type) to the provided \p value.
8375  *
8376  * This macro does not attempt to perform type checking or bounds checking.
8377  *
8378  * Use this to set value types in a \c MonoArray.
8379  */
8380 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8381 {
8382 }
8383
8384 /**
8385  * mono_array_setref:
8386  * \param array array to alter
8387  * \param index index into the array
8388  * \param value value to set
8389  * Reference Type version: This sets the \p index's element of the
8390  * \p array with elements of size sizeof(type) to the provided \p value.
8391  *
8392  * This macro does not attempt to perform type checking or bounds checking.
8393  *
8394  * Use this to reference types in a \c MonoArray.
8395  */
8396 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8397 {
8398 }
8399
8400 /**
8401  * mono_array_get:
8402  * \param array array on which to operate on
8403  * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8404  * \param index index into the array
8405  *
8406  * Use this macro to retrieve the \p index element of an \p array and
8407  * extract the value assuming that the elements of the array match
8408  * the provided type value.
8409  *
8410  * This method can be used with both arrays holding value types and
8411  * reference types.   For reference types, the \p type parameter should
8412  * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8413  *
8414  * This macro does not attempt to perform type checking or bounds checking.
8415  *
8416  * \returns The element at the \p index position in the \p array.
8417  */
8418 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8419 {
8420 }
8421 #endif
8422