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