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