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