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