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