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