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