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