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