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