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