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