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