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