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