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