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