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