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