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