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