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