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