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