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