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