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