Merge pull request #4224 from akoeplinger/fix-46602
[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 #ifndef DISABLE_REMOTING
2735         if (klass == mono_defaults.transparent_proxy_class) {
2736                 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2737                 klass = remote_class->proxy_class;
2738                 is_proxy = TRUE;
2739         }
2740 #endif
2741         return class_get_virtual_method (klass, method, is_proxy, error);
2742 }
2743
2744 static MonoMethod*
2745 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2746 {
2747         mono_error_init (error);
2748
2749
2750         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2751                         return method;
2752
2753         mono_class_setup_vtable (klass);
2754         MonoMethod **vtable = klass->vtable;
2755
2756         if (method->slot == -1) {
2757                 /* method->slot might not be set for instances of generic methods */
2758                 if (method->is_inflated) {
2759                         g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2760                         method->slot = ((MonoMethodInflated*)method)->declaring->slot; 
2761                 } else {
2762                         if (!is_proxy)
2763                                 g_assert_not_reached ();
2764                 }
2765         }
2766
2767         MonoMethod *res = NULL;
2768         /* check method->slot is a valid index: perform isinstance? */
2769         if (method->slot != -1) {
2770                 if (mono_class_is_interface (method->klass)) {
2771                         if (!is_proxy) {
2772                                 gboolean variance_used = FALSE;
2773                                 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2774                                 g_assert (iface_offset > 0);
2775                                 res = vtable [iface_offset + method->slot];
2776                         }
2777                 } else {
2778                         res = vtable [method->slot];
2779                 }
2780     }
2781
2782 #ifndef DISABLE_REMOTING
2783         if (is_proxy) {
2784                 /* It may be an interface, abstract class method or generic method */
2785                 if (!res || mono_method_signature (res)->generic_param_count)
2786                         res = method;
2787
2788                 /* generic methods demand invoke_with_check */
2789                 if (mono_method_signature (res)->generic_param_count)
2790                         res = mono_marshal_get_remoting_invoke_with_check (res);
2791                 else {
2792 #ifndef DISABLE_COM
2793                         if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2794                                 res = mono_cominterop_get_invoke (res);
2795                         else
2796 #endif
2797                                 res = mono_marshal_get_remoting_invoke (res);
2798                 }
2799         } else
2800 #endif
2801         {
2802                 if (method->is_inflated) {
2803                         /* Have to inflate the result */
2804                         res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2805                 }
2806         }
2807
2808         return res;
2809 }
2810
2811 static MonoObject*
2812 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2813 {
2814         MONO_REQ_GC_UNSAFE_MODE;
2815
2816         MonoObject *result = NULL;
2817
2818         g_assert (callbacks.runtime_invoke);
2819
2820         mono_error_init (error);
2821         
2822         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2823                 mono_profiler_method_start_invoke (method);
2824
2825         result = callbacks.runtime_invoke (method, obj, params, exc, error);
2826
2827         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2828                 mono_profiler_method_end_invoke (method);
2829
2830         if (!mono_error_ok (error))
2831                 return NULL;
2832
2833         return result;
2834 }
2835
2836 /**
2837  * mono_runtime_invoke:
2838  * @method: method to invoke
2839  * @obJ: object instance
2840  * @params: arguments to the method
2841  * @exc: exception information.
2842  *
2843  * Invokes the method represented by @method on the object @obj.
2844  *
2845  * obj is the 'this' pointer, it should be NULL for static
2846  * methods, a MonoObject* for object instances and a pointer to
2847  * the value type for value types.
2848  *
2849  * The params array contains the arguments to the method with the
2850  * same convention: MonoObject* pointers for object instances and
2851  * pointers to the value type otherwise. 
2852  * 
2853  * From unmanaged code you'll usually use the
2854  * mono_runtime_invoke() variant.
2855  *
2856  * Note that this function doesn't handle virtual methods for
2857  * you, it will exec the exact method you pass: we still need to
2858  * expose a function to lookup the derived class implementation
2859  * of a virtual method (there are examples of this in the code,
2860  * though).
2861  * 
2862  * You can pass NULL as the exc argument if you don't want to
2863  * catch exceptions, otherwise, *exc will be set to the exception
2864  * thrown, if any.  if an exception is thrown, you can't use the
2865  * MonoObject* result from the function.
2866  * 
2867  * If the method returns a value type, it is boxed in an object
2868  * reference.
2869  */
2870 MonoObject*
2871 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2872 {
2873         MonoError error;
2874         MonoObject *res;
2875         if (exc) {
2876                 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2877                 if (*exc == NULL && !mono_error_ok(&error)) {
2878                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2879                 } else
2880                         mono_error_cleanup (&error);
2881         } else {
2882                 res = mono_runtime_invoke_checked (method, obj, params, &error);
2883                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2884         }
2885         return res;
2886 }
2887
2888 /**
2889  * mono_runtime_try_invoke:
2890  * @method: method to invoke
2891  * @obJ: object instance
2892  * @params: arguments to the method
2893  * @exc: exception information.
2894  * @error: set on error
2895  *
2896  * Invokes the method represented by @method on the object @obj.
2897  *
2898  * obj is the 'this' pointer, it should be NULL for static
2899  * methods, a MonoObject* for object instances and a pointer to
2900  * the value type for value types.
2901  *
2902  * The params array contains the arguments to the method with the
2903  * same convention: MonoObject* pointers for object instances and
2904  * pointers to the value type otherwise. 
2905  * 
2906  * From unmanaged code you'll usually use the
2907  * mono_runtime_invoke() variant.
2908  *
2909  * Note that this function doesn't handle virtual methods for
2910  * you, it will exec the exact method you pass: we still need to
2911  * expose a function to lookup the derived class implementation
2912  * of a virtual method (there are examples of this in the code,
2913  * though).
2914  * 
2915  * For this function, you must not pass NULL as the exc argument if
2916  * you don't want to catch exceptions, use
2917  * mono_runtime_invoke_checked().  If an exception is thrown, you
2918  * can't use the MonoObject* result from the function.
2919  * 
2920  * If this method cannot be invoked, @error will be set and @exc and
2921  * the return value must not be used.
2922  *
2923  * If the method returns a value type, it is boxed in an object
2924  * reference.
2925  */
2926 MonoObject*
2927 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2928 {
2929         MONO_REQ_GC_UNSAFE_MODE;
2930
2931         g_assert (exc != NULL);
2932
2933         if (mono_runtime_get_no_exec ())
2934                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2935
2936         return do_runtime_invoke (method, obj, params, exc, error);
2937 }
2938
2939 /**
2940  * mono_runtime_invoke_checked:
2941  * @method: method to invoke
2942  * @obJ: object instance
2943  * @params: arguments to the method
2944  * @error: set on error
2945  *
2946  * Invokes the method represented by @method on the object @obj.
2947  *
2948  * obj is the 'this' pointer, it should be NULL for static
2949  * methods, a MonoObject* for object instances and a pointer to
2950  * the value type for value types.
2951  *
2952  * The params array contains the arguments to the method with the
2953  * same convention: MonoObject* pointers for object instances and
2954  * pointers to the value type otherwise. 
2955  * 
2956  * From unmanaged code you'll usually use the
2957  * mono_runtime_invoke() variant.
2958  *
2959  * Note that this function doesn't handle virtual methods for
2960  * you, it will exec the exact method you pass: we still need to
2961  * expose a function to lookup the derived class implementation
2962  * of a virtual method (there are examples of this in the code,
2963  * though).
2964  * 
2965  * If an exception is thrown, you can't use the MonoObject* result
2966  * from the function.
2967  * 
2968  * If this method cannot be invoked, @error will be set.  If the
2969  * method throws an exception (and we're in coop mode) the exception
2970  * will be set in @error.
2971  *
2972  * If the method returns a value type, it is boxed in an object
2973  * reference.
2974  */
2975 MonoObject*
2976 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2977 {
2978         MONO_REQ_GC_UNSAFE_MODE;
2979
2980         if (mono_runtime_get_no_exec ())
2981                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2982
2983         return do_runtime_invoke (method, obj, params, NULL, error);
2984 }
2985
2986 /**
2987  * mono_method_get_unmanaged_thunk:
2988  * @method: method to generate a thunk for.
2989  *
2990  * Returns an unmanaged->managed thunk that can be used to call
2991  * a managed method directly from C.
2992  *
2993  * The thunk's C signature closely matches the managed signature:
2994  *
2995  * C#: public bool Equals (object obj);
2996  * C:  typedef MonoBoolean (*Equals)(MonoObject*,
2997  *             MonoObject*, MonoException**);
2998  *
2999  * The 1st ("this") parameter must not be used with static methods:
3000  *
3001  * C#: public static bool ReferenceEquals (object a, object b);
3002  * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3003  *             MonoException**);
3004  *
3005  * The last argument must be a non-null pointer of a MonoException* pointer.
3006  * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3007  * exception has been thrown in managed code. Otherwise it will point
3008  * to the MonoException* caught by the thunk. In this case, the result of
3009  * the thunk is undefined:
3010  *
3011  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3012  * MonoException *ex = NULL;
3013  * Equals func = mono_method_get_unmanaged_thunk (method);
3014  * MonoBoolean res = func (thisObj, objToCompare, &ex);
3015  * if (ex) {
3016  *    // handle exception
3017  * }
3018  *
3019  * The calling convention of the thunk matches the platform's default
3020  * convention. This means that under Windows, C declarations must
3021  * contain the __stdcall attribute:
3022  *
3023  * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3024  *             MonoObject*, MonoException**);
3025  *
3026  * LIMITATIONS
3027  *
3028  * Value type arguments and return values are treated as they were objects:
3029  *
3030  * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3031  * C:  typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3032  *
3033  * Arguments must be properly boxed upon trunk's invocation, while return
3034  * values must be unboxed.
3035  */
3036 gpointer
3037 mono_method_get_unmanaged_thunk (MonoMethod *method)
3038 {
3039         MONO_REQ_GC_NEUTRAL_MODE;
3040         MONO_REQ_API_ENTRYPOINT;
3041
3042         MonoError error;
3043         gpointer res;
3044
3045         g_assert (!mono_threads_is_coop_enabled ());
3046
3047         MONO_ENTER_GC_UNSAFE;
3048         method = mono_marshal_get_thunk_invoke_wrapper (method);
3049         res = mono_compile_method_checked (method, &error);
3050         mono_error_cleanup (&error);
3051         MONO_EXIT_GC_UNSAFE;
3052
3053         return res;
3054 }
3055
3056 void
3057 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3058 {
3059         MONO_REQ_GC_UNSAFE_MODE;
3060
3061         int t;
3062         if (type->byref) {
3063                 /* object fields cannot be byref, so we don't need a
3064                    wbarrier here */
3065                 gpointer *p = (gpointer*)dest;
3066                 *p = value;
3067                 return;
3068         }
3069         t = type->type;
3070 handle_enum:
3071         switch (t) {
3072         case MONO_TYPE_BOOLEAN:
3073         case MONO_TYPE_I1:
3074         case MONO_TYPE_U1: {
3075                 guint8 *p = (guint8*)dest;
3076                 *p = value ? *(guint8*)value : 0;
3077                 return;
3078         }
3079         case MONO_TYPE_I2:
3080         case MONO_TYPE_U2:
3081         case MONO_TYPE_CHAR: {
3082                 guint16 *p = (guint16*)dest;
3083                 *p = value ? *(guint16*)value : 0;
3084                 return;
3085         }
3086 #if SIZEOF_VOID_P == 4
3087         case MONO_TYPE_I:
3088         case MONO_TYPE_U:
3089 #endif
3090         case MONO_TYPE_I4:
3091         case MONO_TYPE_U4: {
3092                 gint32 *p = (gint32*)dest;
3093                 *p = value ? *(gint32*)value : 0;
3094                 return;
3095         }
3096 #if SIZEOF_VOID_P == 8
3097         case MONO_TYPE_I:
3098         case MONO_TYPE_U:
3099 #endif
3100         case MONO_TYPE_I8:
3101         case MONO_TYPE_U8: {
3102                 gint64 *p = (gint64*)dest;
3103                 *p = value ? *(gint64*)value : 0;
3104                 return;
3105         }
3106         case MONO_TYPE_R4: {
3107                 float *p = (float*)dest;
3108                 *p = value ? *(float*)value : 0;
3109                 return;
3110         }
3111         case MONO_TYPE_R8: {
3112                 double *p = (double*)dest;
3113                 *p = value ? *(double*)value : 0;
3114                 return;
3115         }
3116         case MONO_TYPE_STRING:
3117         case MONO_TYPE_SZARRAY:
3118         case MONO_TYPE_CLASS:
3119         case MONO_TYPE_OBJECT:
3120         case MONO_TYPE_ARRAY:
3121                 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3122                 return;
3123         case MONO_TYPE_FNPTR:
3124         case MONO_TYPE_PTR: {
3125                 gpointer *p = (gpointer*)dest;
3126                 *p = deref_pointer? *(gpointer*)value: value;
3127                 return;
3128         }
3129         case MONO_TYPE_VALUETYPE:
3130                 /* note that 't' and 'type->type' can be different */
3131                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3132                         t = mono_class_enum_basetype (type->data.klass)->type;
3133                         goto handle_enum;
3134                 } else {
3135                         MonoClass *klass = mono_class_from_mono_type (type);
3136                         int size = mono_class_value_size (klass, NULL);
3137                         if (value == NULL)
3138                                 mono_gc_bzero_atomic (dest, size);
3139                         else
3140                                 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3141                 }
3142                 return;
3143         case MONO_TYPE_GENERICINST:
3144                 t = type->data.generic_class->container_class->byval_arg.type;
3145                 goto handle_enum;
3146         default:
3147                 g_error ("got type %x", type->type);
3148         }
3149 }
3150
3151 /**
3152  * mono_field_set_value:
3153  * @obj: Instance object
3154  * @field: MonoClassField describing the field to set
3155  * @value: The value to be set
3156  *
3157  * Sets the value of the field described by @field in the object instance @obj
3158  * to the value passed in @value.   This method should only be used for instance
3159  * fields.   For static fields, use mono_field_static_set_value.
3160  *
3161  * The value must be on the native format of the field type. 
3162  */
3163 void
3164 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3165 {
3166         MONO_REQ_GC_UNSAFE_MODE;
3167
3168         void *dest;
3169
3170         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3171
3172         dest = (char*)obj + field->offset;
3173         mono_copy_value (field->type, dest, value, FALSE);
3174 }
3175
3176 /**
3177  * mono_field_static_set_value:
3178  * @field: MonoClassField describing the field to set
3179  * @value: The value to be set
3180  *
3181  * Sets the value of the static field described by @field
3182  * to the value passed in @value.
3183  *
3184  * The value must be on the native format of the field type. 
3185  */
3186 void
3187 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3188 {
3189         MONO_REQ_GC_UNSAFE_MODE;
3190
3191         void *dest;
3192
3193         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3194         /* you cant set a constant! */
3195         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3196
3197         if (field->offset == -1) {
3198                 /* Special static */
3199                 gpointer addr;
3200
3201                 mono_domain_lock (vt->domain);
3202                 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3203                 mono_domain_unlock (vt->domain);
3204                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3205         } else {
3206                 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3207         }
3208         mono_copy_value (field->type, dest, value, FALSE);
3209 }
3210
3211 /**
3212  * mono_vtable_get_static_field_data:
3213  *
3214  * Internal use function: return a pointer to the memory holding the static fields
3215  * for a class or NULL if there are no static fields.
3216  * This is exported only for use by the debugger.
3217  */
3218 void *
3219 mono_vtable_get_static_field_data (MonoVTable *vt)
3220 {
3221         MONO_REQ_GC_NEUTRAL_MODE
3222
3223         if (!vt->has_static_fields)
3224                 return NULL;
3225         return vt->vtable [vt->klass->vtable_size];
3226 }
3227
3228 static guint8*
3229 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3230 {
3231         MONO_REQ_GC_UNSAFE_MODE;
3232
3233         guint8 *src;
3234
3235         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3236                 if (field->offset == -1) {
3237                         /* Special static */
3238                         gpointer addr;
3239
3240                         mono_domain_lock (vt->domain);
3241                         addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3242                         mono_domain_unlock (vt->domain);
3243                         src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3244                 } else {
3245                         src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3246                 }
3247         } else {
3248                 src = (guint8*)obj + field->offset;
3249         }
3250
3251         return src;
3252 }
3253
3254 /**
3255  * mono_field_get_value:
3256  * @obj: Object instance
3257  * @field: MonoClassField describing the field to fetch information from
3258  * @value: pointer to the location where the value will be stored
3259  *
3260  * Use this routine to get the value of the field @field in the object
3261  * passed.
3262  *
3263  * The pointer provided by value must be of the field type, for reference
3264  * types this is a MonoObject*, for value types its the actual pointer to
3265  * the value type.
3266  *
3267  * For example:
3268  *     int i;
3269  *     mono_field_get_value (obj, int_field, &i);
3270  */
3271 void
3272 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3273 {
3274         MONO_REQ_GC_UNSAFE_MODE;
3275
3276         void *src;
3277
3278         g_assert (obj);
3279
3280         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3281
3282         src = (char*)obj + field->offset;
3283         mono_copy_value (field->type, value, src, TRUE);
3284 }
3285
3286 /**
3287  * mono_field_get_value_object:
3288  * @domain: domain where the object will be created (if boxing)
3289  * @field: MonoClassField describing the field to fetch information from
3290  * @obj: The object instance for the field.
3291  *
3292  * Returns: a new MonoObject with the value from the given field.  If the
3293  * field represents a value type, the value is boxed.
3294  *
3295  */
3296 MonoObject *
3297 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3298 {       
3299         MonoError error;
3300         MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3301         mono_error_assert_ok (&error);
3302         return result;
3303 }
3304
3305 /**
3306  * mono_field_get_value_object_checked:
3307  * @domain: domain where the object will be created (if boxing)
3308  * @field: MonoClassField describing the field to fetch information from
3309  * @obj: The object instance for the field.
3310  * @error: Set on error.
3311  *
3312  * Returns: a new MonoObject with the value from the given field.  If the
3313  * field represents a value type, the value is boxed.  On error returns NULL and sets @error.
3314  *
3315  */
3316 MonoObject *
3317 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3318 {
3319         MONO_REQ_GC_UNSAFE_MODE;
3320
3321         mono_error_init (error);
3322
3323         MonoObject *o;
3324         MonoClass *klass;
3325         MonoVTable *vtable = NULL;
3326         gchar *v;
3327         gboolean is_static = FALSE;
3328         gboolean is_ref = FALSE;
3329         gboolean is_literal = FALSE;
3330         gboolean is_ptr = FALSE;
3331         MonoType *type = mono_field_get_type_checked (field, error);
3332
3333         return_val_if_nok (error, NULL);
3334
3335         switch (type->type) {
3336         case MONO_TYPE_STRING:
3337         case MONO_TYPE_OBJECT:
3338         case MONO_TYPE_CLASS:
3339         case MONO_TYPE_ARRAY:
3340         case MONO_TYPE_SZARRAY:
3341                 is_ref = TRUE;
3342                 break;
3343         case MONO_TYPE_U1:
3344         case MONO_TYPE_I1:
3345         case MONO_TYPE_BOOLEAN:
3346         case MONO_TYPE_U2:
3347         case MONO_TYPE_I2:
3348         case MONO_TYPE_CHAR:
3349         case MONO_TYPE_U:
3350         case MONO_TYPE_I:
3351         case MONO_TYPE_U4:
3352         case MONO_TYPE_I4:
3353         case MONO_TYPE_R4:
3354         case MONO_TYPE_U8:
3355         case MONO_TYPE_I8:
3356         case MONO_TYPE_R8:
3357         case MONO_TYPE_VALUETYPE:
3358                 is_ref = type->byref;
3359                 break;
3360         case MONO_TYPE_GENERICINST:
3361                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3362                 break;
3363         case MONO_TYPE_PTR:
3364                 is_ptr = TRUE;
3365                 break;
3366         default:
3367                 g_error ("type 0x%x not handled in "
3368                          "mono_field_get_value_object", type->type);
3369                 return NULL;
3370         }
3371
3372         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3373                 is_literal = TRUE;
3374
3375         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3376                 is_static = TRUE;
3377
3378                 if (!is_literal) {
3379                         vtable = mono_class_vtable_full (domain, field->parent, error);
3380                         return_val_if_nok (error, NULL);
3381
3382                         if (!vtable->initialized) {
3383                                 mono_runtime_class_init_full (vtable, error);
3384                                 return_val_if_nok (error, NULL);
3385                         }
3386                 }
3387         } else {
3388                 g_assert (obj);
3389         }
3390         
3391         if (is_ref) {
3392                 if (is_literal) {
3393                         get_default_field_value (domain, field, &o, error);
3394                         return_val_if_nok (error, NULL);
3395                 } else if (is_static) {
3396                         mono_field_static_get_value_checked (vtable, field, &o, error);
3397                         return_val_if_nok (error, NULL);
3398                 } else {
3399                         mono_field_get_value (obj, field, &o);
3400                 }
3401                 return o;
3402         }
3403
3404         if (is_ptr) {
3405                 static MonoMethod *m;
3406                 gpointer args [2];
3407                 gpointer *ptr;
3408                 gpointer v;
3409
3410                 if (!m) {
3411                         MonoClass *ptr_klass = mono_class_get_pointer_class ();
3412                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3413                         g_assert (m);
3414                 }
3415
3416                 v = &ptr;
3417                 if (is_literal) {
3418                         get_default_field_value (domain, field, v, error);
3419                         return_val_if_nok (error, NULL);
3420                 } else if (is_static) {
3421                         mono_field_static_get_value_checked (vtable, field, v, error);
3422                         return_val_if_nok (error, NULL);
3423                 } else {
3424                         mono_field_get_value (obj, field, v);
3425                 }
3426
3427                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3428                 args [0] = ptr ? *ptr : NULL;
3429                 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3430                 return_val_if_nok (error, NULL);
3431
3432                 o = mono_runtime_invoke_checked (m, NULL, args, error);
3433                 return_val_if_nok (error, NULL);
3434
3435                 return o;
3436         }
3437
3438         /* boxed value type */
3439         klass = mono_class_from_mono_type (type);
3440
3441         if (mono_class_is_nullable (klass))
3442                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3443
3444         o = mono_object_new_checked (domain, klass, error);
3445         return_val_if_nok (error, NULL);
3446         v = ((gchar *) o) + sizeof (MonoObject);
3447
3448         if (is_literal) {
3449                 get_default_field_value (domain, field, v, error);
3450                 return_val_if_nok (error, NULL);
3451         } else if (is_static) {
3452                 mono_field_static_get_value_checked (vtable, field, v, error);
3453                 return_val_if_nok (error, NULL);
3454         } else {
3455                 mono_field_get_value (obj, field, v);
3456         }
3457
3458         return o;
3459 }
3460
3461 int
3462 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3463 {
3464         MONO_REQ_GC_UNSAFE_MODE;
3465
3466         mono_error_init (error);
3467         int retval = 0;
3468         const char *p = blob;
3469         mono_metadata_decode_blob_size (p, &p);
3470
3471         switch (type) {
3472         case MONO_TYPE_BOOLEAN:
3473         case MONO_TYPE_U1:
3474         case MONO_TYPE_I1:
3475                 *(guint8 *) value = *p;
3476                 break;
3477         case MONO_TYPE_CHAR:
3478         case MONO_TYPE_U2:
3479         case MONO_TYPE_I2:
3480                 *(guint16*) value = read16 (p);
3481                 break;
3482         case MONO_TYPE_U4:
3483         case MONO_TYPE_I4:
3484                 *(guint32*) value = read32 (p);
3485                 break;
3486         case MONO_TYPE_U8:
3487         case MONO_TYPE_I8:
3488                 *(guint64*) value = read64 (p);
3489                 break;
3490         case MONO_TYPE_R4:
3491                 readr4 (p, (float*) value);
3492                 break;
3493         case MONO_TYPE_R8:
3494                 readr8 (p, (double*) value);
3495                 break;
3496         case MONO_TYPE_STRING:
3497                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3498                 break;
3499         case MONO_TYPE_CLASS:
3500                 *(gpointer*) value = NULL;
3501                 break;
3502         default:
3503                 retval = -1;
3504                 g_warning ("type 0x%02x should not be in constant table", type);
3505         }
3506         return retval;
3507 }
3508
3509 static void
3510 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3511 {
3512         MONO_REQ_GC_NEUTRAL_MODE;
3513
3514         MonoTypeEnum def_type;
3515         const char* data;
3516
3517         mono_error_init (error);
3518         
3519         data = mono_class_get_field_default_value (field, &def_type);
3520         mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3521 }
3522
3523 void
3524 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3525 {
3526         MONO_REQ_GC_UNSAFE_MODE;
3527
3528         void *src;
3529
3530         mono_error_init (error);
3531
3532         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3533         
3534         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3535                 get_default_field_value (vt->domain, field, value, error);
3536                 return;
3537         }
3538
3539         if (field->offset == -1) {
3540                 /* Special static */
3541                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3542                 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3543         } else {
3544                 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3545         }
3546         mono_copy_value (field->type, value, src, TRUE);
3547 }
3548
3549 /**
3550  * mono_field_static_get_value:
3551  * @vt: vtable to the object
3552  * @field: MonoClassField describing the field to fetch information from
3553  * @value: where the value is returned
3554  *
3555  * Use this routine to get the value of the static field @field value.
3556  *
3557  * The pointer provided by value must be of the field type, for reference
3558  * types this is a MonoObject*, for value types its the actual pointer to
3559  * the value type.
3560  *
3561  * For example:
3562  *     int i;
3563  *     mono_field_static_get_value (vt, int_field, &i);
3564  */
3565 void
3566 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3567 {
3568         MONO_REQ_GC_NEUTRAL_MODE;
3569
3570         MonoError error;
3571         mono_field_static_get_value_checked (vt, field, value, &error);
3572         mono_error_cleanup (&error);
3573 }
3574
3575 /**
3576  * mono_field_static_get_value_checked:
3577  * @vt: vtable to the object
3578  * @field: MonoClassField describing the field to fetch information from
3579  * @value: where the value is returned
3580  * @error: set on error
3581  *
3582  * Use this routine to get the value of the static field @field value.
3583  *
3584  * The pointer provided by value must be of the field type, for reference
3585  * types this is a MonoObject*, for value types its the actual pointer to
3586  * the value type.
3587  *
3588  * For example:
3589  *     int i;
3590  *     mono_field_static_get_value_checked (vt, int_field, &i, error);
3591  *     if (!is_ok (error)) { ... }
3592  *
3593  * On failure sets @error.
3594  */
3595 void
3596 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3597 {
3598         MONO_REQ_GC_NEUTRAL_MODE;
3599
3600         mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3601 }
3602
3603 /**
3604  * mono_property_set_value:
3605  * @prop: MonoProperty to set
3606  * @obj: instance object on which to act
3607  * @params: parameters to pass to the propery
3608  * @exc: optional exception
3609  *
3610  * Invokes the property's set method with the given arguments on the
3611  * object instance obj (or NULL for static properties). 
3612  * 
3613  * You can pass NULL as the exc argument if you don't want to
3614  * catch exceptions, otherwise, *exc will be set to the exception
3615  * thrown, if any.  if an exception is thrown, you can't use the
3616  * MonoObject* result from the function.
3617  */
3618 void
3619 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3620 {
3621         MONO_REQ_GC_UNSAFE_MODE;
3622
3623         MonoError error;
3624         do_runtime_invoke (prop->set, obj, params, exc, &error);
3625         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3626                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3627         } else {
3628                 mono_error_cleanup (&error);
3629         }
3630 }
3631
3632 /**
3633  * mono_property_set_value_checked:
3634  * @prop: MonoProperty to set
3635  * @obj: instance object on which to act
3636  * @params: parameters to pass to the propery
3637  * @error: set on error
3638  *
3639  * Invokes the property's set method with the given arguments on the
3640  * object instance obj (or NULL for static properties). 
3641  * 
3642  * Returns: TRUE on success.  On failure returns FALSE and sets @error.
3643  * If an exception is thrown, it will be caught and returned via @error.
3644  */
3645 gboolean
3646 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3647 {
3648         MONO_REQ_GC_UNSAFE_MODE;
3649
3650         MonoObject *exc;
3651
3652         mono_error_init (error);
3653         do_runtime_invoke (prop->set, obj, params, &exc, error);
3654         if (exc != NULL && is_ok (error))
3655                 mono_error_set_exception_instance (error, (MonoException*)exc);
3656         return is_ok (error);
3657 }
3658
3659 /**
3660  * mono_property_get_value:
3661  * @prop: MonoProperty to fetch
3662  * @obj: instance object on which to act
3663  * @params: parameters to pass to the propery
3664  * @exc: optional exception
3665  *
3666  * Invokes the property's get method with the given arguments on the
3667  * object instance obj (or NULL for static properties). 
3668  * 
3669  * You can pass NULL as the exc argument if you don't want to
3670  * catch exceptions, otherwise, *exc will be set to the exception
3671  * thrown, if any.  if an exception is thrown, you can't use the
3672  * MonoObject* result from the function.
3673  *
3674  * Returns: the value from invoking the get method on the property.
3675  */
3676 MonoObject*
3677 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3678 {
3679         MONO_REQ_GC_UNSAFE_MODE;
3680
3681         MonoError error;
3682         MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3683         if (exc && *exc == NULL && !mono_error_ok (&error)) {
3684                 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3685         } else {
3686                 mono_error_cleanup (&error); /* FIXME don't raise here */
3687         }
3688
3689         return val;
3690 }
3691
3692 /**
3693  * mono_property_get_value_checked:
3694  * @prop: MonoProperty to fetch
3695  * @obj: instance object on which to act
3696  * @params: parameters to pass to the propery
3697  * @error: set on error
3698  *
3699  * Invokes the property's get method with the given arguments on the
3700  * object instance obj (or NULL for static properties). 
3701  * 
3702  * If an exception is thrown, you can't use the
3703  * MonoObject* result from the function.  The exception will be propagated via @error.
3704  *
3705  * Returns: the value from invoking the get method on the property. On
3706  * failure returns NULL and sets @error.
3707  */
3708 MonoObject*
3709 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3710 {
3711         MONO_REQ_GC_UNSAFE_MODE;
3712
3713         MonoObject *exc;
3714         MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3715         if (exc != NULL && !is_ok (error))
3716                 mono_error_set_exception_instance (error, (MonoException*) exc);
3717         if (!is_ok (error))
3718                 val = NULL;
3719         return val;
3720 }
3721
3722
3723 /*
3724  * mono_nullable_init:
3725  * @buf: The nullable structure to initialize.
3726  * @value: the value to initialize from
3727  * @klass: the type for the object
3728  *
3729  * Initialize the nullable structure pointed to by @buf from @value which
3730  * should be a boxed value type.   The size of @buf should be able to hold
3731  * as much data as the @klass->instance_size (which is the number of bytes
3732  * that will be copies).
3733  *
3734  * Since Nullables have variable structure, we can not define a C
3735  * structure for them.
3736  */
3737 void
3738 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3739 {
3740         MONO_REQ_GC_UNSAFE_MODE;
3741
3742         MonoClass *param_class = klass->cast_class;
3743
3744         mono_class_setup_fields (klass);
3745         g_assert (klass->fields_inited);
3746                                 
3747         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3748         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3749
3750         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3751         if (value) {
3752                 if (param_class->has_references)
3753                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3754                 else
3755                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3756         } else {
3757                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3758         }
3759 }
3760
3761 /**
3762  * mono_nullable_box:
3763  * @buf: The buffer representing the data to be boxed
3764  * @klass: the type to box it as.
3765  * @error: set on oerr
3766  *
3767  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3768  * @buf.  On failure returns NULL and sets @error
3769  */
3770 MonoObject*
3771 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3772 {
3773         MONO_REQ_GC_UNSAFE_MODE;
3774
3775         mono_error_init (error);
3776         MonoClass *param_class = klass->cast_class;
3777
3778         mono_class_setup_fields (klass);
3779         g_assert (klass->fields_inited);
3780
3781         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3782         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3783
3784         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3785                 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3786                 return_val_if_nok (error, NULL);
3787                 if (param_class->has_references)
3788                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3789                 else
3790                         mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3791                 return o;
3792         }
3793         else
3794                 return NULL;
3795 }
3796
3797 /**
3798  * mono_get_delegate_invoke:
3799  * @klass: The delegate class
3800  *
3801  * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3802  */
3803 MonoMethod *
3804 mono_get_delegate_invoke (MonoClass *klass)
3805 {
3806         MONO_REQ_GC_NEUTRAL_MODE;
3807
3808         MonoMethod *im;
3809
3810         /* This is called at runtime, so avoid the slower search in metadata */
3811         mono_class_setup_methods (klass);
3812         if (mono_class_has_failure (klass))
3813                 return NULL;
3814         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3815         return im;
3816 }
3817
3818 /**
3819  * mono_get_delegate_begin_invoke:
3820  * @klass: The delegate class
3821  *
3822  * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3823  */
3824 MonoMethod *
3825 mono_get_delegate_begin_invoke (MonoClass *klass)
3826 {
3827         MONO_REQ_GC_NEUTRAL_MODE;
3828
3829         MonoMethod *im;
3830
3831         /* This is called at runtime, so avoid the slower search in metadata */
3832         mono_class_setup_methods (klass);
3833         if (mono_class_has_failure (klass))
3834                 return NULL;
3835         im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3836         return im;
3837 }
3838
3839 /**
3840  * mono_get_delegate_end_invoke:
3841  * @klass: The delegate class
3842  *
3843  * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3844  */
3845 MonoMethod *
3846 mono_get_delegate_end_invoke (MonoClass *klass)
3847 {
3848         MONO_REQ_GC_NEUTRAL_MODE;
3849
3850         MonoMethod *im;
3851
3852         /* This is called at runtime, so avoid the slower search in metadata */
3853         mono_class_setup_methods (klass);
3854         if (mono_class_has_failure (klass))
3855                 return NULL;
3856         im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3857         return im;
3858 }
3859
3860 /**
3861  * mono_runtime_delegate_invoke:
3862  * @delegate: pointer to a delegate object.
3863  * @params: parameters for the delegate.
3864  * @exc: Pointer to the exception result.
3865  *
3866  * Invokes the delegate method @delegate with the parameters provided.
3867  *
3868  * You can pass NULL as the exc argument if you don't want to
3869  * catch exceptions, otherwise, *exc will be set to the exception
3870  * thrown, if any.  if an exception is thrown, you can't use the
3871  * MonoObject* result from the function.
3872  */
3873 MonoObject*
3874 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3875 {
3876         MONO_REQ_GC_UNSAFE_MODE;
3877
3878         MonoError error;
3879         if (exc) {
3880                 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3881                 if (*exc) {
3882                         mono_error_cleanup (&error);
3883                         return NULL;
3884                 } else {
3885                         if (!is_ok (&error))
3886                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3887                         return result;
3888                 }
3889         } else {
3890                 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3891                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3892                 return result;
3893         }
3894 }
3895
3896 /**
3897  * mono_runtime_delegate_try_invoke:
3898  * @delegate: pointer to a delegate object.
3899  * @params: parameters for the delegate.
3900  * @exc: Pointer to the exception result.
3901  * @error: set on error
3902  *
3903  * Invokes the delegate method @delegate with the parameters provided.
3904  *
3905  * You can pass NULL as the exc argument if you don't want to
3906  * catch exceptions, otherwise, *exc will be set to the exception
3907  * thrown, if any.  On failure to execute, @error will be set.
3908  * if an exception is thrown, you can't use the
3909  * MonoObject* result from the function.
3910  */
3911 MonoObject*
3912 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3913 {
3914         MONO_REQ_GC_UNSAFE_MODE;
3915
3916         mono_error_init (error);
3917         MonoMethod *im;
3918         MonoClass *klass = delegate->vtable->klass;
3919         MonoObject *o;
3920
3921         im = mono_get_delegate_invoke (klass);
3922         if (!im)
3923                 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3924
3925         if (exc) {
3926                 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3927         } else {
3928                 o = mono_runtime_invoke_checked (im, delegate, params, error);
3929         }
3930
3931         return o;
3932 }
3933
3934 /**
3935  * mono_runtime_delegate_invoke_checked:
3936  * @delegate: pointer to a delegate object.
3937  * @params: parameters for the delegate.
3938  * @error: set on error
3939  *
3940  * Invokes the delegate method @delegate with the parameters provided.
3941  *
3942  * On failure @error will be set and you can't use the MonoObject*
3943  * result from the function.
3944  */
3945 MonoObject*
3946 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3947 {
3948         mono_error_init (error);
3949         return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3950 }
3951
3952 static char **main_args = NULL;
3953 static int num_main_args = 0;
3954
3955 /**
3956  * mono_runtime_get_main_args:
3957  *
3958  * Returns: a MonoArray with the arguments passed to the main program
3959  */
3960 MonoArray*
3961 mono_runtime_get_main_args (void)
3962 {
3963         MONO_REQ_GC_UNSAFE_MODE;
3964         MonoError error;
3965         MonoArray *result = mono_runtime_get_main_args_checked (&error);
3966         mono_error_assert_ok (&error);
3967         return result;
3968 }
3969
3970 /**
3971  * mono_runtime_get_main_args:
3972  * @error: set on error
3973  *
3974  * Returns: a MonoArray with the arguments passed to the main
3975  * program. On failure returns NULL and sets @error.
3976  */
3977 MonoArray*
3978 mono_runtime_get_main_args_checked (MonoError *error)
3979 {
3980         MonoArray *res;
3981         int i;
3982         MonoDomain *domain = mono_domain_get ();
3983
3984         mono_error_init (error);
3985
3986         res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3987         return_val_if_nok (error, NULL);
3988
3989         for (i = 0; i < num_main_args; ++i)
3990                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3991
3992         return res;
3993 }
3994
3995 static void
3996 free_main_args (void)
3997 {
3998         MONO_REQ_GC_NEUTRAL_MODE;
3999
4000         int i;
4001
4002         for (i = 0; i < num_main_args; ++i)
4003                 g_free (main_args [i]);
4004         g_free (main_args);
4005         num_main_args = 0;
4006         main_args = NULL;
4007 }
4008
4009 /**
4010  * mono_runtime_set_main_args:
4011  * @argc: number of arguments from the command line
4012  * @argv: array of strings from the command line
4013  *
4014  * Set the command line arguments from an embedding application that doesn't otherwise call
4015  * mono_runtime_run_main ().
4016  */
4017 int
4018 mono_runtime_set_main_args (int argc, char* argv[])
4019 {
4020         MONO_REQ_GC_NEUTRAL_MODE;
4021
4022         int i;
4023
4024         free_main_args ();
4025         main_args = g_new0 (char*, argc);
4026         num_main_args = argc;
4027
4028         for (i = 0; i < argc; ++i) {
4029                 gchar *utf8_arg;
4030
4031                 utf8_arg = mono_utf8_from_external (argv[i]);
4032                 if (utf8_arg == NULL) {
4033                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4034                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4035                         exit (-1);
4036                 }
4037
4038                 main_args [i] = utf8_arg;
4039         }
4040
4041         return 0;
4042 }
4043
4044 /*
4045  * Prepare an array of arguments in order to execute a standard Main()
4046  * method (argc/argv contains the executable name). This method also
4047  * sets the command line argument value needed by System.Environment.
4048  * 
4049  */
4050 static MonoArray*
4051 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4052 {
4053         MONO_REQ_GC_UNSAFE_MODE;
4054
4055         MonoError error;
4056         int i;
4057         MonoArray *args = NULL;
4058         MonoDomain *domain = mono_domain_get ();
4059         gchar *utf8_fullpath;
4060         MonoMethodSignature *sig;
4061
4062         g_assert (method != NULL);
4063         
4064         mono_thread_set_main (mono_thread_current ());
4065
4066         main_args = g_new0 (char*, argc);
4067         num_main_args = argc;
4068
4069         if (!g_path_is_absolute (argv [0])) {
4070                 gchar *basename = g_path_get_basename (argv [0]);
4071                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4072                                                     basename,
4073                                                     NULL);
4074
4075                 utf8_fullpath = mono_utf8_from_external (fullpath);
4076                 if(utf8_fullpath == NULL) {
4077                         /* Printing the arg text will cause glib to
4078                          * whinge about "Invalid UTF-8", but at least
4079                          * its relevant, and shows the problem text
4080                          * string.
4081                          */
4082                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4083                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4084                         exit (-1);
4085                 }
4086
4087                 g_free (fullpath);
4088                 g_free (basename);
4089         } else {
4090                 utf8_fullpath = mono_utf8_from_external (argv[0]);
4091                 if(utf8_fullpath == NULL) {
4092                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4093                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4094                         exit (-1);
4095                 }
4096         }
4097
4098         main_args [0] = utf8_fullpath;
4099
4100         for (i = 1; i < argc; ++i) {
4101                 gchar *utf8_arg;
4102
4103                 utf8_arg=mono_utf8_from_external (argv[i]);
4104                 if(utf8_arg==NULL) {
4105                         /* Ditto the comment about Invalid UTF-8 here */
4106                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4107                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4108                         exit (-1);
4109                 }
4110
4111                 main_args [i] = utf8_arg;
4112         }
4113         argc--;
4114         argv++;
4115
4116         sig = mono_method_signature (method);
4117         if (!sig) {
4118                 g_print ("Unable to load Main method.\n");
4119                 exit (-1);
4120         }
4121
4122         if (sig->param_count) {
4123                 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4124                 mono_error_assert_ok (&error);
4125                 for (i = 0; i < argc; ++i) {
4126                         /* The encodings should all work, given that
4127                          * we've checked all these args for the
4128                          * main_args array.
4129                          */
4130                         gchar *str = mono_utf8_from_external (argv [i]);
4131                         MonoString *arg = mono_string_new (domain, str);
4132                         mono_array_setref (args, i, arg);
4133                         g_free (str);
4134                 }
4135         } else {
4136                 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4137                 mono_error_assert_ok (&error);
4138         }
4139         
4140         mono_assembly_set_main (method->klass->image->assembly);
4141
4142         return args;
4143 }
4144
4145 /**
4146  * mono_runtime_run_main:
4147  * @method: the method to start the application with (usually Main)
4148  * @argc: number of arguments from the command line
4149  * @argv: array of strings from the command line
4150  * @exc: excetption results
4151  *
4152  * Execute a standard Main() method (argc/argv contains the
4153  * executable name). This method also sets the command line argument value
4154  * needed by System.Environment.
4155  *
4156  * 
4157  */
4158 int
4159 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4160                        MonoObject **exc)
4161 {
4162         MONO_REQ_GC_UNSAFE_MODE;
4163
4164         MonoError error;
4165         MonoArray *args = prepare_run_main (method, argc, argv);
4166         int res;
4167         if (exc) {
4168                 res = mono_runtime_try_exec_main (method, args, exc);
4169         } else {
4170                 res = mono_runtime_exec_main_checked (method, args, &error);
4171                 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4172         }
4173         return res;
4174 }
4175
4176 /**
4177  * mono_runtime_run_main_checked:
4178  * @method: the method to start the application with (usually Main)
4179  * @argc: number of arguments from the command line
4180  * @argv: array of strings from the command line
4181  * @error: set on error
4182  *
4183  * Execute a standard Main() method (argc/argv contains the
4184  * executable name). This method also sets the command line argument value
4185  * needed by System.Environment.  On failure sets @error.
4186  *
4187  * 
4188  */
4189 int
4190 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4191                                MonoError *error)
4192 {
4193         mono_error_init (error);
4194         MonoArray *args = prepare_run_main (method, argc, argv);
4195         return mono_runtime_exec_main_checked (method, args, error);
4196 }
4197
4198 /**
4199  * mono_runtime_try_run_main:
4200  * @method: the method to start the application with (usually Main)
4201  * @argc: number of arguments from the command line
4202  * @argv: array of strings from the command line
4203  * @exc: set if Main throws an exception
4204  * @error: set if Main can't be executed
4205  *
4206  * Execute a standard Main() method (argc/argv contains the executable
4207  * name). This method also sets the command line argument value needed
4208  * by System.Environment.  On failure sets @error if Main can't be
4209  * executed or @exc if it threw and exception.
4210  *
4211  * 
4212  */
4213 int
4214 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4215                            MonoObject **exc)
4216 {
4217         g_assert (exc);
4218         MonoArray *args = prepare_run_main (method, argc, argv);
4219         return mono_runtime_try_exec_main (method, args, exc);
4220 }
4221
4222
4223 static MonoObject*
4224 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4225 {
4226         static MonoMethod *serialize_method;
4227
4228         MonoError error;
4229         void *params [1];
4230         MonoObject *array;
4231
4232         if (!serialize_method) {
4233                 MonoClass *klass = mono_class_get_remoting_services_class ();
4234                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4235         }
4236
4237         if (!serialize_method) {
4238                 *failure = TRUE;
4239                 return NULL;
4240         }
4241
4242         g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4243
4244         params [0] = obj;
4245         *exc = NULL;
4246
4247         array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4248         if (*exc == NULL && !mono_error_ok (&error))
4249                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4250         else
4251                 mono_error_cleanup (&error);
4252
4253         if (*exc)
4254                 *failure = TRUE;
4255
4256         return array;
4257 }
4258
4259 static MonoObject*
4260 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4261 {
4262         MONO_REQ_GC_UNSAFE_MODE;
4263
4264         static MonoMethod *deserialize_method;
4265
4266         MonoError error;
4267         void *params [1];
4268         MonoObject *result;
4269
4270         if (!deserialize_method) {
4271                 MonoClass *klass = mono_class_get_remoting_services_class ();
4272                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4273         }
4274         if (!deserialize_method) {
4275                 *failure = TRUE;
4276                 return NULL;
4277         }
4278
4279         params [0] = obj;
4280         *exc = NULL;
4281
4282         result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4283         if (*exc == NULL && !mono_error_ok (&error))
4284                 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4285         else
4286                 mono_error_cleanup (&error);
4287
4288         if (*exc)
4289                 *failure = TRUE;
4290
4291         return result;
4292 }
4293
4294 #ifndef DISABLE_REMOTING
4295 static MonoObject*
4296 make_transparent_proxy (MonoObject *obj, MonoError *error)
4297 {
4298         MONO_REQ_GC_UNSAFE_MODE;
4299
4300         static MonoMethod *get_proxy_method;
4301
4302         MonoDomain *domain = mono_domain_get ();
4303         MonoRealProxy *real_proxy;
4304         MonoReflectionType *reflection_type;
4305         MonoTransparentProxy *transparent_proxy;
4306
4307         mono_error_init (error);
4308
4309         if (!get_proxy_method)
4310                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4311
4312         g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4313
4314         real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4315         return_val_if_nok (error, NULL);
4316         reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4317         return_val_if_nok (error, NULL);
4318
4319         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4320         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4321
4322         MonoObject *exc = NULL;
4323
4324         transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4325         if (exc != NULL && is_ok (error))
4326                 mono_error_set_exception_instance (error, (MonoException*)exc);
4327
4328         return (MonoObject*) transparent_proxy;
4329 }
4330 #endif /* DISABLE_REMOTING */
4331
4332 /**
4333  * mono_object_xdomain_representation
4334  * @obj: an object
4335  * @target_domain: a domain
4336  * @error: set on error.
4337  *
4338  * Creates a representation of obj in the domain target_domain.  This
4339  * is either a copy of obj arrived through via serialization and
4340  * deserialization or a proxy, depending on whether the object is
4341  * serializable or marshal by ref.  obj must not be in target_domain.
4342  *
4343  * If the object cannot be represented in target_domain, NULL is
4344  * returned and @error is set appropriately.
4345  */
4346 MonoObject*
4347 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4348 {
4349         MONO_REQ_GC_UNSAFE_MODE;
4350
4351         mono_error_init (error);
4352         MonoObject *deserialized = NULL;
4353
4354 #ifndef DISABLE_REMOTING
4355         if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4356                 deserialized = make_transparent_proxy (obj, error);
4357         } 
4358         else
4359 #endif
4360         {
4361                 gboolean failure = FALSE;
4362                 MonoDomain *domain = mono_domain_get ();
4363                 MonoObject *serialized;
4364                 MonoObject *exc = NULL;
4365
4366                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4367                 serialized = serialize_object (obj, &failure, &exc);
4368                 mono_domain_set_internal_with_options (target_domain, FALSE);
4369                 if (!failure)
4370                         deserialized = deserialize_object (serialized, &failure, &exc);
4371                 if (domain != target_domain)
4372                         mono_domain_set_internal_with_options (domain, FALSE);
4373                 if (failure)
4374                         mono_error_set_exception_instance (error, (MonoException*)exc);
4375         }
4376
4377         return deserialized;
4378 }
4379
4380 /* Used in call_unhandled_exception_delegate */
4381 static MonoObject *
4382 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4383 {
4384         MONO_REQ_GC_UNSAFE_MODE;
4385
4386         mono_error_init (error);
4387         MonoClass *klass;
4388         gpointer args [2];
4389         MonoMethod *method = NULL;
4390         MonoBoolean is_terminating = TRUE;
4391         MonoObject *obj;
4392
4393         klass = mono_class_get_unhandled_exception_event_args_class ();
4394         mono_class_init (klass);
4395
4396         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4397         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4398         g_assert (method);
4399
4400         args [0] = exc;
4401         args [1] = &is_terminating;
4402
4403         obj = mono_object_new_checked (mono_domain_get (), klass, error);
4404         return_val_if_nok (error, NULL);
4405
4406         mono_runtime_invoke_checked (method, obj, args, error);
4407         return_val_if_nok (error, NULL);
4408
4409         return obj;
4410 }
4411
4412 /* Used in mono_unhandled_exception */
4413 static void
4414 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4415         MONO_REQ_GC_UNSAFE_MODE;
4416
4417         MonoError error;
4418         MonoObject *e = NULL;
4419         gpointer pa [2];
4420         MonoDomain *current_domain = mono_domain_get ();
4421
4422         if (domain != current_domain)
4423                 mono_domain_set_internal_with_options (domain, FALSE);
4424
4425         g_assert (domain == mono_object_domain (domain->domain));
4426
4427         if (mono_object_domain (exc) != domain) {
4428
4429                 exc = mono_object_xdomain_representation (exc, domain, &error);
4430                 if (!exc) {
4431                         if (!is_ok (&error)) {
4432                                 MonoError inner_error;
4433                                 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4434                                 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4435                                 mono_error_assert_ok (&inner_error);
4436                         } else {
4437                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4438                                                 "System.Runtime.Serialization", "SerializationException",
4439                                                 "Could not serialize unhandled exception.");
4440                         }
4441                 }
4442         }
4443         g_assert (mono_object_domain (exc) == domain);
4444
4445         pa [0] = domain->domain;
4446         pa [1] = create_unhandled_exception_eventargs (exc, &error);
4447         mono_error_assert_ok (&error);
4448         mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4449         if (!is_ok (&error)) {
4450                 if (e == NULL)
4451                         e = (MonoObject*)mono_error_convert_to_exception (&error);
4452                 else
4453                         mono_error_cleanup (&error);
4454         }
4455
4456         if (domain != current_domain)
4457                 mono_domain_set_internal_with_options (current_domain, FALSE);
4458
4459         if (e) {
4460                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4461                 if (!mono_error_ok (&error)) {
4462                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4463                         mono_error_cleanup (&error);
4464                 } else {
4465                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
4466                         g_free (msg);
4467                 }
4468         }
4469 }
4470
4471 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4472
4473 /**
4474  * mono_runtime_unhandled_exception_policy_set:
4475  * @policy: the new policy
4476  * 
4477  * This is a VM internal routine.
4478  *
4479  * Sets the runtime policy for handling unhandled exceptions.
4480  */
4481 void
4482 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4483         runtime_unhandled_exception_policy = policy;
4484 }
4485
4486 /**
4487  * mono_runtime_unhandled_exception_policy_get:
4488  *
4489  * This is a VM internal routine.
4490  *
4491  * Gets the runtime policy for handling unhandled exceptions.
4492  */
4493 MonoRuntimeUnhandledExceptionPolicy
4494 mono_runtime_unhandled_exception_policy_get (void) {
4495         return runtime_unhandled_exception_policy;
4496 }
4497
4498 /**
4499  * mono_unhandled_exception:
4500  * @exc: exception thrown
4501  *
4502  * This is a VM internal routine.
4503  *
4504  * We call this function when we detect an unhandled exception
4505  * in the default domain.
4506  *
4507  * It invokes the * UnhandledException event in AppDomain or prints
4508  * a warning to the console 
4509  */
4510 void
4511 mono_unhandled_exception (MonoObject *exc)
4512 {
4513         MONO_REQ_GC_UNSAFE_MODE;
4514
4515         MonoError error;
4516         MonoClassField *field;
4517         MonoDomain *current_domain, *root_domain;
4518         MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4519
4520         if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4521                 return;
4522
4523         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4524         g_assert (field);
4525
4526         current_domain = mono_domain_get ();
4527         root_domain = mono_get_root_domain ();
4528
4529         root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4530         mono_error_assert_ok (&error);
4531         if (current_domain != root_domain) {
4532                 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4533                 mono_error_assert_ok (&error);
4534         }
4535
4536         if (!current_appdomain_delegate && !root_appdomain_delegate) {
4537                 mono_print_unhandled_exception (exc);
4538         } else {
4539                 /* unhandled exception callbacks must not be aborted */
4540                 mono_threads_begin_abort_protected_block ();
4541                 if (root_appdomain_delegate)
4542                         call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4543                 if (current_appdomain_delegate)
4544                         call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4545                 mono_threads_end_abort_protected_block ();
4546         }
4547
4548         /* set exitcode only if we will abort the process */
4549         if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4550                  || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4551         {
4552                 mono_environment_exitcode_set (1);
4553         }
4554 }
4555
4556 /**
4557  * mono_runtime_exec_managed_code:
4558  * @domain: Application domain
4559  * @main_func: function to invoke from the execution thread
4560  * @main_args: parameter to the main_func
4561  *
4562  * Launch a new thread to execute a function
4563  *
4564  * main_func is called back from the thread with main_args as the
4565  * parameter.  The callback function is expected to start Main()
4566  * eventually.  This function then waits for all managed threads to
4567  * finish.
4568  * It is not necesseray anymore to execute managed code in a subthread,
4569  * so this function should not be used anymore by default: just
4570  * execute the code and then call mono_thread_manage ().
4571  */
4572 void
4573 mono_runtime_exec_managed_code (MonoDomain *domain,
4574                                 MonoMainThreadFunc main_func,
4575                                 gpointer main_args)
4576 {
4577         MonoError error;
4578         mono_thread_create_checked (domain, main_func, main_args, &error);
4579         mono_error_assert_ok (&error);
4580
4581         mono_thread_manage ();
4582 }
4583
4584 static void
4585 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4586 {
4587         MonoInternalThread* thread = mono_thread_internal_current ();
4588         MonoCustomAttrInfo* cinfo;
4589         gboolean has_stathread_attribute;
4590
4591         if (!domain->entry_assembly) {
4592                 gchar *str;
4593                 MonoAssembly *assembly;
4594
4595                 assembly = method->klass->image->assembly;
4596                 domain->entry_assembly = assembly;
4597                 /* Domains created from another domain already have application_base and configuration_file set */
4598                 if (domain->setup->application_base == NULL) {
4599                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4600                 }
4601
4602                 if (domain->setup->configuration_file == NULL) {
4603                         str = g_strconcat (assembly->image->name, ".config", NULL);
4604                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4605                         g_free (str);
4606                         mono_domain_set_options_from_config (domain);
4607                 }
4608         }
4609
4610         MonoError cattr_error;
4611         cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4612         mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4613         if (cinfo) {
4614                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4615                 if (!cinfo->cached)
4616                         mono_custom_attrs_free (cinfo);
4617         } else {
4618                 has_stathread_attribute = FALSE;
4619         }
4620         if (has_stathread_attribute) {
4621                 thread->apartment_state = ThreadApartmentState_STA;
4622         } else {
4623                 thread->apartment_state = ThreadApartmentState_MTA;
4624         }
4625         mono_thread_init_apartment_state ();
4626
4627 }
4628
4629 static int
4630 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4631 {
4632         MONO_REQ_GC_UNSAFE_MODE;
4633
4634         gpointer pa [1];
4635         int rval;
4636
4637         mono_error_init (error);
4638         g_assert (args);
4639
4640         pa [0] = args;
4641
4642         /* FIXME: check signature of method */
4643         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4644                 MonoObject *res;
4645                 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4646                 if (is_ok (error))
4647                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4648                 else
4649                         rval = -1;
4650                 mono_environment_exitcode_set (rval);
4651         } else {
4652                 mono_runtime_invoke_checked (method, NULL, pa, error);
4653
4654                 if (is_ok (error))
4655                         rval = 0;
4656                 else {
4657                         rval = -1;
4658                 }
4659         }
4660         return rval;
4661 }
4662
4663 static int
4664 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4665 {
4666         MONO_REQ_GC_UNSAFE_MODE;
4667
4668         gpointer pa [1];
4669         int rval;
4670
4671         g_assert (args);
4672         g_assert (exc);
4673
4674         pa [0] = args;
4675
4676         /* FIXME: check signature of method */
4677         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4678                 MonoError inner_error;
4679                 MonoObject *res;
4680                 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4681                 if (*exc == NULL && !mono_error_ok (&inner_error))
4682                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4683                 else
4684                         mono_error_cleanup (&inner_error);
4685
4686                 if (*exc == NULL)
4687                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4688                 else
4689                         rval = -1;
4690
4691                 mono_environment_exitcode_set (rval);
4692         } else {
4693                 MonoError inner_error;
4694                 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4695                 if (*exc == NULL && !mono_error_ok (&inner_error))
4696                         *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4697                 else
4698                         mono_error_cleanup (&inner_error);
4699
4700                 if (*exc == NULL)
4701                         rval = 0;
4702                 else {
4703                         /* If the return type of Main is void, only
4704                          * set the exitcode if an exception was thrown
4705                          * (we don't want to blow away an
4706                          * explicitly-set exit code)
4707                          */
4708                         rval = -1;
4709                         mono_environment_exitcode_set (rval);
4710                 }
4711         }
4712
4713         return rval;
4714 }
4715
4716 /*
4717  * Execute a standard Main() method (args doesn't contain the
4718  * executable name).
4719  */
4720 int
4721 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4722 {
4723         MonoError error;
4724         prepare_thread_to_exec_main (mono_object_domain (args), method);
4725         if (exc) {
4726                 int rval = do_try_exec_main (method, args, exc);
4727                 return rval;
4728         } else {
4729                 int rval = do_exec_main_checked (method, args, &error);
4730                 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4731                 return rval;
4732         }
4733 }
4734
4735 /*
4736  * Execute a standard Main() method (args doesn't contain the
4737  * executable name).
4738  *
4739  * On failure sets @error
4740  */
4741 int
4742 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4743 {
4744         mono_error_init (error);
4745         prepare_thread_to_exec_main (mono_object_domain (args), method);
4746         return do_exec_main_checked (method, args, error);
4747 }
4748
4749 /*
4750  * Execute a standard Main() method (args doesn't contain the
4751  * executable name).
4752  *
4753  * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4754  */
4755 int
4756 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4757 {
4758         prepare_thread_to_exec_main (mono_object_domain (args), method);
4759         return do_try_exec_main (method, args, exc);
4760 }
4761
4762
4763
4764 /** invoke_array_extract_argument:
4765  * @params: array of arguments to the method.
4766  * @i: the index of the argument to extract.
4767  * @t: ith type from the method signature.
4768  * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4769  * @error: set on error.
4770  *
4771  * Given an array of method arguments, return the ith one using the corresponding type
4772  * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4773  *
4774  * On failure sets @error and returns NULL.
4775  */
4776 static gpointer
4777 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4778 {
4779         MonoType *t_orig = t;
4780         gpointer result = NULL;
4781         mono_error_init (error);
4782                 again:
4783                         switch (t->type) {
4784                         case MONO_TYPE_U1:
4785                         case MONO_TYPE_I1:
4786                         case MONO_TYPE_BOOLEAN:
4787                         case MONO_TYPE_U2:
4788                         case MONO_TYPE_I2:
4789                         case MONO_TYPE_CHAR:
4790                         case MONO_TYPE_U:
4791                         case MONO_TYPE_I:
4792                         case MONO_TYPE_U4:
4793                         case MONO_TYPE_I4:
4794                         case MONO_TYPE_U8:
4795                         case MONO_TYPE_I8:
4796                         case MONO_TYPE_R4:
4797                         case MONO_TYPE_R8:
4798                         case MONO_TYPE_VALUETYPE:
4799                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4800                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4801                                         result = mono_array_get (params, MonoObject*, i);
4802                                         if (t->byref)
4803                                                 *has_byref_nullables = TRUE;
4804                                 } else {
4805                                         /* MS seems to create the objects if a null is passed in */
4806                                         if (!mono_array_get (params, MonoObject*, i)) {
4807                                                 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4808                                                 return_val_if_nok (error, NULL);
4809                                                 mono_array_setref (params, i, o); 
4810                                         }
4811
4812                                         if (t->byref) {
4813                                                 /*
4814                                                  * We can't pass the unboxed vtype byref to the callee, since
4815                                                  * that would mean the callee would be able to modify boxed
4816                                                  * primitive types. So we (and MS) make a copy of the boxed
4817                                                  * object, pass that to the callee, and replace the original
4818                                                  * boxed object in the arg array with the copy.
4819                                                  */
4820                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4821                                                 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4822                                                 return_val_if_nok (error, NULL);
4823                                                 mono_array_setref (params, i, copy);
4824                                         }
4825                                                 
4826                                         result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4827                                 }
4828                                 break;
4829                         case MONO_TYPE_STRING:
4830                         case MONO_TYPE_OBJECT:
4831                         case MONO_TYPE_CLASS:
4832                         case MONO_TYPE_ARRAY:
4833                         case MONO_TYPE_SZARRAY:
4834                                 if (t->byref)
4835                                         result = mono_array_addr (params, MonoObject*, i);
4836                                         // FIXME: I need to check this code path
4837                                 else
4838                                         result = mono_array_get (params, MonoObject*, i);
4839                                 break;
4840                         case MONO_TYPE_GENERICINST:
4841                                 if (t->byref)
4842                                         t = &t->data.generic_class->container_class->this_arg;
4843                                 else
4844                                         t = &t->data.generic_class->container_class->byval_arg;
4845                                 goto again;
4846                         case MONO_TYPE_PTR: {
4847                                 MonoObject *arg;
4848
4849                                 /* The argument should be an IntPtr */
4850                                 arg = mono_array_get (params, MonoObject*, i);
4851                                 if (arg == NULL) {
4852                                         result = NULL;
4853                                 } else {
4854                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4855                                         result = ((MonoIntPtr*)arg)->m_value;
4856                                 }
4857                                 break;
4858                         }
4859                         default:
4860                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4861                         }
4862         return result;
4863 }
4864 /**
4865  * mono_runtime_invoke_array:
4866  * @method: method to invoke
4867  * @obJ: object instance
4868  * @params: arguments to the method
4869  * @exc: exception information.
4870  *
4871  * Invokes the method represented by @method on the object @obj.
4872  *
4873  * obj is the 'this' pointer, it should be NULL for static
4874  * methods, a MonoObject* for object instances and a pointer to
4875  * the value type for value types.
4876  *
4877  * The params array contains the arguments to the method with the
4878  * same convention: MonoObject* pointers for object instances and
4879  * pointers to the value type otherwise. The _invoke_array
4880  * variant takes a C# object[] as the params argument (MonoArray
4881  * *params): in this case the value types are boxed inside the
4882  * respective reference representation.
4883  * 
4884  * From unmanaged code you'll usually use the
4885  * mono_runtime_invoke_checked() variant.
4886  *
4887  * Note that this function doesn't handle virtual methods for
4888  * you, it will exec the exact method you pass: we still need to
4889  * expose a function to lookup the derived class implementation
4890  * of a virtual method (there are examples of this in the code,
4891  * though).
4892  * 
4893  * You can pass NULL as the exc argument if you don't want to
4894  * catch exceptions, otherwise, *exc will be set to the exception
4895  * thrown, if any.  if an exception is thrown, you can't use the
4896  * MonoObject* result from the function.
4897  * 
4898  * If the method returns a value type, it is boxed in an object
4899  * reference.
4900  */
4901 MonoObject*
4902 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4903                            MonoObject **exc)
4904 {
4905         MonoError error;
4906         if (exc) {
4907                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4908                 if (*exc) {
4909                         mono_error_cleanup (&error);
4910                         return NULL;
4911                 } else {
4912                         if (!is_ok (&error))
4913                                 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4914                         return result;
4915                 }
4916         } else {
4917                 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4918                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4919                 return result;
4920         }
4921 }
4922
4923 /**
4924  * mono_runtime_invoke_array_checked:
4925  * @method: method to invoke
4926  * @obJ: object instance
4927  * @params: arguments to the method
4928  * @error: set on failure.
4929  *
4930  * Invokes the method represented by @method on the object @obj.
4931  *
4932  * obj is the 'this' pointer, it should be NULL for static
4933  * methods, a MonoObject* for object instances and a pointer to
4934  * the value type for value types.
4935  *
4936  * The params array contains the arguments to the method with the
4937  * same convention: MonoObject* pointers for object instances and
4938  * pointers to the value type otherwise. The _invoke_array
4939  * variant takes a C# object[] as the params argument (MonoArray
4940  * *params): in this case the value types are boxed inside the
4941  * respective reference representation.
4942  *
4943  * From unmanaged code you'll usually use the
4944  * mono_runtime_invoke_checked() variant.
4945  *
4946  * Note that this function doesn't handle virtual methods for
4947  * you, it will exec the exact method you pass: we still need to
4948  * expose a function to lookup the derived class implementation
4949  * of a virtual method (there are examples of this in the code,
4950  * though).
4951  *
4952  * On failure or exception, @error will be set. In that case, you
4953  * can't use the MonoObject* result from the function.
4954  *
4955  * If the method returns a value type, it is boxed in an object
4956  * reference.
4957  */
4958 MonoObject*
4959 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4960                                    MonoError *error)
4961 {
4962         mono_error_init (error);
4963         return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4964 }
4965
4966 /**
4967  * mono_runtime_try_invoke_array:
4968  * @method: method to invoke
4969  * @obJ: object instance
4970  * @params: arguments to the method
4971  * @exc: exception information.
4972  * @error: set on failure.
4973  *
4974  * Invokes the method represented by @method on the object @obj.
4975  *
4976  * obj is the 'this' pointer, it should be NULL for static
4977  * methods, a MonoObject* for object instances and a pointer to
4978  * the value type for value types.
4979  *
4980  * The params array contains the arguments to the method with the
4981  * same convention: MonoObject* pointers for object instances and
4982  * pointers to the value type otherwise. The _invoke_array
4983  * variant takes a C# object[] as the params argument (MonoArray
4984  * *params): in this case the value types are boxed inside the
4985  * respective reference representation.
4986  *
4987  * From unmanaged code you'll usually use the
4988  * mono_runtime_invoke_checked() variant.
4989  *
4990  * Note that this function doesn't handle virtual methods for
4991  * you, it will exec the exact method you pass: we still need to
4992  * expose a function to lookup the derived class implementation
4993  * of a virtual method (there are examples of this in the code,
4994  * though).
4995  *
4996  * You can pass NULL as the exc argument if you don't want to catch
4997  * exceptions, otherwise, *exc will be set to the exception thrown, if
4998  * any.  On other failures, @error will be set. If an exception is
4999  * thrown or there's an error, you can't use the MonoObject* result
5000  * from the function.
5001  *
5002  * If the method returns a value type, it is boxed in an object
5003  * reference.
5004  */
5005 MonoObject*
5006 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5007                                MonoObject **exc, MonoError *error)
5008 {
5009         MONO_REQ_GC_UNSAFE_MODE;
5010
5011         mono_error_init (error);
5012
5013         MonoMethodSignature *sig = mono_method_signature (method);
5014         gpointer *pa = NULL;
5015         MonoObject *res;
5016         int i;
5017         gboolean has_byref_nullables = FALSE;
5018
5019         if (NULL != params) {
5020                 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5021                 for (i = 0; i < mono_array_length (params); i++) {
5022                         MonoType *t = sig->params [i];
5023                         pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5024                         return_val_if_nok (error, NULL);
5025                 }
5026         }
5027
5028         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5029                 void *o = obj;
5030
5031                 if (mono_class_is_nullable (method->klass)) {
5032                         /* Need to create a boxed vtype instead */
5033                         g_assert (!obj);
5034
5035                         if (!params)
5036                                 return NULL;
5037                         else {
5038                                 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5039                         }
5040                 }
5041
5042                 if (!obj) {
5043                         obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5044                         mono_error_assert_ok (error);
5045                         g_assert (obj); /*maybe we should raise a TLE instead?*/
5046 #ifndef DISABLE_REMOTING
5047                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5048                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5049                         }
5050 #endif
5051                         if (method->klass->valuetype)
5052                                 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5053                         else
5054                                 o = obj;
5055                 } else if (method->klass->valuetype) {
5056                         obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5057                         return_val_if_nok (error, NULL);
5058                 }
5059
5060                 if (exc) {
5061                         mono_runtime_try_invoke (method, o, pa, exc, error);
5062                 } else {
5063                         mono_runtime_invoke_checked (method, o, pa, error);
5064                 }
5065
5066                 return (MonoObject *)obj;
5067         } else {
5068                 if (mono_class_is_nullable (method->klass)) {
5069                         MonoObject *nullable;
5070
5071                         /* Convert the unboxed vtype into a Nullable structure */
5072                         nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5073                         return_val_if_nok (error, NULL);
5074
5075                         MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5076                         return_val_if_nok (error, NULL);
5077                         mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5078                         obj = mono_object_unbox (nullable);
5079                 }
5080
5081                 /* obj must be already unboxed if needed */
5082                 if (exc) {
5083                         res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5084                 } else {
5085                         res = mono_runtime_invoke_checked (method, obj, pa, error);
5086                 }
5087                 return_val_if_nok (error, NULL);
5088
5089                 if (sig->ret->type == MONO_TYPE_PTR) {
5090                         MonoClass *pointer_class;
5091                         static MonoMethod *box_method;
5092                         void *box_args [2];
5093                         MonoObject *box_exc;
5094
5095                         /* 
5096                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
5097                          * convert it to a Pointer object.
5098                          */
5099                         pointer_class = mono_class_get_pointer_class ();
5100                         if (!box_method)
5101                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5102
5103                         g_assert (res->vtable->klass == mono_defaults.int_class);
5104                         box_args [0] = ((MonoIntPtr*)res)->m_value;
5105                         box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5106                         return_val_if_nok (error, NULL);
5107
5108                         res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5109                         g_assert (box_exc == NULL);
5110                         mono_error_assert_ok (error);
5111                 }
5112
5113                 if (has_byref_nullables) {
5114                         /* 
5115                          * The runtime invoke wrapper already converted byref nullables back,
5116                          * and stored them in pa, we just need to copy them back to the
5117                          * managed array.
5118                          */
5119                         for (i = 0; i < mono_array_length (params); i++) {
5120                                 MonoType *t = sig->params [i];
5121
5122                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5123                                         mono_array_setref (params, i, pa [i]);
5124                         }
5125                 }
5126
5127                 return res;
5128         }
5129 }
5130
5131 /**
5132  * mono_object_new:
5133  * @klass: the class of the object that we want to create
5134  *
5135  * Returns: a newly created object whose definition is
5136  * looked up using @klass.   This will not invoke any constructors, 
5137  * so the consumer of this routine has to invoke any constructors on
5138  * its own to initialize the object.
5139  * 
5140  * It returns NULL on failure.
5141  */
5142 MonoObject *
5143 mono_object_new (MonoDomain *domain, MonoClass *klass)
5144 {
5145         MONO_REQ_GC_UNSAFE_MODE;
5146
5147         MonoError error;
5148
5149         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5150
5151         mono_error_cleanup (&error);
5152         return result;
5153 }
5154
5155 MonoObject *
5156 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5157 {
5158         MONO_REQ_GC_UNSAFE_MODE;
5159
5160         MonoError error;
5161
5162         MonoObject * result = mono_object_new_checked (domain, klass, &error);
5163
5164         mono_error_set_pending_exception (&error);
5165         return result;
5166 }
5167
5168 /**
5169  * mono_object_new_checked:
5170  * @klass: the class of the object that we want to create
5171  * @error: set on error
5172  *
5173  * Returns: a newly created object whose definition is
5174  * looked up using @klass.   This will not invoke any constructors,
5175  * so the consumer of this routine has to invoke any constructors on
5176  * its own to initialize the object.
5177  *
5178  * It returns NULL on failure and sets @error.
5179  */
5180 MonoObject *
5181 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5182 {
5183         MONO_REQ_GC_UNSAFE_MODE;
5184
5185         MonoVTable *vtable;
5186
5187         vtable = mono_class_vtable (domain, klass);
5188         g_assert (vtable); /* FIXME don't swallow the error */
5189
5190         MonoObject *o = mono_object_new_specific_checked (vtable, error);
5191         return o;
5192 }
5193
5194 /**
5195  * mono_object_new_pinned:
5196  *
5197  *   Same as mono_object_new, but the returned object will be pinned.
5198  * For SGEN, these objects will only be freed at appdomain unload.
5199  */
5200 MonoObject *
5201 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5202 {
5203         MONO_REQ_GC_UNSAFE_MODE;
5204
5205         MonoVTable *vtable;
5206
5207         mono_error_init (error);
5208
5209         vtable = mono_class_vtable (domain, klass);
5210         g_assert (vtable); /* FIXME don't swallow the error */
5211
5212         MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5213
5214         if (G_UNLIKELY (!o))
5215                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5216         else if (G_UNLIKELY (vtable->klass->has_finalize))
5217                 mono_object_register_finalizer (o);
5218
5219         return o;
5220 }
5221
5222 /**
5223  * mono_object_new_specific:
5224  * @vtable: the vtable of the object that we want to create
5225  *
5226  * Returns: A newly created object with class and domain specified
5227  * by @vtable
5228  */
5229 MonoObject *
5230 mono_object_new_specific (MonoVTable *vtable)
5231 {
5232         MonoError error;
5233         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5234         mono_error_cleanup (&error);
5235
5236         return o;
5237 }
5238
5239 MonoObject *
5240 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5241 {
5242         MONO_REQ_GC_UNSAFE_MODE;
5243
5244         MonoObject *o;
5245
5246         mono_error_init (error);
5247
5248         /* check for is_com_object for COM Interop */
5249         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5250         {
5251                 gpointer pa [1];
5252                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5253
5254                 if (im == NULL) {
5255                         MonoClass *klass = mono_class_get_activation_services_class ();
5256
5257                         if (!klass->inited)
5258                                 mono_class_init (klass);
5259
5260                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5261                         if (!im) {
5262                                 mono_error_set_not_supported (error, "Linked away.");
5263                                 return NULL;
5264                         }
5265                         vtable->domain->create_proxy_for_type_method = im;
5266                 }
5267         
5268                 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5269                 if (!mono_error_ok (error))
5270                         return NULL;
5271
5272                 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5273                 if (!mono_error_ok (error))
5274                         return NULL;
5275
5276                 if (o != NULL)
5277                         return o;
5278         }
5279
5280         return mono_object_new_alloc_specific_checked (vtable, error);
5281 }
5282
5283 MonoObject *
5284 ves_icall_object_new_specific (MonoVTable *vtable)
5285 {
5286         MonoError error;
5287         MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5288         mono_error_set_pending_exception (&error);
5289
5290         return o;
5291 }
5292
5293 /**
5294  * mono_object_new_alloc_specific:
5295  * @vtable: virtual table for the object.
5296  *
5297  * This function allocates a new `MonoObject` with the type derived
5298  * from the @vtable information.   If the class of this object has a 
5299  * finalizer, then the object will be tracked for finalization.
5300  *
5301  * This method might raise an exception on errors.  Use the
5302  * `mono_object_new_fast_checked` method if you want to manually raise
5303  * the exception.
5304  *
5305  * Returns: the allocated object.   
5306  */
5307 MonoObject *
5308 mono_object_new_alloc_specific (MonoVTable *vtable)
5309 {
5310         MonoError error;
5311         MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5312         mono_error_cleanup (&error);
5313
5314         return o;
5315 }
5316
5317 /**
5318  * mono_object_new_alloc_specific_checked:
5319  * @vtable: virtual table for the object.
5320  * @error: holds the error return value.  
5321  *
5322  * This function allocates a new `MonoObject` with the type derived
5323  * from the @vtable information. If the class of this object has a 
5324  * finalizer, then the object will be tracked for finalization.
5325  *
5326  * If there is not enough memory, the @error parameter will be set
5327  * and will contain a user-visible message with the amount of bytes
5328  * that were requested.
5329  *
5330  * Returns: the allocated object, or NULL if there is not enough memory
5331  *
5332  */
5333 MonoObject *
5334 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5335 {
5336         MONO_REQ_GC_UNSAFE_MODE;
5337
5338         MonoObject *o;
5339
5340         mono_error_init (error);
5341
5342         o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5343
5344         if (G_UNLIKELY (!o))
5345                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5346         else if (G_UNLIKELY (vtable->klass->has_finalize))
5347                 mono_object_register_finalizer (o);
5348
5349         return o;
5350 }
5351
5352 /**
5353  * mono_object_new_fast:
5354  * @vtable: virtual table for the object.
5355  *
5356  * This function allocates a new `MonoObject` with the type derived
5357  * from the @vtable information.   The returned object is not tracked
5358  * for finalization.   If your object implements a finalizer, you should
5359  * use `mono_object_new_alloc_specific` instead.
5360  *
5361  * This method might raise an exception on errors.  Use the
5362  * `mono_object_new_fast_checked` method if you want to manually raise
5363  * the exception.
5364  *
5365  * Returns: the allocated object.   
5366  */
5367 MonoObject*
5368 mono_object_new_fast (MonoVTable *vtable)
5369 {
5370         MonoError error;
5371         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5372         mono_error_cleanup (&error);
5373
5374         return o;
5375 }
5376
5377 /**
5378  * mono_object_new_fast_checked:
5379  * @vtable: virtual table for the object.
5380  * @error: holds the error return value.
5381  *
5382  * This function allocates a new `MonoObject` with the type derived
5383  * from the @vtable information. The returned object is not tracked
5384  * for finalization.   If your object implements a finalizer, you should
5385  * use `mono_object_new_alloc_specific_checked` instead.
5386  *
5387  * If there is not enough memory, the @error parameter will be set
5388  * and will contain a user-visible message with the amount of bytes
5389  * that were requested.
5390  *
5391  * Returns: the allocated object, or NULL if there is not enough memory
5392  *
5393  */
5394 MonoObject*
5395 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5396 {
5397         MONO_REQ_GC_UNSAFE_MODE;
5398
5399         MonoObject *o;
5400
5401         mono_error_init (error);
5402
5403         o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5404
5405         if (G_UNLIKELY (!o))
5406                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5407
5408         return o;
5409 }
5410
5411 MonoObject *
5412 ves_icall_object_new_fast (MonoVTable *vtable)
5413 {
5414         MonoError error;
5415         MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5416         mono_error_set_pending_exception (&error);
5417
5418         return o;
5419 }
5420
5421 MonoObject*
5422 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5423 {
5424         MONO_REQ_GC_UNSAFE_MODE;
5425
5426         MonoObject *o;
5427
5428         mono_error_init (error);
5429
5430         o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5431
5432         if (G_UNLIKELY (!o))
5433                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5434         else if (G_UNLIKELY (vtable->klass->has_finalize))
5435                 mono_object_register_finalizer (o);
5436
5437         return o;
5438 }
5439
5440 /**
5441  * mono_class_get_allocation_ftn:
5442  * @vtable: vtable
5443  * @for_box: the object will be used for boxing
5444  * @pass_size_in_words: 
5445  *
5446  * Return the allocation function appropriate for the given class.
5447  */
5448
5449 void*
5450 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5451 {
5452         MONO_REQ_GC_NEUTRAL_MODE;
5453
5454         *pass_size_in_words = FALSE;
5455
5456         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5457                 return ves_icall_object_new_specific;
5458
5459         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5460
5461                 return ves_icall_object_new_fast;
5462
5463                 /* 
5464                  * FIXME: This is actually slower than ves_icall_object_new_fast, because
5465                  * of the overhead of parameter passing.
5466                  */
5467                 /*
5468                 *pass_size_in_words = TRUE;
5469 #ifdef GC_REDIRECT_TO_LOCAL
5470                 return GC_local_gcj_fast_malloc;
5471 #else
5472                 return GC_gcj_fast_malloc;
5473 #endif
5474                 */
5475         }
5476
5477         return ves_icall_object_new_specific;
5478 }
5479
5480 /**
5481  * mono_object_new_from_token:
5482  * @image: Context where the type_token is hosted
5483  * @token: a token of the type that we want to create
5484  *
5485  * Returns: A newly created object whose definition is
5486  * looked up using @token in the @image image
5487  */
5488 MonoObject *
5489 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
5490 {
5491         MONO_REQ_GC_UNSAFE_MODE;
5492
5493         MonoError error;
5494         MonoObject *result;
5495         MonoClass *klass;
5496
5497         klass = mono_class_get_checked (image, token, &error);
5498         mono_error_assert_ok (&error);
5499         
5500         result = mono_object_new_checked (domain, klass, &error);
5501
5502         mono_error_cleanup (&error);
5503         return result;
5504         
5505 }
5506
5507
5508 /**
5509  * mono_object_clone:
5510  * @obj: the object to clone
5511  *
5512  * Returns: A newly created object who is a shallow copy of @obj
5513  */
5514 MonoObject *
5515 mono_object_clone (MonoObject *obj)
5516 {
5517         MonoError error;
5518         MonoObject *o = mono_object_clone_checked (obj, &error);
5519         mono_error_cleanup (&error);
5520
5521         return o;
5522 }
5523
5524 MonoObject *
5525 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5526 {
5527         MONO_REQ_GC_UNSAFE_MODE;
5528
5529         MonoObject *o;
5530         int size;
5531
5532         mono_error_init (error);
5533
5534         size = obj->vtable->klass->instance_size;
5535
5536         if (obj->vtable->klass->rank)
5537                 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5538
5539         o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5540
5541         if (G_UNLIKELY (!o)) {
5542                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5543                 return NULL;
5544         }
5545
5546         /* If the object doesn't contain references this will do a simple memmove. */
5547         mono_gc_wbarrier_object_copy (o, obj);
5548
5549         if (obj->vtable->klass->has_finalize)
5550                 mono_object_register_finalizer (o);
5551         return o;
5552 }
5553
5554 /**
5555  * mono_array_full_copy:
5556  * @src: source array to copy
5557  * @dest: destination array
5558  *
5559  * Copies the content of one array to another with exactly the same type and size.
5560  */
5561 void
5562 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5563 {
5564         MONO_REQ_GC_UNSAFE_MODE;
5565
5566         uintptr_t size;
5567         MonoClass *klass = src->obj.vtable->klass;
5568
5569         g_assert (klass == dest->obj.vtable->klass);
5570
5571         size = mono_array_length (src);
5572         g_assert (size == mono_array_length (dest));
5573         size *= mono_array_element_size (klass);
5574 #ifdef HAVE_SGEN_GC
5575         if (klass->element_class->valuetype) {
5576                 if (klass->element_class->has_references)
5577                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5578                 else
5579                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5580         } else {
5581                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5582         }
5583 #else
5584         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5585 #endif
5586 }
5587
5588 /**
5589  * mono_array_clone_in_domain:
5590  * @domain: the domain in which the array will be cloned into
5591  * @array: the array to clone
5592  * @error: set on error
5593  *
5594  * This routine returns a copy of the array that is hosted on the
5595  * specified MonoDomain.  On failure returns NULL and sets @error.
5596  */
5597 MonoArray*
5598 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5599 {
5600         MONO_REQ_GC_UNSAFE_MODE;
5601
5602         MonoArray *o;
5603         uintptr_t size, i;
5604         uintptr_t *sizes;
5605         MonoClass *klass = array->obj.vtable->klass;
5606
5607         mono_error_init (error);
5608
5609         if (array->bounds == NULL) {
5610                 size = mono_array_length (array);
5611                 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5612                 return_val_if_nok (error, NULL);
5613
5614                 size *= mono_array_element_size (klass);
5615 #ifdef HAVE_SGEN_GC
5616                 if (klass->element_class->valuetype) {
5617                         if (klass->element_class->has_references)
5618                                 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5619                         else
5620                                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5621                 } else {
5622                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5623                 }
5624 #else
5625                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5626 #endif
5627                 return o;
5628         }
5629         
5630         sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5631         size = mono_array_element_size (klass);
5632         for (i = 0; i < klass->rank; ++i) {
5633                 sizes [i] = array->bounds [i].length;
5634                 size *= array->bounds [i].length;
5635                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5636         }
5637         o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5638         return_val_if_nok (error, NULL);
5639 #ifdef HAVE_SGEN_GC
5640         if (klass->element_class->valuetype) {
5641                 if (klass->element_class->has_references)
5642                         mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5643                 else
5644                         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5645         } else {
5646                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5647         }
5648 #else
5649         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5650 #endif
5651
5652         return o;
5653 }
5654
5655 /**
5656  * mono_array_clone:
5657  * @array: the array to clone
5658  *
5659  * Returns: A newly created array who is a shallow copy of @array
5660  */
5661 MonoArray*
5662 mono_array_clone (MonoArray *array)
5663 {
5664         MONO_REQ_GC_UNSAFE_MODE;
5665
5666         MonoError error;
5667         MonoArray *result = mono_array_clone_checked (array, &error);
5668         mono_error_cleanup (&error);
5669         return result;
5670 }
5671
5672 /**
5673  * mono_array_clone_checked:
5674  * @array: the array to clone
5675  * @error: set on error
5676  *
5677  * Returns: A newly created array who is a shallow copy of @array.  On
5678  * failure returns NULL and sets @error.
5679  */
5680 MonoArray*
5681 mono_array_clone_checked (MonoArray *array, MonoError *error)
5682 {
5683
5684         MONO_REQ_GC_UNSAFE_MODE;
5685         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5686 }
5687
5688 /* helper macros to check for overflow when calculating the size of arrays */
5689 #ifdef MONO_BIG_ARRAYS
5690 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5691 #define MYGUINT_MAX MYGUINT64_MAX
5692 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5693             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5694 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5695             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
5696                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5697 #else
5698 #define MYGUINT32_MAX 4294967295U
5699 #define MYGUINT_MAX MYGUINT32_MAX
5700 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5701             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5702 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5703             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
5704                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5705 #endif
5706
5707 gboolean
5708 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5709 {
5710         MONO_REQ_GC_NEUTRAL_MODE;
5711
5712         uintptr_t byte_len;
5713
5714         byte_len = mono_array_element_size (klass);
5715         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5716                 return FALSE;
5717         byte_len *= len;
5718         if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5719                 return FALSE;
5720         byte_len += MONO_SIZEOF_MONO_ARRAY;
5721
5722         *res = byte_len;
5723
5724         return TRUE;
5725 }
5726
5727 /**
5728  * mono_array_new_full:
5729  * @domain: domain where the object is created
5730  * @array_class: array class
5731  * @lengths: lengths for each dimension in the array
5732  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5733  *
5734  * This routine creates a new array objects with the given dimensions,
5735  * lower bounds and type.
5736  */
5737 MonoArray*
5738 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5739 {
5740         MonoError error;
5741         MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5742         mono_error_cleanup (&error);
5743
5744         return array;
5745 }
5746
5747 MonoArray*
5748 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5749 {
5750         MONO_REQ_GC_UNSAFE_MODE;
5751
5752         uintptr_t byte_len = 0, len, bounds_size;
5753         MonoObject *o;
5754         MonoArray *array;
5755         MonoArrayBounds *bounds;
5756         MonoVTable *vtable;
5757         int i;
5758
5759         mono_error_init (error);
5760
5761         if (!array_class->inited)
5762                 mono_class_init (array_class);
5763
5764         len = 1;
5765
5766         /* A single dimensional array with a 0 lower bound is the same as an szarray */
5767         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5768                 len = lengths [0];
5769                 if (len > MONO_ARRAY_MAX_INDEX) {
5770                         mono_error_set_generic_error (error, "System", "OverflowException", "");
5771                         return NULL;
5772                 }
5773                 bounds_size = 0;
5774         } else {
5775                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5776
5777                 for (i = 0; i < array_class->rank; ++i) {
5778                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5779                                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5780                                 return NULL;
5781                         }
5782                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5783                                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5784                                 return NULL;
5785                         }
5786                         len *= lengths [i];
5787                 }
5788         }
5789
5790         if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5791                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5792                 return NULL;
5793         }
5794
5795         if (bounds_size) {
5796                 /* align */
5797                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5798                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5799                         return NULL;
5800                 }
5801                 byte_len = (byte_len + 3) & ~3;
5802                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5803                         mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5804                         return NULL;
5805                 }
5806                 byte_len += bounds_size;
5807         }
5808         /* 
5809          * Following three lines almost taken from mono_object_new ():
5810          * they need to be kept in sync.
5811          */
5812         vtable = mono_class_vtable_full (domain, array_class, error);
5813         return_val_if_nok (error, NULL);
5814
5815         if (bounds_size)
5816                 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5817         else
5818                 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5819
5820         if (G_UNLIKELY (!o)) {
5821                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5822                 return NULL;
5823         }
5824
5825         array = (MonoArray*)o;
5826
5827         bounds = array->bounds;
5828
5829         if (bounds_size) {
5830                 for (i = 0; i < array_class->rank; ++i) {
5831                         bounds [i].length = lengths [i];
5832                         if (lower_bounds)
5833                                 bounds [i].lower_bound = lower_bounds [i];
5834                 }
5835         }
5836
5837         return array;
5838 }
5839
5840 /**
5841  * mono_array_new:
5842  * @domain: domain where the object is created
5843  * @eclass: element class
5844  * @n: number of array elements
5845  *
5846  * This routine creates a new szarray with @n elements of type @eclass.
5847  */
5848 MonoArray *
5849 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5850 {
5851         MONO_REQ_GC_UNSAFE_MODE;
5852
5853         MonoError error;
5854         MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5855         mono_error_cleanup (&error);
5856         return result;
5857 }
5858
5859 /**
5860  * mono_array_new_checked:
5861  * @domain: domain where the object is created
5862  * @eclass: element class
5863  * @n: number of array elements
5864  * @error: set on error
5865  *
5866  * This routine creates a new szarray with @n elements of type @eclass.
5867  * On failure returns NULL and sets @error.
5868  */
5869 MonoArray *
5870 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5871 {
5872         MonoClass *ac;
5873
5874         mono_error_init (error);
5875
5876         ac = mono_array_class_get (eclass, 1);
5877         g_assert (ac);
5878
5879         MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5880         return_val_if_nok (error, NULL);
5881
5882         return mono_array_new_specific_checked (vtable, n, error);
5883 }
5884
5885 MonoArray*
5886 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5887 {
5888         MonoError error;
5889         MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5890         mono_error_set_pending_exception (&error);
5891
5892         return arr;
5893 }
5894
5895 /**
5896  * mono_array_new_specific:
5897  * @vtable: a vtable in the appropriate domain for an initialized class
5898  * @n: number of array elements
5899  *
5900  * This routine is a fast alternative to mono_array_new() for code which
5901  * can be sure about the domain it operates in.
5902  */
5903 MonoArray *
5904 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5905 {
5906         MonoError error;
5907         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5908         mono_error_cleanup (&error);
5909
5910         return arr;
5911 }
5912
5913 MonoArray*
5914 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5915 {
5916         MONO_REQ_GC_UNSAFE_MODE;
5917
5918         MonoObject *o;
5919         uintptr_t byte_len;
5920
5921         mono_error_init (error);
5922
5923         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5924                 mono_error_set_generic_error (error, "System", "OverflowException", "");
5925                 return NULL;
5926         }
5927
5928         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5929                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5930                 return NULL;
5931         }
5932         o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5933
5934         if (G_UNLIKELY (!o)) {
5935                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5936                 return NULL;
5937         }
5938
5939         return (MonoArray*)o;
5940 }
5941
5942 MonoArray*
5943 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5944 {
5945         MonoError error;
5946         MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5947         mono_error_set_pending_exception (&error);
5948
5949         return arr;
5950 }
5951
5952 /**
5953  * mono_string_empty_wrapper:
5954  *
5955  * Returns: The same empty string instance as the managed string.Empty
5956  */
5957 MonoString*
5958 mono_string_empty_wrapper (void)
5959 {
5960         MonoDomain *domain = mono_domain_get ();
5961         return mono_string_empty (domain);
5962 }
5963
5964 /**
5965  * mono_string_empty:
5966  *
5967  * Returns: The same empty string instance as the managed string.Empty
5968  */
5969 MonoString*
5970 mono_string_empty (MonoDomain *domain)
5971 {
5972         g_assert (domain);
5973         g_assert (domain->empty_string);
5974         return domain->empty_string;
5975 }
5976
5977 /**
5978  * mono_string_new_utf16:
5979  * @text: a pointer to an utf16 string
5980  * @len: the length of the string
5981  *
5982  * Returns: A newly created string object which contains @text.
5983  */
5984 MonoString *
5985 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5986 {
5987         MONO_REQ_GC_UNSAFE_MODE;
5988
5989         MonoError error;
5990         MonoString *res = NULL;
5991         res = mono_string_new_utf16_checked (domain, text, len, &error);
5992         mono_error_cleanup (&error);
5993
5994         return res;
5995 }
5996
5997 /**
5998  * mono_string_new_utf16_checked:
5999  * @text: a pointer to an utf16 string
6000  * @len: the length of the string
6001  * @error: written on error.
6002  *
6003  * Returns: A newly created string object which contains @text.
6004  * On error, returns NULL and sets @error.
6005  */
6006 MonoString *
6007 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6008 {
6009         MONO_REQ_GC_UNSAFE_MODE;
6010
6011         MonoString *s;
6012         
6013         mono_error_init (error);
6014         
6015         s = mono_string_new_size_checked (domain, len, error);
6016         if (s != NULL)
6017                 memcpy (mono_string_chars (s), text, len * 2);
6018
6019         return s;
6020 }
6021
6022 /**
6023  * mono_string_new_utf32:
6024  * @text: a pointer to an utf32 string
6025  * @len: the length of the string
6026  * @error: set on failure.
6027  *
6028  * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6029  */
6030 static MonoString *
6031 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6032 {
6033         MONO_REQ_GC_UNSAFE_MODE;
6034
6035         MonoString *s;
6036         mono_unichar2 *utf16_output = NULL;
6037         gint32 utf16_len = 0;
6038         GError *gerror = NULL;
6039         glong items_written;
6040         
6041         mono_error_init (error);
6042         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6043         
6044         if (gerror)
6045                 g_error_free (gerror);
6046
6047         while (utf16_output [utf16_len]) utf16_len++;
6048         
6049         s = mono_string_new_size_checked (domain, utf16_len, error);
6050         return_val_if_nok (error, NULL);
6051
6052         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6053
6054         g_free (utf16_output);
6055         
6056         return s;
6057 }
6058
6059 /**
6060  * mono_string_new_utf32:
6061  * @text: a pointer to an utf32 string
6062  * @len: the length of the string
6063  *
6064  * Returns: A newly created string object which contains @text.
6065  */
6066 MonoString *
6067 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6068 {
6069         MonoError error;
6070         MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6071         mono_error_cleanup (&error);
6072         return result;
6073 }
6074
6075 /**
6076  * mono_string_new_size:
6077  * @text: a pointer to an utf16 string
6078  * @len: the length of the string
6079  *
6080  * Returns: A newly created string object of @len
6081  */
6082 MonoString *
6083 mono_string_new_size (MonoDomain *domain, gint32 len)
6084 {
6085         MonoError error;
6086         MonoString *str = mono_string_new_size_checked (domain, len, &error);
6087         mono_error_cleanup (&error);
6088
6089         return str;
6090 }
6091
6092 MonoString *
6093 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6094 {
6095         MONO_REQ_GC_UNSAFE_MODE;
6096
6097         MonoString *s;
6098         MonoVTable *vtable;
6099         size_t size;
6100
6101         mono_error_init (error);
6102
6103         /* check for overflow */
6104         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6105                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6106                 return NULL;
6107         }
6108
6109         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6110         g_assert (size > 0);
6111
6112         vtable = mono_class_vtable (domain, mono_defaults.string_class);
6113         g_assert (vtable);
6114
6115         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6116
6117         if (G_UNLIKELY (!s)) {
6118                 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6119                 return NULL;
6120         }
6121
6122         return s;
6123 }
6124
6125 /**
6126  * mono_string_new_len:
6127  * @text: a pointer to an utf8 string
6128  * @length: number of bytes in @text to consider
6129  *
6130  * Returns: A newly created string object which contains @text.
6131  */
6132 MonoString*
6133 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6134 {
6135         MONO_REQ_GC_UNSAFE_MODE;
6136
6137         MonoError error;
6138         MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6139         mono_error_cleanup (&error);
6140         return result;
6141 }
6142
6143 /**
6144  * mono_string_new_len_checked:
6145  * @text: a pointer to an utf8 string
6146  * @length: number of bytes in @text to consider
6147  * @error: set on error
6148  *
6149  * Returns: A newly created string object which contains @text. On
6150  * failure returns NULL and sets @error.
6151  */
6152 MonoString*
6153 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6154 {
6155         MONO_REQ_GC_UNSAFE_MODE;
6156
6157         mono_error_init (error);
6158
6159         GError *eg_error = NULL;
6160         MonoString *o = NULL;
6161         guint16 *ut = NULL;
6162         glong items_written;
6163
6164         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6165
6166         if (!eg_error)
6167                 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6168         else 
6169                 g_error_free (eg_error);
6170
6171         g_free (ut);
6172
6173         return o;
6174 }
6175
6176 /**
6177  * mono_string_new:
6178  * @text: a pointer to an utf8 string
6179  *
6180  * Returns: A newly created string object which contains @text.
6181  *
6182  * This function asserts if it cannot allocate a new string.
6183  *
6184  * @deprecated Use mono_string_new_checked in new code.
6185  */
6186 MonoString*
6187 mono_string_new (MonoDomain *domain, const char *text)
6188 {
6189         MonoError error;
6190         MonoString *res = NULL;
6191         res = mono_string_new_checked (domain, text, &error);
6192         mono_error_assert_ok (&error);
6193         return res;
6194 }
6195
6196 /**
6197  * mono_string_new_checked:
6198  * @text: a pointer to an utf8 string
6199  * @merror: set on error
6200  *
6201  * Returns: A newly created string object which contains @text.
6202  * On error returns NULL and sets @merror.
6203  */
6204 MonoString*
6205 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6206 {
6207         MONO_REQ_GC_UNSAFE_MODE;
6208
6209     GError *eg_error = NULL;
6210     MonoString *o = NULL;
6211     guint16 *ut;
6212     glong items_written;
6213     int l;
6214
6215     mono_error_init (error);
6216
6217     l = strlen (text);
6218    
6219     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6220
6221     if (!eg_error)
6222             o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6223     else
6224         g_error_free (eg_error);
6225
6226     g_free (ut);
6227     
6228 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6229 #if 0
6230         gunichar2 *str;
6231         const gchar *end;
6232         int len;
6233         MonoString *o = NULL;
6234
6235         if (!g_utf8_validate (text, -1, &end)) {
6236                 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6237                 goto leave;
6238         }
6239
6240         len = g_utf8_strlen (text, -1);
6241         o = mono_string_new_size_checked (domain, len, error);
6242         if (!o)
6243                 goto leave;
6244         str = mono_string_chars (o);
6245
6246         while (text < end) {
6247                 *str++ = g_utf8_get_char (text);
6248                 text = g_utf8_next_char (text);
6249         }
6250
6251 leave:
6252 #endif
6253         return o;
6254 }
6255
6256 /**
6257  * mono_string_new_wrapper:
6258  * @text: pointer to utf8 characters.
6259  *
6260  * Helper function to create a string object from @text in the current domain.
6261  */
6262 MonoString*
6263 mono_string_new_wrapper (const char *text)
6264 {
6265         MONO_REQ_GC_UNSAFE_MODE;
6266
6267         MonoDomain *domain = mono_domain_get ();
6268
6269         if (text)
6270                 return mono_string_new (domain, text);
6271
6272         return NULL;
6273 }
6274
6275 /**
6276  * mono_value_box:
6277  * @class: the class of the value
6278  * @value: a pointer to the unboxed data
6279  *
6280  * Returns: A newly created object which contains @value.
6281  */
6282 MonoObject *
6283 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6284 {
6285         MonoError error;
6286         MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6287         mono_error_cleanup (&error);
6288         return result;
6289 }
6290
6291 /**
6292  * mono_value_box_checked:
6293  * @domain: the domain of the new object
6294  * @class: the class of the value
6295  * @value: a pointer to the unboxed data
6296  * @error: set on error
6297  *
6298  * Returns: A newly created object which contains @value. On failure
6299  * returns NULL and sets @error.
6300  */
6301 MonoObject *
6302 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6303 {
6304         MONO_REQ_GC_UNSAFE_MODE;
6305         MonoObject *res;
6306         int size;
6307         MonoVTable *vtable;
6308
6309         mono_error_init (error);
6310
6311         g_assert (klass->valuetype);
6312         if (mono_class_is_nullable (klass))
6313                 return mono_nullable_box ((guint8 *)value, klass, error);
6314
6315         vtable = mono_class_vtable (domain, klass);
6316         if (!vtable)
6317                 return NULL;
6318         size = mono_class_instance_size (klass);
6319         res = mono_object_new_alloc_specific_checked (vtable, error);
6320         return_val_if_nok (error, NULL);
6321
6322         size = size - sizeof (MonoObject);
6323
6324 #ifdef HAVE_SGEN_GC
6325         g_assert (size == mono_class_value_size (klass, NULL));
6326         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6327 #else
6328 #if NO_UNALIGNED_ACCESS
6329         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6330 #else
6331         switch (size) {
6332         case 1:
6333                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6334                 break;
6335         case 2:
6336                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6337                 break;
6338         case 4:
6339                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6340                 break;
6341         case 8:
6342                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6343                 break;
6344         default:
6345                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6346         }
6347 #endif
6348 #endif
6349         if (klass->has_finalize) {
6350                 mono_object_register_finalizer (res);
6351                 return_val_if_nok (error, NULL);
6352         }
6353         return res;
6354 }
6355
6356 /**
6357  * mono_value_copy:
6358  * @dest: destination pointer
6359  * @src: source pointer
6360  * @klass: a valuetype class
6361  *
6362  * Copy a valuetype from @src to @dest. This function must be used
6363  * when @klass contains references fields.
6364  */
6365 void
6366 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6367 {
6368         MONO_REQ_GC_UNSAFE_MODE;
6369
6370         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6371 }
6372
6373 /**
6374  * mono_value_copy_array:
6375  * @dest: destination array
6376  * @dest_idx: index in the @dest array
6377  * @src: source pointer
6378  * @count: number of items
6379  *
6380  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
6381  * This function must be used when @klass contains references fields.
6382  * Overlap is handled.
6383  */
6384 void
6385 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6386 {
6387         MONO_REQ_GC_UNSAFE_MODE;
6388
6389         int size = mono_array_element_size (dest->obj.vtable->klass);
6390         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6391         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6392         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6393 }
6394
6395 /**
6396  * mono_object_get_domain:
6397  * @obj: object to query
6398  * 
6399  * Returns: the MonoDomain where the object is hosted
6400  */
6401 MonoDomain*
6402 mono_object_get_domain (MonoObject *obj)
6403 {
6404         MONO_REQ_GC_UNSAFE_MODE;
6405
6406         return mono_object_domain (obj);
6407 }
6408
6409 /**
6410  * mono_object_get_class:
6411  * @obj: object to query
6412  *
6413  * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6414  *
6415  * Returns: the MonoClass of the object.
6416  */
6417 MonoClass*
6418 mono_object_get_class (MonoObject *obj)
6419 {
6420         MONO_REQ_GC_UNSAFE_MODE;
6421
6422         return mono_object_class (obj);
6423 }
6424 /**
6425  * mono_object_get_size:
6426  * @o: object to query
6427  * 
6428  * Returns: the size, in bytes, of @o
6429  */
6430 guint
6431 mono_object_get_size (MonoObject* o)
6432 {
6433         MONO_REQ_GC_UNSAFE_MODE;
6434
6435         MonoClass* klass = mono_object_class (o);
6436         if (klass == mono_defaults.string_class) {
6437                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6438         } else if (o->vtable->rank) {
6439                 MonoArray *array = (MonoArray*)o;
6440                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6441                 if (array->bounds) {
6442                         size += 3;
6443                         size &= ~3;
6444                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
6445                 }
6446                 return size;
6447         } else {
6448                 return mono_class_instance_size (klass);
6449         }
6450 }
6451
6452 /**
6453  * mono_object_unbox:
6454  * @obj: object to unbox
6455  * 
6456  * Returns: a pointer to the start of the valuetype boxed in this
6457  * object.
6458  *
6459  * This method will assert if the object passed is not a valuetype.
6460  */
6461 gpointer
6462 mono_object_unbox (MonoObject *obj)
6463 {
6464         MONO_REQ_GC_UNSAFE_MODE;
6465
6466         /* add assert for valuetypes? */
6467         g_assert (obj->vtable->klass->valuetype);
6468         return ((char*)obj) + sizeof (MonoObject);
6469 }
6470
6471 /**
6472  * mono_object_isinst:
6473  * @obj: an object
6474  * @klass: a pointer to a class 
6475  *
6476  * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6477  */
6478 MonoObject *
6479 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6480 {
6481         MONO_REQ_GC_UNSAFE_MODE;
6482
6483         HANDLE_FUNCTION_ENTER ();
6484         MONO_HANDLE_DCL (MonoObject, obj);
6485         MonoError error;
6486         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6487         mono_error_cleanup (&error);
6488         HANDLE_FUNCTION_RETURN_OBJ (result);
6489 }
6490         
6491
6492 /**
6493  * mono_object_isinst_checked:
6494  * @obj: an object
6495  * @klass: a pointer to a class 
6496  * @error: set on error
6497  *
6498  * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6499  * On failure returns NULL and sets @error.
6500  */
6501 MonoObject *
6502 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6503 {
6504         MONO_REQ_GC_UNSAFE_MODE;
6505
6506         HANDLE_FUNCTION_ENTER ();
6507         mono_error_init (error);
6508         MONO_HANDLE_DCL (MonoObject, obj);
6509         MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6510         HANDLE_FUNCTION_RETURN_OBJ (result);
6511 }
6512
6513 /**
6514  * mono_object_handle_isinst:
6515  * @obj: an object
6516  * @klass: a pointer to a class 
6517  * @error: set on error
6518  *
6519  * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6520  * On failure returns NULL and sets @error.
6521  */
6522 MonoObjectHandle
6523 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6524 {
6525         mono_error_init (error);
6526         
6527         if (!klass->inited)
6528                 mono_class_init (klass);
6529
6530         if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6531                 return mono_object_handle_isinst_mbyref (obj, klass, error);
6532         }
6533
6534         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6535
6536         if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6537                 MONO_HANDLE_ASSIGN (result, obj);
6538         return result;
6539 }
6540
6541 MonoObject *
6542 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6543 {
6544         MONO_REQ_GC_UNSAFE_MODE;
6545
6546         HANDLE_FUNCTION_ENTER ();
6547         MonoError error;
6548         MONO_HANDLE_DCL (MonoObject, obj);
6549         MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6550         mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6551         HANDLE_FUNCTION_RETURN_OBJ (result);
6552 }
6553
6554 MonoObjectHandle
6555 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6556 {
6557         mono_error_init (error);
6558
6559         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6560
6561         if (MONO_HANDLE_IS_NULL (obj))
6562                 goto leave;
6563
6564         MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6565         
6566         if (mono_class_is_interface (klass)) {
6567                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6568                         MONO_HANDLE_ASSIGN (result, obj);
6569                         goto leave;
6570                 }
6571
6572                 /* casting an array one of the invariant interfaces that must act as such */
6573                 if (klass->is_array_special_interface) {
6574                         if (mono_class_is_assignable_from (klass, vt->klass)) {
6575                                 MONO_HANDLE_ASSIGN (result, obj);
6576                                 goto leave;
6577                         }
6578                 }
6579
6580                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6581                 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6582                         MONO_HANDLE_ASSIGN (result, obj);
6583                         goto leave;
6584                 }
6585         } else {
6586                 MonoClass *oklass = vt->klass;
6587                 if (mono_class_is_transparent_proxy (oklass)){
6588                         MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6589                         oklass = remote_class->proxy_class;
6590                 }
6591
6592                 mono_class_setup_supertypes (klass);    
6593                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6594                         MONO_HANDLE_ASSIGN (result, obj);
6595                         goto leave;
6596                 }
6597         }
6598 #ifndef DISABLE_REMOTING
6599         if (vt->klass == mono_defaults.transparent_proxy_class) 
6600         {
6601                 MonoBoolean custom_type_info =  MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6602                 if (!custom_type_info)
6603                         goto leave;
6604                 MonoDomain *domain = mono_domain_get ();
6605                 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6606                 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6607                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6608                 MonoMethod *im = NULL;
6609                 gpointer pa [2];
6610
6611                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6612                 if (!im) {
6613                         mono_error_set_not_supported (error, "Linked away.");
6614                         goto leave;
6615                 }
6616                 im = mono_object_handle_get_virtual_method (rp, im, error);
6617                 if (!is_ok (error))
6618                         goto leave;
6619                 g_assert (im);
6620         
6621                 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6622                 if (!is_ok (error))
6623                         goto leave;
6624
6625                 pa [0] = MONO_HANDLE_RAW (reftype);
6626                 pa [1] = MONO_HANDLE_RAW (obj);
6627                 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6628                 if (!is_ok (error))
6629                         goto leave;
6630
6631                 if (*(MonoBoolean *) mono_object_unbox(res)) {
6632                         /* Update the vtable of the remote type, so it can safely cast to this new type */
6633                         mono_upgrade_remote_class (domain, obj, klass, error);
6634                         if (!is_ok (error))
6635                                 goto leave;
6636                         MONO_HANDLE_ASSIGN (result, obj);
6637                 }
6638         }
6639 #endif /* DISABLE_REMOTING */
6640 leave:
6641         return result;
6642 }
6643
6644 /**
6645  * mono_object_castclass_mbyref:
6646  * @obj: an object
6647  * @klass: a pointer to a class 
6648  *
6649  * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6650  */
6651 MonoObject *
6652 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6653 {
6654         MONO_REQ_GC_UNSAFE_MODE;
6655         HANDLE_FUNCTION_ENTER ();
6656         MonoError error;
6657         MONO_HANDLE_DCL (MonoObject, obj);
6658         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6659         if (MONO_HANDLE_IS_NULL (obj))
6660                 goto leave;
6661         MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6662         mono_error_cleanup (&error);
6663 leave:
6664         HANDLE_FUNCTION_RETURN_OBJ (result);
6665 }
6666
6667 typedef struct {
6668         MonoDomain *orig_domain;
6669         MonoString *ins;
6670         MonoString *res;
6671 } LDStrInfo;
6672
6673 static void
6674 str_lookup (MonoDomain *domain, gpointer user_data)
6675 {
6676         MONO_REQ_GC_UNSAFE_MODE;
6677
6678         LDStrInfo *info = (LDStrInfo *)user_data;
6679         if (info->res || domain == info->orig_domain)
6680                 return;
6681         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6682 }
6683
6684 static MonoString*
6685 mono_string_get_pinned (MonoString *str, MonoError *error)
6686 {
6687         MONO_REQ_GC_UNSAFE_MODE;
6688
6689         mono_error_init (error);
6690
6691         /* We only need to make a pinned version of a string if this is a moving GC */
6692         if (!mono_gc_is_moving ())
6693                 return str;
6694         int size;
6695         MonoString *news;
6696         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6697         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6698         if (news) {
6699                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6700                 news->length = mono_string_length (str);
6701         } else {
6702                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6703         }
6704         return news;
6705 }
6706
6707 static MonoString*
6708 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6709 {
6710         MONO_REQ_GC_UNSAFE_MODE;
6711
6712         MonoGHashTable *ldstr_table;
6713         MonoString *s, *res;
6714         MonoDomain *domain;
6715         
6716         mono_error_init (error);
6717
6718         domain = ((MonoObject *)str)->vtable->domain;
6719         ldstr_table = domain->ldstr_table;
6720         ldstr_lock ();
6721         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6722         if (res) {
6723                 ldstr_unlock ();
6724                 return res;
6725         }
6726         if (insert) {
6727                 /* Allocate outside the lock */
6728                 ldstr_unlock ();
6729                 s = mono_string_get_pinned (str, error);
6730                 return_val_if_nok (error, NULL);
6731                 if (s) {
6732                         ldstr_lock ();
6733                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6734                         if (res) {
6735                                 ldstr_unlock ();
6736                                 return res;
6737                         }
6738                         mono_g_hash_table_insert (ldstr_table, s, s);
6739                         ldstr_unlock ();
6740                 }
6741                 return s;
6742         } else {
6743                 LDStrInfo ldstr_info;
6744                 ldstr_info.orig_domain = domain;
6745                 ldstr_info.ins = str;
6746                 ldstr_info.res = NULL;
6747
6748                 mono_domain_foreach (str_lookup, &ldstr_info);
6749                 if (ldstr_info.res) {
6750                         /* 
6751                          * the string was already interned in some other domain:
6752                          * intern it in the current one as well.
6753                          */
6754                         mono_g_hash_table_insert (ldstr_table, str, str);
6755                         ldstr_unlock ();
6756                         return str;
6757                 }
6758         }
6759         ldstr_unlock ();
6760         return NULL;
6761 }
6762
6763 /**
6764  * mono_string_is_interned:
6765  * @o: String to probe
6766  *
6767  * Returns whether the string has been interned.
6768  */
6769 MonoString*
6770 mono_string_is_interned (MonoString *o)
6771 {
6772         MonoError error;
6773         MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6774         /* This function does not fail. */
6775         mono_error_assert_ok (&error);
6776         return result;
6777 }
6778
6779 /**
6780  * mono_string_intern:
6781  * @o: String to intern
6782  *
6783  * Interns the string passed.  
6784  * Returns: The interned string.
6785  */
6786 MonoString*
6787 mono_string_intern (MonoString *str)
6788 {
6789         MonoError error;
6790         MonoString *result = mono_string_intern_checked (str, &error);
6791         mono_error_assert_ok (&error);
6792         return result;
6793 }
6794
6795 /**
6796  * mono_string_intern_checked:
6797  * @o: String to intern
6798  * @error: set on error.
6799  *
6800  * Interns the string passed.
6801  * Returns: The interned string.  On failure returns NULL and sets @error
6802  */
6803 MonoString*
6804 mono_string_intern_checked (MonoString *str, MonoError *error)
6805 {
6806         MONO_REQ_GC_UNSAFE_MODE;
6807
6808         mono_error_init (error);
6809
6810         return mono_string_is_interned_lookup (str, TRUE, error);
6811 }
6812
6813 /**
6814  * mono_ldstr:
6815  * @domain: the domain where the string will be used.
6816  * @image: a metadata context
6817  * @idx: index into the user string table.
6818  * 
6819  * Implementation for the ldstr opcode.
6820  * Returns: a loaded string from the @image/@idx combination.
6821  */
6822 MonoString*
6823 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6824 {
6825         MonoError error;
6826         MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6827         mono_error_cleanup (&error);
6828         return result;
6829 }
6830
6831 /**
6832  * mono_ldstr_checked:
6833  * @domain: the domain where the string will be used.
6834  * @image: a metadata context
6835  * @idx: index into the user string table.
6836  * @error: set on error.
6837  * 
6838  * Implementation for the ldstr opcode.
6839  * Returns: a loaded string from the @image/@idx combination.
6840  * On failure returns NULL and sets @error.
6841  */
6842 MonoString*
6843 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6844 {
6845         MONO_REQ_GC_UNSAFE_MODE;
6846         mono_error_init (error);
6847
6848         if (image->dynamic) {
6849                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6850                 return str;
6851         } else {
6852                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6853                         return NULL; /*FIXME we should probably be raising an exception here*/
6854                 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6855                 return str;
6856         }
6857 }
6858
6859 /**
6860  * mono_ldstr_metadata_sig
6861  * @domain: the domain for the string
6862  * @sig: the signature of a metadata string
6863  * @error: set on error
6864  *
6865  * Returns: a MonoString for a string stored in the metadata. On
6866  * failure returns NULL and sets @error.
6867  */
6868 static MonoString*
6869 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6870 {
6871         MONO_REQ_GC_UNSAFE_MODE;
6872
6873         mono_error_init (error);
6874         const char *str = sig;
6875         MonoString *o, *interned;
6876         size_t len2;
6877
6878         len2 = mono_metadata_decode_blob_size (str, &str);
6879         len2 >>= 1;
6880
6881         o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6882         return_val_if_nok (error, NULL);
6883 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6884         {
6885                 int i;
6886                 guint16 *p2 = (guint16*)mono_string_chars (o);
6887                 for (i = 0; i < len2; ++i) {
6888                         *p2 = GUINT16_FROM_LE (*p2);
6889                         ++p2;
6890                 }
6891         }
6892 #endif
6893         ldstr_lock ();
6894         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6895         ldstr_unlock ();
6896         if (interned)
6897                 return interned; /* o will get garbage collected */
6898
6899         o = mono_string_get_pinned (o, error);
6900         if (o) {
6901                 ldstr_lock ();
6902                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6903                 if (!interned) {
6904                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
6905                         interned = o;
6906                 }
6907                 ldstr_unlock ();
6908         }
6909
6910         return interned;
6911 }
6912
6913 /*
6914  * mono_ldstr_utf8:
6915  *
6916  *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
6917  * of an object.
6918  */
6919 char*
6920 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6921 {
6922         const char *str;
6923         size_t len2;
6924         long written = 0;
6925         char *as;
6926         GError *gerror = NULL;
6927
6928         mono_error_init (error);
6929
6930         if (!mono_verifier_verify_string_signature (image, idx, NULL))
6931                 return NULL; /*FIXME we should probably be raising an exception here*/
6932         str = mono_metadata_user_string (image, idx);
6933
6934         len2 = mono_metadata_decode_blob_size (str, &str);
6935         len2 >>= 1;
6936
6937         as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6938         if (gerror) {
6939                 mono_error_set_argument (error, "string", "%s", gerror->message);
6940                 g_error_free (gerror);
6941                 return NULL;
6942         }
6943         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6944         if (len2 > written) {
6945                 /* allocate the total length and copy the part of the string that has been converted */
6946                 char *as2 = (char *)g_malloc0 (len2);
6947                 memcpy (as2, as, written);
6948                 g_free (as);
6949                 as = as2;
6950         }
6951
6952         return as;
6953 }
6954
6955 /**
6956  * mono_string_to_utf8:
6957  * @s: a System.String
6958  *
6959  * Returns the UTF8 representation for @s.
6960  * The resulting buffer needs to be freed with mono_free().
6961  *
6962  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6963  */
6964 char *
6965 mono_string_to_utf8 (MonoString *s)
6966 {
6967         MONO_REQ_GC_UNSAFE_MODE;
6968
6969         MonoError error;
6970         char *result = mono_string_to_utf8_checked (s, &error);
6971         
6972         if (!is_ok (&error)) {
6973                 mono_error_cleanup (&error);
6974                 return NULL;
6975         }
6976         return result;
6977 }
6978
6979 /**
6980  * mono_string_to_utf8_checked:
6981  * @s: a System.String
6982  * @error: a MonoError.
6983  * 
6984  * Converts a MonoString to its UTF8 representation. May fail; check 
6985  * @error to determine whether the conversion was successful.
6986  * The resulting buffer should be freed with mono_free().
6987  */
6988 char *
6989 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6990 {
6991         MONO_REQ_GC_UNSAFE_MODE;
6992
6993         long written = 0;
6994         char *as;
6995         GError *gerror = NULL;
6996
6997         mono_error_init (error);
6998
6999         if (s == NULL)
7000                 return NULL;
7001
7002         if (!s->length)
7003                 return g_strdup ("");
7004
7005         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7006         if (gerror) {
7007                 mono_error_set_argument (error, "string", "%s", gerror->message);
7008                 g_error_free (gerror);
7009                 return NULL;
7010         }
7011         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7012         if (s->length > written) {
7013                 /* allocate the total length and copy the part of the string that has been converted */
7014                 char *as2 = (char *)g_malloc0 (s->length);
7015                 memcpy (as2, as, written);
7016                 g_free (as);
7017                 as = as2;
7018         }
7019
7020         return as;
7021 }
7022
7023 char *
7024 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7025 {
7026         return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7027 }
7028
7029 /**
7030  * mono_string_to_utf8_ignore:
7031  * @s: a MonoString
7032  *
7033  * Converts a MonoString to its UTF8 representation. Will ignore
7034  * invalid surrogate pairs.
7035  * The resulting buffer should be freed with mono_free().
7036  * 
7037  */
7038 char *
7039 mono_string_to_utf8_ignore (MonoString *s)
7040 {
7041         MONO_REQ_GC_UNSAFE_MODE;
7042
7043         long written = 0;
7044         char *as;
7045
7046         if (s == NULL)
7047                 return NULL;
7048
7049         if (!s->length)
7050                 return g_strdup ("");
7051
7052         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7053
7054         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7055         if (s->length > written) {
7056                 /* allocate the total length and copy the part of the string that has been converted */
7057                 char *as2 = (char *)g_malloc0 (s->length);
7058                 memcpy (as2, as, written);
7059                 g_free (as);
7060                 as = as2;
7061         }
7062
7063         return as;
7064 }
7065
7066 /**
7067  * mono_string_to_utf8_image_ignore:
7068  * @s: a System.String
7069  *
7070  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7071  */
7072 char *
7073 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7074 {
7075         MONO_REQ_GC_UNSAFE_MODE;
7076
7077         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7078 }
7079
7080 /**
7081  * mono_string_to_utf8_mp_ignore:
7082  * @s: a System.String
7083  *
7084  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7085  */
7086 char *
7087 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7088 {
7089         MONO_REQ_GC_UNSAFE_MODE;
7090
7091         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7092 }
7093
7094
7095 /**
7096  * mono_string_to_utf16:
7097  * @s: a MonoString
7098  *
7099  * Return an null-terminated array of the utf-16 chars
7100  * contained in @s. The result must be freed with g_free().
7101  * This is a temporary helper until our string implementation
7102  * is reworked to always include the null terminating char.
7103  */
7104 mono_unichar2*
7105 mono_string_to_utf16 (MonoString *s)
7106 {
7107         MONO_REQ_GC_UNSAFE_MODE;
7108
7109         char *as;
7110
7111         if (s == NULL)
7112                 return NULL;
7113
7114         as = (char *)g_malloc ((s->length * 2) + 2);
7115         as [(s->length * 2)] = '\0';
7116         as [(s->length * 2) + 1] = '\0';
7117
7118         if (!s->length) {
7119                 return (gunichar2 *)(as);
7120         }
7121         
7122         memcpy (as, mono_string_chars(s), s->length * 2);
7123         return (gunichar2 *)(as);
7124 }
7125
7126 /**
7127  * mono_string_to_utf32:
7128  * @s: a MonoString
7129  *
7130  * Return an null-terminated array of the UTF-32 (UCS-4) chars
7131  * contained in @s. The result must be freed with g_free().
7132  */
7133 mono_unichar4*
7134 mono_string_to_utf32 (MonoString *s)
7135 {
7136         MONO_REQ_GC_UNSAFE_MODE;
7137
7138         mono_unichar4 *utf32_output = NULL; 
7139         GError *error = NULL;
7140         glong items_written;
7141         
7142         if (s == NULL)
7143                 return NULL;
7144                 
7145         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7146         
7147         if (error)
7148                 g_error_free (error);
7149
7150         return utf32_output;
7151 }
7152
7153 /**
7154  * mono_string_from_utf16:
7155  * @data: the UTF16 string (LPWSTR) to convert
7156  *
7157  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7158  *
7159  * Returns: a MonoString.
7160  */
7161 MonoString *
7162 mono_string_from_utf16 (gunichar2 *data)
7163 {
7164         MonoError error;
7165         MonoString *result = mono_string_from_utf16_checked (data, &error);
7166         mono_error_cleanup (&error);
7167         return result;
7168 }
7169
7170 /**
7171  * mono_string_from_utf16_checked:
7172  * @data: the UTF16 string (LPWSTR) to convert
7173  * @error: set on error
7174  *
7175  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7176  *
7177  * Returns: a MonoString. On failure sets @error and returns NULL.
7178  */
7179 MonoString *
7180 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7181 {
7182
7183         MONO_REQ_GC_UNSAFE_MODE;
7184
7185         mono_error_init (error);
7186         MonoDomain *domain = mono_domain_get ();
7187         int len = 0;
7188
7189         if (!data)
7190                 return NULL;
7191
7192         while (data [len]) len++;
7193
7194         return mono_string_new_utf16_checked (domain, data, len, error);
7195 }
7196
7197 /**
7198  * mono_string_from_utf32:
7199  * @data: the UTF32 string (LPWSTR) to convert
7200  *
7201  * Converts a UTF32 (UCS-4)to a MonoString.
7202  *
7203  * Returns: a MonoString.
7204  */
7205 MonoString *
7206 mono_string_from_utf32 (mono_unichar4 *data)
7207 {
7208         MonoError error;
7209         MonoString *result = mono_string_from_utf32_checked (data, &error);
7210         mono_error_cleanup (&error);
7211         return result;
7212 }
7213
7214 /**
7215  * mono_string_from_utf32_checked:
7216  * @data: the UTF32 string (LPWSTR) to convert
7217  * @error: set on error
7218  *
7219  * Converts a UTF32 (UCS-4)to a MonoString.
7220  *
7221  * Returns: a MonoString. On failure returns NULL and sets @error.
7222  */
7223 MonoString *
7224 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7225 {
7226         MONO_REQ_GC_UNSAFE_MODE;
7227
7228         mono_error_init (error);
7229         MonoString* result = NULL;
7230         mono_unichar2 *utf16_output = NULL;
7231         GError *gerror = NULL;
7232         glong items_written;
7233         int len = 0;
7234
7235         if (!data)
7236                 return NULL;
7237
7238         while (data [len]) len++;
7239
7240         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7241
7242         if (gerror)
7243                 g_error_free (gerror);
7244
7245         result = mono_string_from_utf16_checked (utf16_output, error);
7246         g_free (utf16_output);
7247         return result;
7248 }
7249
7250 static char *
7251 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7252 {
7253         MONO_REQ_GC_UNSAFE_MODE;
7254
7255         char *r;
7256         char *mp_s;
7257         int len;
7258
7259         if (ignore_error) {
7260                 r = mono_string_to_utf8_ignore (s);
7261         } else {
7262                 r = mono_string_to_utf8_checked (s, error);
7263                 if (!mono_error_ok (error))
7264                         return NULL;
7265         }
7266
7267         if (!mp && !image)
7268                 return r;
7269
7270         len = strlen (r) + 1;
7271         if (mp)
7272                 mp_s = (char *)mono_mempool_alloc (mp, len);
7273         else
7274                 mp_s = (char *)mono_image_alloc (image, len);
7275
7276         memcpy (mp_s, r, len);
7277
7278         g_free (r);
7279
7280         return mp_s;
7281 }
7282
7283 /**
7284  * mono_string_to_utf8_image:
7285  * @s: a System.String
7286  *
7287  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7288  */
7289 char *
7290 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7291 {
7292         MONO_REQ_GC_UNSAFE_MODE;
7293
7294         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7295 }
7296
7297 /**
7298  * mono_string_to_utf8_mp:
7299  * @s: a System.String
7300  *
7301  * Same as mono_string_to_utf8, but allocate the string from a mempool.
7302  */
7303 char *
7304 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7305 {
7306         MONO_REQ_GC_UNSAFE_MODE;
7307
7308         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7309 }
7310
7311
7312 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7313
7314 void
7315 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7316 {
7317         eh_callbacks = *cbs;
7318 }
7319
7320 MonoRuntimeExceptionHandlingCallbacks *
7321 mono_get_eh_callbacks (void)
7322 {
7323         return &eh_callbacks;
7324 }
7325
7326 /**
7327  * mono_raise_exception:
7328  * @ex: exception object
7329  *
7330  * Signal the runtime that the exception @ex has been raised in unmanaged code.
7331  */
7332 void
7333 mono_raise_exception (MonoException *ex) 
7334 {
7335         MONO_REQ_GC_UNSAFE_MODE;
7336
7337         /*
7338          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7339          * that will cause gcc to omit the function epilog, causing problems when
7340          * the JIT tries to walk the stack, since the return address on the stack
7341          * will point into the next function in the executable, not this one.
7342          */     
7343         eh_callbacks.mono_raise_exception (ex);
7344 }
7345
7346 void
7347 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
7348 {
7349         MONO_REQ_GC_UNSAFE_MODE;
7350
7351         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7352 }
7353
7354 /**
7355  * mono_wait_handle_new:
7356  * @domain: Domain where the object will be created
7357  * @handle: Handle for the wait handle
7358  * @error: set on error.
7359  *
7360  * Returns: A new MonoWaitHandle created in the given domain for the
7361  * given handle.  On failure returns NULL and sets @rror.
7362  */
7363 MonoWaitHandle *
7364 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7365 {
7366         MONO_REQ_GC_UNSAFE_MODE;
7367
7368         MonoWaitHandle *res;
7369         gpointer params [1];
7370         static MonoMethod *handle_set;
7371
7372         mono_error_init (error);
7373         res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7374         return_val_if_nok (error, NULL);
7375
7376         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
7377         if (!handle_set)
7378                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7379
7380         params [0] = &handle;
7381
7382         mono_runtime_invoke_checked (handle_set, res, params, error);
7383         return res;
7384 }
7385
7386 HANDLE
7387 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7388 {
7389         MONO_REQ_GC_UNSAFE_MODE;
7390
7391         static MonoClassField *f_safe_handle = NULL;
7392         MonoSafeHandle *sh;
7393
7394         if (!f_safe_handle) {
7395                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7396                 g_assert (f_safe_handle);
7397         }
7398
7399         mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7400         return sh->handle;
7401 }
7402
7403
7404 static MonoObject*
7405 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7406 {
7407         MONO_REQ_GC_UNSAFE_MODE;
7408
7409         RuntimeInvokeFunction runtime_invoke;
7410
7411         mono_error_init (error);
7412
7413         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7414                 MonoMethod *method = mono_get_context_capture_method ();
7415                 MonoMethod *wrapper;
7416                 if (!method)
7417                         return NULL;
7418                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7419                 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7420                 return_val_if_nok (error, NULL);
7421                 domain->capture_context_method = mono_compile_method_checked (method, error);
7422                 return_val_if_nok (error, NULL);
7423         }
7424
7425         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7426
7427         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7428 }
7429 /**
7430  * mono_async_result_new:
7431  * @domain:domain where the object will be created.
7432  * @handle: wait handle.
7433  * @state: state to pass to AsyncResult
7434  * @data: C closure data.
7435  * @error: set on error.
7436  *
7437  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7438  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7439  * On failure returns NULL and sets @error.
7440  *
7441  */
7442 MonoAsyncResult *
7443 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7444 {
7445         MONO_REQ_GC_UNSAFE_MODE;
7446
7447         mono_error_init (error);
7448         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7449         return_val_if_nok (error, NULL);
7450         MonoObject *context = mono_runtime_capture_context (domain, error);
7451         return_val_if_nok (error, NULL);
7452         /* we must capture the execution context from the original thread */
7453         if (context) {
7454                 MONO_OBJECT_SETREF (res, execution_context, context);
7455                 /* note: result may be null if the flow is suppressed */
7456         }
7457
7458         res->data = (void **)data;
7459         MONO_OBJECT_SETREF (res, object_data, object_data);
7460         MONO_OBJECT_SETREF (res, async_state, state);
7461         MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7462         return_val_if_nok (error, NULL);
7463         if (handle != NULL)
7464                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7465
7466         res->sync_completed = FALSE;
7467         res->completed = FALSE;
7468
7469         return res;
7470 }
7471
7472 MonoObject *
7473 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7474 {
7475         MONO_REQ_GC_UNSAFE_MODE;
7476
7477         MonoError error;
7478         MonoAsyncCall *ac;
7479         MonoObject *res;
7480
7481         g_assert (ares);
7482         g_assert (ares->async_delegate);
7483
7484         ac = (MonoAsyncCall*) ares->object_data;
7485         if (!ac) {
7486                 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7487                 if (mono_error_set_pending_exception (&error))
7488                         return NULL;
7489         } else {
7490                 gpointer wait_event = NULL;
7491
7492                 ac->msg->exc = NULL;
7493
7494                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7495
7496                 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7497                 mono_threads_begin_abort_protected_block ();
7498
7499                 if (!ac->msg->exc) {
7500                         MonoException *ex = mono_error_convert_to_exception (&error);
7501                         ac->msg->exc = (MonoObject *)ex;
7502                 } else {
7503                         mono_error_cleanup (&error);
7504                 }
7505
7506                 MONO_OBJECT_SETREF (ac, res, res);
7507
7508                 mono_monitor_enter ((MonoObject*) ares);
7509                 ares->completed = 1;
7510                 if (ares->handle)
7511                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7512                 mono_monitor_exit ((MonoObject*) ares);
7513
7514                 if (wait_event != NULL)
7515                         mono_w32event_set (wait_event);
7516
7517                 mono_error_init (&error); //the else branch would leave it in an undefined state
7518                 if (ac->cb_method)
7519                         mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7520
7521                 mono_threads_end_abort_protected_block ();
7522
7523                 if (mono_error_set_pending_exception (&error))
7524                         return NULL;
7525         }
7526
7527         return res;
7528 }
7529
7530 gboolean
7531 mono_message_init (MonoDomain *domain,
7532                    MonoMethodMessage *this_obj, 
7533                    MonoReflectionMethod *method,
7534                    MonoArray *out_args,
7535                    MonoError *error)
7536 {
7537         MONO_REQ_GC_UNSAFE_MODE;
7538
7539         static MonoMethod *init_message_method = NULL;
7540
7541         if (!init_message_method) {
7542                 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7543                 g_assert (init_message_method != NULL);
7544         }
7545
7546         mono_error_init (error);
7547         /* FIXME set domain instead? */
7548         g_assert (domain == mono_domain_get ());
7549         
7550         gpointer args[2];
7551
7552         args[0] = method;
7553         args[1] = out_args;
7554
7555         mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7556         return is_ok (error);
7557 }
7558
7559 #ifndef DISABLE_REMOTING
7560 /**
7561  * mono_remoting_invoke:
7562  * @real_proxy: pointer to a RealProxy object
7563  * @msg: The MonoMethodMessage to execute
7564  * @exc: used to store exceptions
7565  * @out_args: used to store output arguments
7566  *
7567  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7568  * IMessage interface and it is not trivial to extract results from there. So
7569  * we call an helper method PrivateInvoke instead of calling
7570  * RealProxy::Invoke() directly.
7571  *
7572  * Returns: the result object.
7573  */
7574 MonoObject *
7575 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7576 {
7577         MONO_REQ_GC_UNSAFE_MODE;
7578
7579         MonoObject *o;
7580         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7581         gpointer pa [4];
7582
7583         g_assert (exc);
7584
7585         mono_error_init (error);
7586
7587         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7588
7589         if (!im) {
7590                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7591                 if (!im) {
7592                         mono_error_set_not_supported (error, "Linked away.");
7593                         return NULL;
7594                 }
7595                 real_proxy->vtable->domain->private_invoke_method = im;
7596         }
7597
7598         pa [0] = real_proxy;
7599         pa [1] = msg;
7600         pa [2] = exc;
7601         pa [3] = out_args;
7602
7603         o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7604         return_val_if_nok (error, NULL);
7605
7606         return o;
7607 }
7608 #endif
7609
7610 MonoObject *
7611 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
7612                      MonoObject **exc, MonoArray **out_args, MonoError *error) 
7613 {
7614         MONO_REQ_GC_UNSAFE_MODE;
7615
7616         static MonoClass *object_array_klass;
7617         mono_error_init (error);
7618
7619         MonoDomain *domain; 
7620         MonoMethod *method;
7621         MonoMethodSignature *sig;
7622         MonoArray *arr;
7623         int i, j, outarg_count = 0;
7624
7625 #ifndef DISABLE_REMOTING
7626         if (target && mono_object_is_transparent_proxy (target)) {
7627                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7628                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7629                         target = tp->rp->unwrapped_server;
7630                 } else {
7631                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7632                 }
7633         }
7634 #endif
7635
7636         domain = mono_domain_get (); 
7637         method = msg->method->method;
7638         sig = mono_method_signature (method);
7639
7640         for (i = 0; i < sig->param_count; i++) {
7641                 if (sig->params [i]->byref) 
7642                         outarg_count++;
7643         }
7644
7645         if (!object_array_klass) {
7646                 MonoClass *klass;
7647
7648                 klass = mono_array_class_get (mono_defaults.object_class, 1);
7649                 g_assert (klass);
7650
7651                 mono_memory_barrier ();
7652                 object_array_klass = klass;
7653         }
7654
7655         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7656         return_val_if_nok (error, NULL);
7657
7658         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7659         *exc = NULL;
7660
7661         MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7662         return_val_if_nok (error, NULL);
7663
7664         for (i = 0, j = 0; i < sig->param_count; i++) {
7665                 if (sig->params [i]->byref) {
7666                         MonoObject* arg;
7667                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7668                         mono_array_setref (*out_args, j, arg);
7669                         j++;
7670                 }
7671         }
7672
7673         return ret;
7674 }
7675
7676 /**
7677  * prepare_to_string_method:
7678  * @obj: The object
7679  * @target: Set to @obj or unboxed value if a valuetype
7680  *
7681  * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7682  */
7683 static MonoMethod *
7684 prepare_to_string_method (MonoObject *obj, void **target)
7685 {
7686         MONO_REQ_GC_UNSAFE_MODE;
7687
7688         static MonoMethod *to_string = NULL;
7689         MonoMethod *method;
7690         g_assert (target);
7691         g_assert (obj);
7692
7693         *target = obj;
7694
7695         if (!to_string)
7696                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7697
7698         method = mono_object_get_virtual_method (obj, to_string);
7699
7700         // Unbox value type if needed
7701         if (mono_class_is_valuetype (mono_method_get_class (method))) {
7702                 *target = mono_object_unbox (obj);
7703         }
7704         return method;
7705 }
7706
7707 /**
7708  * mono_object_to_string:
7709  * @obj: The object
7710  * @exc: Any exception thrown by ToString (). May be NULL.
7711  *
7712  * Returns: the result of calling ToString () on an object.
7713  */
7714 MonoString *
7715 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7716 {
7717         MonoError error;
7718         MonoString *s = NULL;
7719         void *target;
7720         MonoMethod *method = prepare_to_string_method (obj, &target);
7721         if (exc) {
7722                 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7723                 if (*exc == NULL && !mono_error_ok (&error))
7724                         *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7725                 else
7726                         mono_error_cleanup (&error);
7727         } else {
7728                 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7729                 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7730         }
7731
7732         return s;
7733 }
7734
7735 /**
7736  * mono_object_to_string_checked:
7737  * @obj: The object
7738  * @error: Set on error.
7739  *
7740  * Returns: the result of calling ToString () on an object. If the
7741  * method cannot be invoked or if it raises an exception, sets @error
7742  * and returns NULL.
7743  */
7744 MonoString *
7745 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7746 {
7747         mono_error_init (error);
7748         void *target;
7749         MonoMethod *method = prepare_to_string_method (obj, &target);
7750         return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7751 }
7752
7753 /**
7754  * mono_object_try_to_string:
7755  * @obj: The object
7756  * @exc: Any exception thrown by ToString (). Must not be NULL.
7757  * @error: Set if method cannot be invoked.
7758  *
7759  * Returns: the result of calling ToString () on an object. If the
7760  * method cannot be invoked sets @error, if it raises an exception sets @exc,
7761  * and returns NULL.
7762  */
7763 MonoString *
7764 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7765 {
7766         g_assert (exc);
7767         mono_error_init (error);
7768         void *target;
7769         MonoMethod *method = prepare_to_string_method (obj, &target);
7770         return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7771 }
7772
7773
7774
7775 static char *
7776 get_native_backtrace (MonoException *exc_raw)
7777 {
7778         HANDLE_FUNCTION_ENTER ();
7779         MONO_HANDLE_DCL(MonoException, exc);
7780         char * trace = mono_exception_handle_get_native_backtrace (exc);
7781         HANDLE_FUNCTION_RETURN_VAL (trace);
7782 }
7783
7784 /**
7785  * mono_print_unhandled_exception:
7786  * @exc: The exception
7787  *
7788  * Prints the unhandled exception.
7789  */
7790 void
7791 mono_print_unhandled_exception (MonoObject *exc)
7792 {
7793         MONO_REQ_GC_UNSAFE_MODE;
7794
7795         MonoString * str;
7796         char *message = (char*)"";
7797         gboolean free_message = FALSE;
7798         MonoError error;
7799
7800         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7801                 message = g_strdup ("OutOfMemoryException");
7802                 free_message = TRUE;
7803         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7804                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7805                 free_message = TRUE;
7806         } else {
7807                 
7808                 if (((MonoException*)exc)->native_trace_ips) {
7809                         message = get_native_backtrace ((MonoException*)exc);
7810                         free_message = TRUE;
7811                 } else {
7812                         MonoObject *other_exc = NULL;
7813                         str = mono_object_try_to_string (exc, &other_exc, &error);
7814                         if (other_exc == NULL && !is_ok (&error))
7815                                 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7816                         else
7817                                 mono_error_cleanup (&error);
7818                         if (other_exc) {
7819                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7820                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7821                                 
7822                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7823                                         original_backtrace, nested_backtrace);
7824
7825                                 g_free (original_backtrace);
7826                                 g_free (nested_backtrace);
7827                                 free_message = TRUE;
7828                         } else if (str) {
7829                                 message = mono_string_to_utf8_checked (str, &error);
7830                                 if (!mono_error_ok (&error)) {
7831                                         mono_error_cleanup (&error);
7832                                         message = (char *) "";
7833                                 } else {
7834                                         free_message = TRUE;
7835                                 }
7836                         }
7837                 }
7838         }
7839
7840         /*
7841          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
7842          *         exc->vtable->klass->name, message);
7843          */
7844         g_printerr ("\nUnhandled Exception:\n%s\n", message);
7845         
7846         if (free_message)
7847                 g_free (message);
7848 }
7849
7850 /**
7851  * mono_delegate_ctor_with_method:
7852  * @this: pointer to an uninitialized delegate object
7853  * @target: target object
7854  * @addr: pointer to native code
7855  * @method: method
7856  * @error: set on error.
7857  *
7858  * Initialize a delegate and sets a specific method, not the one
7859  * associated with addr.  This is useful when sharing generic code.
7860  * In that case addr will most probably not be associated with the
7861  * correct instantiation of the method.
7862  * On failure returns FALSE and sets @error.
7863  */
7864 gboolean
7865 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7866 {
7867         MONO_REQ_GC_UNSAFE_MODE;
7868
7869         mono_error_init (error);
7870         MonoDelegate *delegate = (MonoDelegate *)this_obj;
7871
7872         g_assert (this_obj);
7873         g_assert (addr);
7874
7875         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7876
7877         if (method)
7878                 delegate->method = method;
7879
7880         mono_stats.delegate_creations++;
7881
7882 #ifndef DISABLE_REMOTING
7883         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7884                 g_assert (method);
7885                 method = mono_marshal_get_remoting_invoke (method);
7886                 delegate->method_ptr = mono_compile_method_checked (method, error);
7887                 return_val_if_nok (error, FALSE);
7888                 MONO_OBJECT_SETREF (delegate, target, target);
7889         } else
7890 #endif
7891         {
7892                 delegate->method_ptr = addr;
7893                 MONO_OBJECT_SETREF (delegate, target, target);
7894         }
7895
7896         delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7897         if (callbacks.init_delegate)
7898                 callbacks.init_delegate (delegate);
7899         return TRUE;
7900 }
7901
7902 /**
7903  * mono_delegate_ctor:
7904  * @this: pointer to an uninitialized delegate object
7905  * @target: target object
7906  * @addr: pointer to native code
7907  * @error: set on error.
7908  *
7909  * This is used to initialize a delegate.
7910  * On failure returns FALSE and sets @error.
7911  */
7912 gboolean
7913 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7914 {
7915         MONO_REQ_GC_UNSAFE_MODE;
7916
7917         mono_error_init (error);
7918         MonoDomain *domain = mono_domain_get ();
7919         MonoJitInfo *ji;
7920         MonoMethod *method = NULL;
7921
7922         g_assert (addr);
7923
7924         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7925         /* Shared code */
7926         if (!ji && domain != mono_get_root_domain ())
7927                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7928         if (ji) {
7929                 method = mono_jit_info_get_method (ji);
7930                 g_assert (!mono_class_is_gtd (method->klass));
7931         }
7932
7933         return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7934 }
7935
7936 /**
7937  * mono_method_call_message_new:
7938  * @method: method to encapsulate
7939  * @params: parameters to the method
7940  * @invoke: optional, delegate invoke.
7941  * @cb: async callback delegate.
7942  * @state: state passed to the async callback.
7943  * @error: set on error.
7944  *
7945  * Translates arguments pointers into a MonoMethodMessage.
7946  * On failure returns NULL and sets @error.
7947  */
7948 MonoMethodMessage *
7949 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
7950                               MonoDelegate **cb, MonoObject **state, MonoError *error)
7951 {
7952         MONO_REQ_GC_UNSAFE_MODE;
7953
7954         mono_error_init (error);
7955
7956         MonoDomain *domain = mono_domain_get ();
7957         MonoMethodSignature *sig = mono_method_signature (method);
7958         MonoMethodMessage *msg;
7959         int i, count;
7960
7961         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error); 
7962         return_val_if_nok  (error, NULL);
7963
7964         if (invoke) {
7965                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7966                 return_val_if_nok (error, NULL);
7967                 mono_message_init (domain, msg, rm, NULL, error);
7968                 return_val_if_nok (error, NULL);
7969                 count =  sig->param_count - 2;
7970         } else {
7971                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7972                 return_val_if_nok (error, NULL);
7973                 mono_message_init (domain, msg, rm, NULL, error);
7974                 return_val_if_nok (error, NULL);
7975                 count =  sig->param_count;
7976         }
7977
7978         for (i = 0; i < count; i++) {
7979                 gpointer vpos;
7980                 MonoClass *klass;
7981                 MonoObject *arg;
7982
7983                 if (sig->params [i]->byref)
7984                         vpos = *((gpointer *)params [i]);
7985                 else 
7986                         vpos = params [i];
7987
7988                 klass = mono_class_from_mono_type (sig->params [i]);
7989
7990                 if (klass->valuetype) {
7991                         arg = mono_value_box_checked (domain, klass, vpos, error);
7992                         return_val_if_nok (error, NULL);
7993                 } else 
7994                         arg = *((MonoObject **)vpos);
7995                       
7996                 mono_array_setref (msg->args, i, arg);
7997         }
7998
7999         if (cb != NULL && state != NULL) {
8000                 *cb = *((MonoDelegate **)params [i]);
8001                 i++;
8002                 *state = *((MonoObject **)params [i]);
8003         }
8004
8005         return msg;
8006 }
8007
8008 /**
8009  * mono_method_return_message_restore:
8010  *
8011  * Restore results from message based processing back to arguments pointers
8012  */
8013 void
8014 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8015 {
8016         MONO_REQ_GC_UNSAFE_MODE;
8017
8018         mono_error_init (error);
8019
8020         MonoMethodSignature *sig = mono_method_signature (method);
8021         int i, j, type, size, out_len;
8022         
8023         if (out_args == NULL)
8024                 return;
8025         out_len = mono_array_length (out_args);
8026         if (out_len == 0)
8027                 return;
8028
8029         for (i = 0, j = 0; i < sig->param_count; i++) {
8030                 MonoType *pt = sig->params [i];
8031
8032                 if (pt->byref) {
8033                         char *arg;
8034                         if (j >= out_len) {
8035                                 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8036                                 return;
8037                         }
8038
8039                         arg = (char *)mono_array_get (out_args, gpointer, j);
8040                         type = pt->type;
8041
8042                         g_assert (type != MONO_TYPE_VOID);
8043
8044                         if (MONO_TYPE_IS_REFERENCE (pt)) {
8045                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8046                         } else {
8047                                 if (arg) {
8048                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8049                                         size = mono_class_value_size (klass, NULL);
8050                                         if (klass->has_references)
8051                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8052                                         else
8053                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8054                                 } else {
8055                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8056                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8057                                 }
8058                         }
8059
8060                         j++;
8061                 }
8062         }
8063 }
8064
8065 #ifndef DISABLE_REMOTING
8066
8067 /**
8068  * mono_load_remote_field:
8069  * @this: pointer to an object
8070  * @klass: klass of the object containing @field
8071  * @field: the field to load
8072  * @res: a storage to store the result
8073  *
8074  * This method is called by the runtime on attempts to load fields of
8075  * transparent proxy objects. @this points to such TP, @klass is the class of
8076  * the object containing @field. @res is a storage location which can be
8077  * used to store the result.
8078  *
8079  * Returns: an address pointing to the value of field.
8080  */
8081 gpointer
8082 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8083 {
8084         MonoError error;
8085         gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8086         mono_error_cleanup (&error);
8087         return result;
8088 }
8089
8090 /**
8091  * mono_load_remote_field_checked:
8092  * @this: pointer to an object
8093  * @klass: klass of the object containing @field
8094  * @field: the field to load
8095  * @res: a storage to store the result
8096  * @error: set on error
8097  *
8098  * This method is called by the runtime on attempts to load fields of
8099  * transparent proxy objects. @this points to such TP, @klass is the class of
8100  * the object containing @field. @res is a storage location which can be
8101  * used to store the result.
8102  *
8103  * Returns: an address pointing to the value of field.  On failure returns NULL and sets @error.
8104  */
8105 gpointer
8106 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8107 {
8108         MONO_REQ_GC_UNSAFE_MODE;
8109
8110         static MonoMethod *getter = NULL;
8111
8112         mono_error_init (error);
8113
8114         MonoDomain *domain = mono_domain_get ();
8115         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8116         MonoClass *field_class;
8117         MonoMethodMessage *msg;
8118         MonoArray *out_args;
8119         MonoObject *exc;
8120         char* full_name;
8121
8122         g_assert (mono_object_is_transparent_proxy (this_obj));
8123         g_assert (res != NULL);
8124
8125         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8126                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8127                 return res;
8128         }
8129         
8130         if (!getter) {
8131                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8132                 if (!getter) {
8133                         mono_error_set_not_supported (error, "Linked away.");
8134                         return NULL;
8135                 }
8136         }
8137         
8138         field_class = mono_class_from_mono_type (field->type);
8139
8140         msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8141         return_val_if_nok (error, NULL);
8142         out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8143         return_val_if_nok (error, NULL);
8144         MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8145         return_val_if_nok (error, NULL);
8146         mono_message_init (domain, msg, rm, out_args, error);
8147         return_val_if_nok (error, NULL);
8148
8149         full_name = mono_type_get_full_name (klass);
8150         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8151         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8152         g_free (full_name);
8153
8154         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8155         return_val_if_nok (error, NULL);
8156
8157         if (exc) {
8158                 mono_error_set_exception_instance (error, (MonoException *)exc);
8159                 return NULL;
8160         }
8161
8162         if (mono_array_length (out_args) == 0)
8163                 return NULL;
8164
8165         mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8166
8167         if (field_class->valuetype) {
8168                 return ((char *)*res) + sizeof (MonoObject);
8169         } else
8170                 return res;
8171 }
8172
8173 /**
8174  * mono_load_remote_field_new:
8175  * @this: 
8176  * @klass: 
8177  * @field:
8178  *
8179  * Missing documentation.
8180  */
8181 MonoObject *
8182 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8183 {
8184         MonoError error;
8185
8186         MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8187         mono_error_cleanup (&error);
8188         return result;
8189 }
8190
8191 /**
8192  * mono_load_remote_field_new_checked:
8193  * @this: pointer to an object
8194  * @klass: klass of the object containing @field
8195  * @field: the field to load
8196  * @error: set on error.
8197  *
8198  * This method is called by the runtime on attempts to load fields of
8199  * transparent proxy objects. @this points to such TP, @klass is the class of
8200  * the object containing @field.
8201  * 
8202  * Returns: a freshly allocated object containing the value of the field.  On failure returns NULL and sets @error.
8203  */
8204 MonoObject *
8205 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8206 {
8207         MONO_REQ_GC_UNSAFE_MODE;
8208
8209         mono_error_init (error);
8210
8211         static MonoMethod *tp_load = NULL;
8212
8213         g_assert (mono_object_is_transparent_proxy (this_obj));
8214
8215         if (!tp_load) {
8216                 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8217                 if (!tp_load) {
8218                         mono_error_set_not_supported (error, "Linked away.");
8219                         return NULL;
8220                 }
8221         }
8222         
8223         /* MonoType *type = mono_class_get_type (klass); */
8224
8225         gpointer args[2];
8226         args [0] = &klass;
8227         args [1] = &field;
8228
8229         return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8230 }
8231
8232 /**
8233  * mono_store_remote_field:
8234  * @this_obj: pointer to an object
8235  * @klass: klass of the object containing @field
8236  * @field: the field to load
8237  * @val: the value/object to store
8238  *
8239  * This method is called by the runtime on attempts to store fields of
8240  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8241  * the object containing @field. @val is the new value to store in @field.
8242  */
8243 void
8244 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8245 {
8246         MonoError error;
8247         (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8248         mono_error_cleanup (&error);
8249 }
8250
8251 /**
8252  * mono_store_remote_field_checked:
8253  * @this_obj: pointer to an object
8254  * @klass: klass of the object containing @field
8255  * @field: the field to load
8256  * @val: the value/object to store
8257  * @error: set on error
8258  *
8259  * This method is called by the runtime on attempts to store fields of
8260  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8261  * the object containing @field. @val is the new value to store in @field.
8262  *
8263  * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8264  */
8265 gboolean
8266 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8267 {
8268         
8269         MONO_REQ_GC_UNSAFE_MODE;
8270
8271         mono_error_init (error);
8272
8273         MonoDomain *domain = mono_domain_get ();
8274         MonoClass *field_class;
8275         MonoObject *arg;
8276
8277         g_assert (mono_object_is_transparent_proxy (this_obj));
8278
8279         field_class = mono_class_from_mono_type (field->type);
8280
8281         if (field_class->valuetype) {
8282                 arg = mono_value_box_checked (domain, field_class, val, error);
8283                 return_val_if_nok (error, FALSE);
8284         } else {
8285                 arg = *((MonoObject**)val);
8286         }
8287
8288         return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8289 }
8290
8291 /**
8292  * mono_store_remote_field_new:
8293  * @this_obj:
8294  * @klass:
8295  * @field:
8296  * @arg:
8297  *
8298  * Missing documentation
8299  */
8300 void
8301 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8302 {
8303         MonoError error;
8304         (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8305         mono_error_cleanup (&error);
8306 }
8307
8308 /**
8309  * mono_store_remote_field_new_checked:
8310  * @this_obj:
8311  * @klass:
8312  * @field:
8313  * @arg:
8314  * @error:
8315  *
8316  * Missing documentation
8317  */
8318 gboolean
8319 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8320 {
8321         MONO_REQ_GC_UNSAFE_MODE;
8322
8323         static MonoMethod *tp_store = NULL;
8324
8325         mono_error_init (error);
8326
8327         g_assert (mono_object_is_transparent_proxy (this_obj));
8328
8329         if (!tp_store) {
8330                 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8331                 if (!tp_store) {
8332                         mono_error_set_not_supported (error, "Linked away.");
8333                         return FALSE;
8334                 }
8335         }
8336
8337         gpointer args[3];
8338         args [0] = &klass;
8339         args [1] = &field;
8340         args [2] = arg;
8341
8342         mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8343         return is_ok (error);
8344 }
8345 #endif
8346
8347 /*
8348  * mono_create_ftnptr:
8349  *
8350  *   Given a function address, create a function descriptor for it.
8351  * This is only needed on some platforms.
8352  */
8353 gpointer
8354 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8355 {
8356         return callbacks.create_ftnptr (domain, addr);
8357 }
8358
8359 /*
8360  * mono_get_addr_from_ftnptr:
8361  *
8362  *   Given a pointer to a function descriptor, return the function address.
8363  * This is only needed on some platforms.
8364  */
8365 gpointer
8366 mono_get_addr_from_ftnptr (gpointer descr)
8367 {
8368         return callbacks.get_addr_from_ftnptr (descr);
8369 }       
8370
8371 /**
8372  * mono_string_chars:
8373  * @s: a MonoString
8374  *
8375  * Returns a pointer to the UCS16 characters stored in the MonoString
8376  */
8377 gunichar2 *
8378 mono_string_chars (MonoString *s)
8379 {
8380         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8381
8382         return s->chars;
8383 }
8384
8385 /**
8386  * mono_string_length:
8387  * @s: MonoString
8388  *
8389  * Returns the lenght in characters of the string
8390  */
8391 int
8392 mono_string_length (MonoString *s)
8393 {
8394         MONO_REQ_GC_UNSAFE_MODE;
8395
8396         return s->length;
8397 }
8398
8399 /**
8400  * mono_array_length:
8401  * @array: a MonoArray*
8402  *
8403  * Returns the total number of elements in the array. This works for
8404  * both vectors and multidimensional arrays.
8405  */
8406 uintptr_t
8407 mono_array_length (MonoArray *array)
8408 {
8409         MONO_REQ_GC_UNSAFE_MODE;
8410
8411         return array->max_length;
8412 }
8413
8414 /**
8415  * mono_array_addr_with_size:
8416  * @array: a MonoArray*
8417  * @size: size of the array elements
8418  * @idx: index into the array
8419  *
8420  * Use this function to obtain the address for the @idx item on the
8421  * @array containing elements of size @size.
8422  *
8423  * This method performs no bounds checking or type checking.
8424  *
8425  * Returns the address of the @idx element in the array.
8426  */
8427 char*
8428 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8429 {
8430         MONO_REQ_GC_UNSAFE_MODE;
8431
8432         return ((char*)(array)->vector) + size * idx;
8433 }
8434
8435
8436 MonoArray *
8437 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error) 
8438 {
8439         MonoDomain *domain = mono_domain_get ();
8440         MonoArray *res;
8441         int len, i;
8442
8443         mono_error_init (error);
8444         if (!list)
8445                 return NULL;
8446
8447         len = g_list_length (list);
8448         res = mono_array_new_checked (domain, eclass, len, error);
8449         return_val_if_nok (error, NULL);
8450
8451         for (i = 0; list; list = list->next, i++)
8452                 mono_array_set (res, gpointer, i, list->data);
8453
8454         return res;
8455 }
8456
8457 #if NEVER_DEFINED
8458 /*
8459  * The following section is purely to declare prototypes and
8460  * document the API, as these C files are processed by our
8461  * tool
8462  */
8463
8464 /**
8465  * mono_array_set:
8466  * @array: array to alter
8467  * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8468  * @index: index into the array
8469  * @value: value to set
8470  *
8471  * Value Type version: This sets the @index's element of the @array
8472  * with elements of size sizeof(type) to the provided @value.
8473  *
8474  * This macro does not attempt to perform type checking or bounds checking.
8475  *
8476  * Use this to set value types in a `MonoArray`.
8477  */
8478 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8479 {
8480 }
8481
8482 /**
8483  * mono_array_setref:
8484  * @array: array to alter
8485  * @index: index into the array
8486  * @value: value to set
8487  *
8488  * Reference Type version: This sets the @index's element of the
8489  * @array with elements of size sizeof(type) to the provided @value.
8490  *
8491  * This macro does not attempt to perform type checking or bounds checking.
8492  *
8493  * Use this to reference types in a `MonoArray`.
8494  */
8495 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8496 {
8497 }
8498
8499 /**
8500  * mono_array_get:
8501  * @array: array on which to operate on
8502  * @element_type: C element type (example: MonoString *, int, MonoObject *)
8503  * @index: index into the array
8504  *
8505  * Use this macro to retrieve the @index element of an @array and
8506  * extract the value assuming that the elements of the array match
8507  * the provided type value.
8508  *
8509  * This method can be used with both arrays holding value types and
8510  * reference types.   For reference types, the @type parameter should
8511  * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8512  *
8513  * This macro does not attempt to perform type checking or bounds checking.
8514  *
8515  * Returns: The element at the @index position in the @array.
8516  */
8517 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8518 {
8519 }
8520 #endif
8521