3838d06e3b641ca6cb05dce6d4d8b695348b1244
[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, MONO_ROOT_SOURCE_THREADING, "main thread object");
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_UNSAFE_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, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
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, MONO_ROOT_SOURCE_STATIC, "managed static variables");
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, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection 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, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection 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         MonoClassField *field;
4094         MonoDomain *current_domain, *root_domain;
4095         MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4096
4097         if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4098                 return;
4099
4100         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4101         g_assert (field);
4102
4103         current_domain = mono_domain_get ();
4104         root_domain = mono_get_root_domain ();
4105
4106         root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4107         if (current_domain != root_domain)
4108                 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4109
4110         /* set exitcode only if we will abort the process */
4111         if (!current_appdomain_delegate && !root_appdomain_delegate) {
4112                 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4113                      || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4114                 {
4115                         mono_environment_exitcode_set (1);
4116                 }
4117
4118                 mono_print_unhandled_exception (exc);
4119         } else {
4120                 if (root_appdomain_delegate)
4121                         call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4122                 if (current_appdomain_delegate)
4123                         call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4124         }
4125 }
4126
4127 /**
4128  * mono_runtime_exec_managed_code:
4129  * @domain: Application domain
4130  * @main_func: function to invoke from the execution thread
4131  * @main_args: parameter to the main_func
4132  *
4133  * Launch a new thread to execute a function
4134  *
4135  * main_func is called back from the thread with main_args as the
4136  * parameter.  The callback function is expected to start Main()
4137  * eventually.  This function then waits for all managed threads to
4138  * finish.
4139  * It is not necesseray anymore to execute managed code in a subthread,
4140  * so this function should not be used anymore by default: just
4141  * execute the code and then call mono_thread_manage ().
4142  */
4143 void
4144 mono_runtime_exec_managed_code (MonoDomain *domain,
4145                                 MonoMainThreadFunc main_func,
4146                                 gpointer main_args)
4147 {
4148         mono_thread_create (domain, main_func, main_args);
4149
4150         mono_thread_manage ();
4151 }
4152
4153 /*
4154  * Execute a standard Main() method (args doesn't contain the
4155  * executable name).
4156  */
4157 int
4158 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4159 {
4160         MONO_REQ_GC_UNSAFE_MODE;
4161
4162         MonoDomain *domain;
4163         gpointer pa [1];
4164         int rval;
4165         MonoCustomAttrInfo* cinfo;
4166         gboolean has_stathread_attribute;
4167         MonoInternalThread* thread = mono_thread_internal_current ();
4168
4169         g_assert (args);
4170
4171         pa [0] = args;
4172
4173         domain = mono_object_domain (args);
4174         if (!domain->entry_assembly) {
4175                 gchar *str;
4176                 MonoAssembly *assembly;
4177
4178                 assembly = method->klass->image->assembly;
4179                 domain->entry_assembly = assembly;
4180                 /* Domains created from another domain already have application_base and configuration_file set */
4181                 if (domain->setup->application_base == NULL) {
4182                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4183                 }
4184
4185                 if (domain->setup->configuration_file == NULL) {
4186                         str = g_strconcat (assembly->image->name, ".config", NULL);
4187                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4188                         g_free (str);
4189                         mono_set_private_bin_path_from_config (domain);
4190                 }
4191         }
4192
4193         cinfo = mono_custom_attrs_from_method (method);
4194         if (cinfo) {
4195                 static MonoClass *stathread_attribute = NULL;
4196                 if (!stathread_attribute)
4197                         stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4198                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4199                 if (!cinfo->cached)
4200                         mono_custom_attrs_free (cinfo);
4201         } else {
4202                 has_stathread_attribute = FALSE;
4203         }
4204         if (has_stathread_attribute) {
4205                 thread->apartment_state = ThreadApartmentState_STA;
4206         } else {
4207                 thread->apartment_state = ThreadApartmentState_MTA;
4208         }
4209         mono_thread_init_apartment_state ();
4210
4211         /* FIXME: check signature of method */
4212         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4213                 MonoObject *res;
4214                 res = mono_runtime_invoke (method, NULL, pa, exc);
4215                 if (!exc || !*exc)
4216                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4217                 else
4218                         rval = -1;
4219
4220                 mono_environment_exitcode_set (rval);
4221         } else {
4222                 mono_runtime_invoke (method, NULL, pa, exc);
4223                 if (!exc || !*exc)
4224                         rval = 0;
4225                 else {
4226                         /* If the return type of Main is void, only
4227                          * set the exitcode if an exception was thrown
4228                          * (we don't want to blow away an
4229                          * explicitly-set exit code)
4230                          */
4231                         rval = -1;
4232                         mono_environment_exitcode_set (rval);
4233                 }
4234         }
4235
4236         return rval;
4237 }
4238
4239 /**
4240  * mono_install_runtime_invoke:
4241  * @func: Function to install
4242  *
4243  * This is a VM internal routine
4244  */
4245 void
4246 mono_install_runtime_invoke (MonoInvokeFunc func)
4247 {
4248         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4249 }
4250
4251
4252 /**
4253  * mono_runtime_invoke_array:
4254  * @method: method to invoke
4255  * @obJ: object instance
4256  * @params: arguments to the method
4257  * @exc: exception information.
4258  *
4259  * Invokes the method represented by @method on the object @obj.
4260  *
4261  * obj is the 'this' pointer, it should be NULL for static
4262  * methods, a MonoObject* for object instances and a pointer to
4263  * the value type for value types.
4264  *
4265  * The params array contains the arguments to the method with the
4266  * same convention: MonoObject* pointers for object instances and
4267  * pointers to the value type otherwise. The _invoke_array
4268  * variant takes a C# object[] as the params argument (MonoArray
4269  * *params): in this case the value types are boxed inside the
4270  * respective reference representation.
4271  * 
4272  * From unmanaged code you'll usually use the
4273  * mono_runtime_invoke() variant.
4274  *
4275  * Note that this function doesn't handle virtual methods for
4276  * you, it will exec the exact method you pass: we still need to
4277  * expose a function to lookup the derived class implementation
4278  * of a virtual method (there are examples of this in the code,
4279  * though).
4280  * 
4281  * You can pass NULL as the exc argument if you don't want to
4282  * catch exceptions, otherwise, *exc will be set to the exception
4283  * thrown, if any.  if an exception is thrown, you can't use the
4284  * MonoObject* result from the function.
4285  * 
4286  * If the method returns a value type, it is boxed in an object
4287  * reference.
4288  */
4289 MonoObject*
4290 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4291                            MonoObject **exc)
4292 {
4293         MONO_REQ_GC_UNSAFE_MODE;
4294
4295         MonoMethodSignature *sig = mono_method_signature (method);
4296         gpointer *pa = NULL;
4297         MonoObject *res;
4298         int i;
4299         gboolean has_byref_nullables = FALSE;
4300
4301         if (NULL != params) {
4302                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4303                 for (i = 0; i < mono_array_length (params); i++) {
4304                         MonoType *t = sig->params [i];
4305
4306                 again:
4307                         switch (t->type) {
4308                         case MONO_TYPE_U1:
4309                         case MONO_TYPE_I1:
4310                         case MONO_TYPE_BOOLEAN:
4311                         case MONO_TYPE_U2:
4312                         case MONO_TYPE_I2:
4313                         case MONO_TYPE_CHAR:
4314                         case MONO_TYPE_U:
4315                         case MONO_TYPE_I:
4316                         case MONO_TYPE_U4:
4317                         case MONO_TYPE_I4:
4318                         case MONO_TYPE_U8:
4319                         case MONO_TYPE_I8:
4320                         case MONO_TYPE_R4:
4321                         case MONO_TYPE_R8:
4322                         case MONO_TYPE_VALUETYPE:
4323                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4324                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4325                                         pa [i] = mono_array_get (params, MonoObject*, i);
4326                                         if (t->byref)
4327                                                 has_byref_nullables = TRUE;
4328                                 } else {
4329                                         /* MS seems to create the objects if a null is passed in */
4330                                         if (!mono_array_get (params, MonoObject*, i))
4331                                                 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
4332
4333                                         if (t->byref) {
4334                                                 /*
4335                                                  * We can't pass the unboxed vtype byref to the callee, since
4336                                                  * that would mean the callee would be able to modify boxed
4337                                                  * primitive types. So we (and MS) make a copy of the boxed
4338                                                  * object, pass that to the callee, and replace the original
4339                                                  * boxed object in the arg array with the copy.
4340                                                  */
4341                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4342                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4343                                                 mono_array_setref (params, i, copy);
4344                                         }
4345                                                 
4346                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4347                                 }
4348                                 break;
4349                         case MONO_TYPE_STRING:
4350                         case MONO_TYPE_OBJECT:
4351                         case MONO_TYPE_CLASS:
4352                         case MONO_TYPE_ARRAY:
4353                         case MONO_TYPE_SZARRAY:
4354                                 if (t->byref)
4355                                         pa [i] = mono_array_addr (params, MonoObject*, i);
4356                                         // FIXME: I need to check this code path
4357                                 else
4358                                         pa [i] = mono_array_get (params, MonoObject*, i);
4359                                 break;
4360                         case MONO_TYPE_GENERICINST:
4361                                 if (t->byref)
4362                                         t = &t->data.generic_class->container_class->this_arg;
4363                                 else
4364                                         t = &t->data.generic_class->container_class->byval_arg;
4365                                 goto again;
4366                         case MONO_TYPE_PTR: {
4367                                 MonoObject *arg;
4368
4369                                 /* The argument should be an IntPtr */
4370                                 arg = mono_array_get (params, MonoObject*, i);
4371                                 if (arg == NULL) {
4372                                         pa [i] = NULL;
4373                                 } else {
4374                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4375                                         pa [i] = ((MonoIntPtr*)arg)->m_value;
4376                                 }
4377                                 break;
4378                         }
4379                         default:
4380                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4381                         }
4382                 }
4383         }
4384
4385         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4386                 void *o = obj;
4387
4388                 if (mono_class_is_nullable (method->klass)) {
4389                         /* Need to create a boxed vtype instead */
4390                         g_assert (!obj);
4391
4392                         if (!params)
4393                                 return NULL;
4394                         else
4395                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4396                 }
4397
4398                 if (!obj) {
4399                         obj = mono_object_new (mono_domain_get (), method->klass);
4400                         g_assert (obj); /*maybe we should raise a TLE instead?*/
4401 #ifndef DISABLE_REMOTING
4402                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4403                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4404                         }
4405 #endif
4406                         if (method->klass->valuetype)
4407                                 o = mono_object_unbox (obj);
4408                         else
4409                                 o = obj;
4410                 } else if (method->klass->valuetype) {
4411                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
4412                 }
4413
4414                 mono_runtime_invoke (method, o, pa, exc);
4415                 return obj;
4416         } else {
4417                 if (mono_class_is_nullable (method->klass)) {
4418                         MonoObject *nullable;
4419
4420                         /* Convert the unboxed vtype into a Nullable structure */
4421                         nullable = mono_object_new (mono_domain_get (), method->klass);
4422
4423                         mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4424                         obj = mono_object_unbox (nullable);
4425                 }
4426
4427                 /* obj must be already unboxed if needed */
4428                 res = mono_runtime_invoke (method, obj, pa, exc);
4429
4430                 if (sig->ret->type == MONO_TYPE_PTR) {
4431                         MonoClass *pointer_class;
4432                         static MonoMethod *box_method;
4433                         void *box_args [2];
4434                         MonoObject *box_exc;
4435
4436                         /* 
4437                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
4438                          * convert it to a Pointer object.
4439                          */
4440                         pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4441                         if (!box_method)
4442                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4443
4444                         g_assert (res->vtable->klass == mono_defaults.int_class);
4445                         box_args [0] = ((MonoIntPtr*)res)->m_value;
4446                         box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4447                         res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4448                         g_assert (!box_exc);
4449                 }
4450
4451                 if (has_byref_nullables) {
4452                         /* 
4453                          * The runtime invoke wrapper already converted byref nullables back,
4454                          * and stored them in pa, we just need to copy them back to the
4455                          * managed array.
4456                          */
4457                         for (i = 0; i < mono_array_length (params); i++) {
4458                                 MonoType *t = sig->params [i];
4459
4460                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4461                                         mono_array_setref (params, i, pa [i]);
4462                         }
4463                 }
4464
4465                 return res;
4466         }
4467 }
4468
4469 static void
4470 arith_overflow (void)
4471 {
4472         MONO_REQ_GC_UNSAFE_MODE;
4473
4474         mono_raise_exception (mono_get_exception_overflow ());
4475 }
4476
4477 /**
4478  * mono_object_new:
4479  * @klass: the class of the object that we want to create
4480  *
4481  * Returns: a newly created object whose definition is
4482  * looked up using @klass.   This will not invoke any constructors, 
4483  * so the consumer of this routine has to invoke any constructors on
4484  * its own to initialize the object.
4485  * 
4486  * It returns NULL on failure.
4487  */
4488 MonoObject *
4489 mono_object_new (MonoDomain *domain, MonoClass *klass)
4490 {
4491         MONO_REQ_GC_UNSAFE_MODE;
4492
4493         MonoVTable *vtable;
4494
4495         vtable = mono_class_vtable (domain, klass);
4496         if (!vtable)
4497                 return NULL;
4498         return mono_object_new_specific (vtable);
4499 }
4500
4501 /**
4502  * mono_object_new_pinned:
4503  *
4504  *   Same as mono_object_new, but the returned object will be pinned.
4505  * For SGEN, these objects will only be freed at appdomain unload.
4506  */
4507 MonoObject *
4508 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4509 {
4510         MONO_REQ_GC_UNSAFE_MODE;
4511
4512         MonoVTable *vtable;
4513
4514         vtable = mono_class_vtable (domain, klass);
4515         if (!vtable)
4516                 return NULL;
4517
4518 #ifdef HAVE_SGEN_GC
4519         return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4520 #else
4521         return mono_object_new_specific (vtable);
4522 #endif
4523 }
4524
4525 /**
4526  * mono_object_new_specific:
4527  * @vtable: the vtable of the object that we want to create
4528  *
4529  * Returns: A newly created object with class and domain specified
4530  * by @vtable
4531  */
4532 MonoObject *
4533 mono_object_new_specific (MonoVTable *vtable)
4534 {
4535         MONO_REQ_GC_UNSAFE_MODE;
4536
4537         MonoObject *o;
4538
4539         /* check for is_com_object for COM Interop */
4540         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4541         {
4542                 gpointer pa [1];
4543                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4544
4545                 if (im == NULL) {
4546                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4547
4548                         if (!klass->inited)
4549                                 mono_class_init (klass);
4550
4551                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4552                         if (!im)
4553                                 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
4554                         vtable->domain->create_proxy_for_type_method = im;
4555                 }
4556         
4557                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4558
4559                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
4560                 if (o != NULL) return o;
4561         }
4562
4563         return mono_object_new_alloc_specific (vtable);
4564 }
4565
4566 MonoObject *
4567 mono_object_new_alloc_specific (MonoVTable *vtable)
4568 {
4569         MONO_REQ_GC_UNSAFE_MODE;
4570
4571         MonoObject *o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4572
4573         if (G_UNLIKELY (vtable->klass->has_finalize))
4574                 mono_object_register_finalizer (o);
4575
4576         return o;
4577 }
4578
4579 MonoObject*
4580 mono_object_new_fast (MonoVTable *vtable)
4581 {
4582         MONO_REQ_GC_UNSAFE_MODE;
4583
4584         return mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4585 }
4586
4587 /**
4588  * mono_class_get_allocation_ftn:
4589  * @vtable: vtable
4590  * @for_box: the object will be used for boxing
4591  * @pass_size_in_words: 
4592  *
4593  * Return the allocation function appropriate for the given class.
4594  */
4595
4596 void*
4597 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4598 {
4599         MONO_REQ_GC_NEUTRAL_MODE;
4600
4601         *pass_size_in_words = FALSE;
4602
4603         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4604                 return mono_object_new_specific;
4605
4606         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4607
4608                 return mono_object_new_fast;
4609
4610                 /* 
4611                  * FIXME: This is actually slower than mono_object_new_fast, because
4612                  * of the overhead of parameter passing.
4613                  */
4614                 /*
4615                 *pass_size_in_words = TRUE;
4616 #ifdef GC_REDIRECT_TO_LOCAL
4617                 return GC_local_gcj_fast_malloc;
4618 #else
4619                 return GC_gcj_fast_malloc;
4620 #endif
4621                 */
4622         }
4623
4624         return mono_object_new_specific;
4625 }
4626
4627 /**
4628  * mono_object_new_from_token:
4629  * @image: Context where the type_token is hosted
4630  * @token: a token of the type that we want to create
4631  *
4632  * Returns: A newly created object whose definition is
4633  * looked up using @token in the @image image
4634  */
4635 MonoObject *
4636 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
4637 {
4638         MONO_REQ_GC_UNSAFE_MODE;
4639
4640         MonoError error;
4641         MonoClass *class;
4642
4643         class = mono_class_get_checked (image, token, &error);
4644         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4645
4646         return mono_object_new (domain, class);
4647 }
4648
4649
4650 /**
4651  * mono_object_clone:
4652  * @obj: the object to clone
4653  *
4654  * Returns: A newly created object who is a shallow copy of @obj
4655  */
4656 MonoObject *
4657 mono_object_clone (MonoObject *obj)
4658 {
4659         MONO_REQ_GC_UNSAFE_MODE;
4660
4661         MonoObject *o;
4662         int size = obj->vtable->klass->instance_size;
4663
4664         if (obj->vtable->klass->rank)
4665                 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4666
4667         o = mono_gc_alloc_obj (obj->vtable, size);
4668
4669         /* If the object doesn't contain references this will do a simple memmove. */
4670         mono_gc_wbarrier_object_copy (o, obj);
4671
4672         if (obj->vtable->klass->has_finalize)
4673                 mono_object_register_finalizer (o);
4674         return o;
4675 }
4676
4677 /**
4678  * mono_array_full_copy:
4679  * @src: source array to copy
4680  * @dest: destination array
4681  *
4682  * Copies the content of one array to another with exactly the same type and size.
4683  */
4684 void
4685 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4686 {
4687         MONO_REQ_GC_UNSAFE_MODE;
4688
4689         uintptr_t size;
4690         MonoClass *klass = src->obj.vtable->klass;
4691
4692         g_assert (klass == dest->obj.vtable->klass);
4693
4694         size = mono_array_length (src);
4695         g_assert (size == mono_array_length (dest));
4696         size *= mono_array_element_size (klass);
4697 #ifdef HAVE_SGEN_GC
4698         if (klass->element_class->valuetype) {
4699                 if (klass->element_class->has_references)
4700                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4701                 else
4702                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4703         } else {
4704                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4705         }
4706 #else
4707         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4708 #endif
4709 }
4710
4711 /**
4712  * mono_array_clone_in_domain:
4713  * @domain: the domain in which the array will be cloned into
4714  * @array: the array to clone
4715  *
4716  * This routine returns a copy of the array that is hosted on the
4717  * specified MonoDomain.
4718  */
4719 MonoArray*
4720 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4721 {
4722         MONO_REQ_GC_UNSAFE_MODE;
4723
4724         MonoArray *o;
4725         uintptr_t size, i;
4726         uintptr_t *sizes;
4727         MonoClass *klass = array->obj.vtable->klass;
4728
4729         if (array->bounds == NULL) {
4730                 size = mono_array_length (array);
4731                 o = mono_array_new_full (domain, klass, &size, NULL);
4732
4733                 size *= mono_array_element_size (klass);
4734 #ifdef HAVE_SGEN_GC
4735                 if (klass->element_class->valuetype) {
4736                         if (klass->element_class->has_references)
4737                                 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4738                         else
4739                                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4740                 } else {
4741                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4742                 }
4743 #else
4744                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4745 #endif
4746                 return o;
4747         }
4748         
4749         sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4750         size = mono_array_element_size (klass);
4751         for (i = 0; i < klass->rank; ++i) {
4752                 sizes [i] = array->bounds [i].length;
4753                 size *= array->bounds [i].length;
4754                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4755         }
4756         o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4757 #ifdef HAVE_SGEN_GC
4758         if (klass->element_class->valuetype) {
4759                 if (klass->element_class->has_references)
4760                         mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4761                 else
4762                         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4763         } else {
4764                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4765         }
4766 #else
4767         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4768 #endif
4769
4770         return o;
4771 }
4772
4773 /**
4774  * mono_array_clone:
4775  * @array: the array to clone
4776  *
4777  * Returns: A newly created array who is a shallow copy of @array
4778  */
4779 MonoArray*
4780 mono_array_clone (MonoArray *array)
4781 {
4782         MONO_REQ_GC_UNSAFE_MODE;
4783
4784         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4785 }
4786
4787 /* helper macros to check for overflow when calculating the size of arrays */
4788 #ifdef MONO_BIG_ARRAYS
4789 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4790 #define MYGUINT_MAX MYGUINT64_MAX
4791 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4792             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4793 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4794             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
4795                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4796 #else
4797 #define MYGUINT32_MAX 4294967295U
4798 #define MYGUINT_MAX MYGUINT32_MAX
4799 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4800             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4801 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4802             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
4803                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4804 #endif
4805
4806 gboolean
4807 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4808 {
4809         MONO_REQ_GC_NEUTRAL_MODE;
4810
4811         uintptr_t byte_len;
4812
4813         byte_len = mono_array_element_size (class);
4814         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4815                 return FALSE;
4816         byte_len *= len;
4817         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4818                 return FALSE;
4819         byte_len += sizeof (MonoArray);
4820
4821         *res = byte_len;
4822
4823         return TRUE;
4824 }
4825
4826 /**
4827  * mono_array_new_full:
4828  * @domain: domain where the object is created
4829  * @array_class: array class
4830  * @lengths: lengths for each dimension in the array
4831  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4832  *
4833  * This routine creates a new array objects with the given dimensions,
4834  * lower bounds and type.
4835  */
4836 MonoArray*
4837 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4838 {
4839         MONO_REQ_GC_UNSAFE_MODE;
4840
4841         uintptr_t byte_len = 0, len, bounds_size;
4842         MonoObject *o;
4843         MonoArray *array;
4844         MonoArrayBounds *bounds;
4845         MonoVTable *vtable;
4846         int i;
4847
4848         if (!array_class->inited)
4849                 mono_class_init (array_class);
4850
4851         len = 1;
4852
4853         /* A single dimensional array with a 0 lower bound is the same as an szarray */
4854         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4855                 len = lengths [0];
4856                 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4857                         arith_overflow ();
4858                 bounds_size = 0;
4859         } else {
4860                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4861
4862                 for (i = 0; i < array_class->rank; ++i) {
4863                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4864                                 arith_overflow ();
4865                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4866                                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4867                         len *= lengths [i];
4868                 }
4869         }
4870
4871         if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4872                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4873
4874         if (bounds_size) {
4875                 /* align */
4876                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4877                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4878                 byte_len = (byte_len + 3) & ~3;
4879                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4880                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4881                 byte_len += bounds_size;
4882         }
4883         /* 
4884          * Following three lines almost taken from mono_object_new ():
4885          * they need to be kept in sync.
4886          */
4887         vtable = mono_class_vtable_full (domain, array_class, TRUE);
4888         if (bounds_size)
4889                 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4890         else
4891                 o = mono_gc_alloc_vector (vtable, byte_len, len);
4892         array = (MonoArray*)o;
4893
4894         bounds = array->bounds;
4895
4896         if (bounds_size) {
4897                 for (i = 0; i < array_class->rank; ++i) {
4898                         bounds [i].length = lengths [i];
4899                         if (lower_bounds)
4900                                 bounds [i].lower_bound = lower_bounds [i];
4901                 }
4902         }
4903
4904         return array;
4905 }
4906
4907 /**
4908  * mono_array_new:
4909  * @domain: domain where the object is created
4910  * @eclass: element class
4911  * @n: number of array elements
4912  *
4913  * This routine creates a new szarray with @n elements of type @eclass.
4914  */
4915 MonoArray *
4916 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4917 {
4918         MONO_REQ_GC_UNSAFE_MODE;
4919
4920         MonoClass *ac;
4921
4922         ac = mono_array_class_get (eclass, 1);
4923         g_assert (ac);
4924
4925         return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4926 }
4927
4928 /**
4929  * mono_array_new_specific:
4930  * @vtable: a vtable in the appropriate domain for an initialized class
4931  * @n: number of array elements
4932  *
4933  * This routine is a fast alternative to mono_array_new() for code which
4934  * can be sure about the domain it operates in.
4935  */
4936 MonoArray *
4937 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4938 {
4939         MONO_REQ_GC_UNSAFE_MODE;
4940
4941         MonoObject *o;
4942         MonoArray *ao;
4943         uintptr_t byte_len;
4944
4945         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4946                 arith_overflow ();
4947                 return NULL;
4948         }
4949
4950         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4951                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4952                 return NULL;
4953         }
4954         o = mono_gc_alloc_vector (vtable, byte_len, n);
4955         ao = (MonoArray*)o;
4956
4957         return ao;
4958 }
4959
4960 /**
4961  * mono_string_new_utf16:
4962  * @text: a pointer to an utf16 string
4963  * @len: the length of the string
4964  *
4965  * Returns: A newly created string object which contains @text.
4966  */
4967 MonoString *
4968 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4969 {
4970         MONO_REQ_GC_UNSAFE_MODE;
4971
4972         MonoString *s;
4973         
4974         s = mono_string_new_size (domain, len);
4975         g_assert (s != NULL);
4976
4977         memcpy (mono_string_chars (s), text, len * 2);
4978
4979         return s;
4980 }
4981
4982 /**
4983  * mono_string_new_utf32:
4984  * @text: a pointer to an utf32 string
4985  * @len: the length of the string
4986  *
4987  * Returns: A newly created string object which contains @text.
4988  */
4989 MonoString *
4990 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4991 {
4992         MONO_REQ_GC_UNSAFE_MODE;
4993
4994         MonoString *s;
4995         mono_unichar2 *utf16_output = NULL;
4996         gint32 utf16_len = 0;
4997         GError *error = NULL;
4998         glong items_written;
4999         
5000         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5001         
5002         if (error)
5003                 g_error_free (error);
5004
5005         while (utf16_output [utf16_len]) utf16_len++;
5006         
5007         s = mono_string_new_size (domain, utf16_len);
5008         g_assert (s != NULL);
5009
5010         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5011
5012         g_free (utf16_output);
5013         
5014         return s;
5015 }
5016
5017 /**
5018  * mono_string_new_size:
5019  * @text: a pointer to an utf16 string
5020  * @len: the length of the string
5021  *
5022  * Returns: A newly created string object of @len
5023  */
5024 MonoString *
5025 mono_string_new_size (MonoDomain *domain, gint32 len)
5026 {
5027         MONO_REQ_GC_UNSAFE_MODE;
5028
5029         MonoString *s;
5030         MonoVTable *vtable;
5031         size_t size;
5032
5033         /* check for overflow */
5034         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5035                 mono_gc_out_of_memory (-1);
5036
5037         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5038         g_assert (size > 0);
5039
5040         vtable = mono_class_vtable (domain, mono_defaults.string_class);
5041         g_assert (vtable);
5042
5043         s = mono_gc_alloc_string (vtable, size, len);
5044
5045         return s;
5046 }
5047
5048 /**
5049  * mono_string_new_len:
5050  * @text: a pointer to an utf8 string
5051  * @length: number of bytes in @text to consider
5052  *
5053  * Returns: A newly created string object which contains @text.
5054  */
5055 MonoString*
5056 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5057 {
5058         MONO_REQ_GC_UNSAFE_MODE;
5059
5060         GError *error = NULL;
5061         MonoString *o = NULL;
5062         guint16 *ut;
5063         glong items_written;
5064
5065         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5066
5067         if (!error)
5068                 o = mono_string_new_utf16 (domain, ut, items_written);
5069         else 
5070                 g_error_free (error);
5071
5072         g_free (ut);
5073
5074         return o;
5075 }
5076
5077 /**
5078  * mono_string_new:
5079  * @text: a pointer to an utf8 string
5080  *
5081  * Returns: A newly created string object which contains @text.
5082  */
5083 MonoString*
5084 mono_string_new (MonoDomain *domain, const char *text)
5085 {
5086         MONO_REQ_GC_UNSAFE_MODE;
5087
5088     GError *error = NULL;
5089     MonoString *o = NULL;
5090     guint16 *ut;
5091     glong items_written;
5092     int l;
5093
5094     l = strlen (text);
5095    
5096     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5097
5098     if (!error)
5099         o = mono_string_new_utf16 (domain, ut, items_written);
5100     else
5101         g_error_free (error);
5102
5103     g_free (ut);
5104 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5105 #if 0
5106         gunichar2 *str;
5107         const gchar *end;
5108         int len;
5109         MonoString *o = NULL;
5110
5111         if (!g_utf8_validate (text, -1, &end))
5112                 return NULL;
5113
5114         len = g_utf8_strlen (text, -1);
5115         o = mono_string_new_size (domain, len);
5116         str = mono_string_chars (o);
5117
5118         while (text < end) {
5119                 *str++ = g_utf8_get_char (text);
5120                 text = g_utf8_next_char (text);
5121         }
5122 #endif
5123         return o;
5124 }
5125
5126 /**
5127  * mono_string_new_wrapper:
5128  * @text: pointer to utf8 characters.
5129  *
5130  * Helper function to create a string object from @text in the current domain.
5131  */
5132 MonoString*
5133 mono_string_new_wrapper (const char *text)
5134 {
5135         MONO_REQ_GC_UNSAFE_MODE;
5136
5137         MonoDomain *domain = mono_domain_get ();
5138
5139         if (text)
5140                 return mono_string_new (domain, text);
5141
5142         return NULL;
5143 }
5144
5145 /**
5146  * mono_value_box:
5147  * @class: the class of the value
5148  * @value: a pointer to the unboxed data
5149  *
5150  * Returns: A newly created object which contains @value.
5151  */
5152 MonoObject *
5153 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5154 {
5155         MONO_REQ_GC_UNSAFE_MODE;
5156
5157         MonoObject *res;
5158         int size;
5159         MonoVTable *vtable;
5160
5161         g_assert (class->valuetype);
5162         if (mono_class_is_nullable (class))
5163                 return mono_nullable_box (value, class);
5164
5165         vtable = mono_class_vtable (domain, class);
5166         if (!vtable)
5167                 return NULL;
5168         size = mono_class_instance_size (class);
5169         res = mono_object_new_alloc_specific (vtable);
5170
5171         size = size - sizeof (MonoObject);
5172
5173 #ifdef HAVE_SGEN_GC
5174         g_assert (size == mono_class_value_size (class, NULL));
5175         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5176 #else
5177 #if NO_UNALIGNED_ACCESS
5178         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5179 #else
5180         switch (size) {
5181         case 1:
5182                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5183                 break;
5184         case 2:
5185                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5186                 break;
5187         case 4:
5188                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5189                 break;
5190         case 8:
5191                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5192                 break;
5193         default:
5194                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5195         }
5196 #endif
5197 #endif
5198         if (class->has_finalize)
5199                 mono_object_register_finalizer (res);
5200         return res;
5201 }
5202
5203 /*
5204  * mono_value_copy:
5205  * @dest: destination pointer
5206  * @src: source pointer
5207  * @klass: a valuetype class
5208  *
5209  * Copy a valuetype from @src to @dest. This function must be used
5210  * when @klass contains references fields.
5211  */
5212 void
5213 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5214 {
5215         MONO_REQ_GC_UNSAFE_MODE;
5216
5217         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5218 }
5219
5220 /*
5221  * mono_value_copy_array:
5222  * @dest: destination array
5223  * @dest_idx: index in the @dest array
5224  * @src: source pointer
5225  * @count: number of items
5226  *
5227  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
5228  * This function must be used when @klass contains references fields.
5229  * Overlap is handled.
5230  */
5231 void
5232 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5233 {
5234         MONO_REQ_GC_UNSAFE_MODE;
5235
5236         int size = mono_array_element_size (dest->obj.vtable->klass);
5237         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5238         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5239         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5240 }
5241
5242 /**
5243  * mono_object_get_domain:
5244  * @obj: object to query
5245  * 
5246  * Returns: the MonoDomain where the object is hosted
5247  */
5248 MonoDomain*
5249 mono_object_get_domain (MonoObject *obj)
5250 {
5251         MONO_REQ_GC_UNSAFE_MODE;
5252
5253         return mono_object_domain (obj);
5254 }
5255
5256 /**
5257  * mono_object_get_class:
5258  * @obj: object to query
5259  * 
5260  * Returns: the MonOClass of the object.
5261  */
5262 MonoClass*
5263 mono_object_get_class (MonoObject *obj)
5264 {
5265         MONO_REQ_GC_UNSAFE_MODE;
5266
5267         return mono_object_class (obj);
5268 }
5269 /**
5270  * mono_object_get_size:
5271  * @o: object to query
5272  * 
5273  * Returns: the size, in bytes, of @o
5274  */
5275 guint
5276 mono_object_get_size (MonoObject* o)
5277 {
5278         MONO_REQ_GC_UNSAFE_MODE;
5279
5280         MonoClass* klass = mono_object_class (o);
5281         if (klass == mono_defaults.string_class) {
5282                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5283         } else if (o->vtable->rank) {
5284                 MonoArray *array = (MonoArray*)o;
5285                 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5286                 if (array->bounds) {
5287                         size += 3;
5288                         size &= ~3;
5289                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
5290                 }
5291                 return size;
5292         } else {
5293                 return mono_class_instance_size (klass);
5294         }
5295 }
5296
5297 /**
5298  * mono_object_unbox:
5299  * @obj: object to unbox
5300  * 
5301  * Returns: a pointer to the start of the valuetype boxed in this
5302  * object.
5303  *
5304  * This method will assert if the object passed is not a valuetype.
5305  */
5306 gpointer
5307 mono_object_unbox (MonoObject *obj)
5308 {
5309         MONO_REQ_GC_UNSAFE_MODE;
5310
5311         /* add assert for valuetypes? */
5312         g_assert (obj->vtable->klass->valuetype);
5313         return ((char*)obj) + sizeof (MonoObject);
5314 }
5315
5316 /**
5317  * mono_object_isinst:
5318  * @obj: an object
5319  * @klass: a pointer to a class 
5320  *
5321  * Returns: @obj if @obj is derived from @klass
5322  */
5323 MonoObject *
5324 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5325 {
5326         MONO_REQ_GC_UNSAFE_MODE;
5327
5328         if (!klass->inited)
5329                 mono_class_init (klass);
5330
5331         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5332                 return mono_object_isinst_mbyref (obj, klass);
5333
5334         if (!obj)
5335                 return NULL;
5336
5337         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5338 }
5339
5340 MonoObject *
5341 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5342 {
5343         MONO_REQ_GC_UNSAFE_MODE;
5344
5345         MonoVTable *vt;
5346
5347         if (!obj)
5348                 return NULL;
5349
5350         vt = obj->vtable;
5351         
5352         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5353                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5354                         return obj;
5355                 }
5356
5357                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5358                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5359                         return obj;
5360         } else {
5361                 MonoClass *oklass = vt->klass;
5362                 if (mono_class_is_transparent_proxy (oklass))
5363                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5364
5365                 mono_class_setup_supertypes (klass);    
5366                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5367                         return obj;
5368         }
5369 #ifndef DISABLE_REMOTING
5370         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5371         {
5372                 MonoDomain *domain = mono_domain_get ();
5373                 MonoObject *res;
5374                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5375                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5376                 MonoMethod *im = NULL;
5377                 gpointer pa [2];
5378
5379                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5380                 if (!im)
5381                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5382                 im = mono_object_get_virtual_method (rp, im);
5383                 g_assert (im);
5384         
5385                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5386                 pa [1] = obj;
5387
5388                 res = mono_runtime_invoke (im, rp, pa, NULL);
5389         
5390                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5391                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5392                         mono_upgrade_remote_class (domain, obj, klass);
5393                         return obj;
5394                 }
5395         }
5396 #endif /* DISABLE_REMOTING */
5397         return NULL;
5398 }
5399
5400 /**
5401  * mono_object_castclass_mbyref:
5402  * @obj: an object
5403  * @klass: a pointer to a class 
5404  *
5405  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5406  */
5407 MonoObject *
5408 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5409 {
5410         MONO_REQ_GC_UNSAFE_MODE;
5411
5412         if (!obj) return NULL;
5413         if (mono_object_isinst_mbyref (obj, klass)) return obj;
5414                 
5415         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5416                                                         "System",
5417                                                         "InvalidCastException"));
5418         return NULL;
5419 }
5420
5421 typedef struct {
5422         MonoDomain *orig_domain;
5423         MonoString *ins;
5424         MonoString *res;
5425 } LDStrInfo;
5426
5427 static void
5428 str_lookup (MonoDomain *domain, gpointer user_data)
5429 {
5430         MONO_REQ_GC_UNSAFE_MODE;
5431
5432         LDStrInfo *info = user_data;
5433         if (info->res || domain == info->orig_domain)
5434                 return;
5435         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5436 }
5437
5438 #ifdef HAVE_SGEN_GC
5439
5440 static MonoString*
5441 mono_string_get_pinned (MonoString *str)
5442 {
5443         MONO_REQ_GC_UNSAFE_MODE;
5444
5445         int size;
5446         MonoString *news;
5447         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5448         news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5449         if (news) {
5450                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5451                 news->length = mono_string_length (str);
5452         }
5453         return news;
5454 }
5455
5456 #else
5457 #define mono_string_get_pinned(str) (str)
5458 #endif
5459
5460 static MonoString*
5461 mono_string_is_interned_lookup (MonoString *str, int insert)
5462 {
5463         MONO_REQ_GC_UNSAFE_MODE;
5464
5465         MonoGHashTable *ldstr_table;
5466         MonoString *s, *res;
5467         MonoDomain *domain;
5468         
5469         domain = ((MonoObject *)str)->vtable->domain;
5470         ldstr_table = domain->ldstr_table;
5471         ldstr_lock ();
5472         res = mono_g_hash_table_lookup (ldstr_table, str);
5473         if (res) {
5474                 ldstr_unlock ();
5475                 return res;
5476         }
5477         if (insert) {
5478                 /* Allocate outside the lock */
5479                 ldstr_unlock ();
5480                 s = mono_string_get_pinned (str);
5481                 if (s) {
5482                         ldstr_lock ();
5483                         res = mono_g_hash_table_lookup (ldstr_table, str);
5484                         if (res) {
5485                                 ldstr_unlock ();
5486                                 return res;
5487                         }
5488                         mono_g_hash_table_insert (ldstr_table, s, s);
5489                         ldstr_unlock ();
5490                 }
5491                 return s;
5492         } else {
5493                 LDStrInfo ldstr_info;
5494                 ldstr_info.orig_domain = domain;
5495                 ldstr_info.ins = str;
5496                 ldstr_info.res = NULL;
5497
5498                 mono_domain_foreach (str_lookup, &ldstr_info);
5499                 if (ldstr_info.res) {
5500                         /* 
5501                          * the string was already interned in some other domain:
5502                          * intern it in the current one as well.
5503                          */
5504                         mono_g_hash_table_insert (ldstr_table, str, str);
5505                         ldstr_unlock ();
5506                         return str;
5507                 }
5508         }
5509         ldstr_unlock ();
5510         return NULL;
5511 }
5512
5513 /**
5514  * mono_string_is_interned:
5515  * @o: String to probe
5516  *
5517  * Returns whether the string has been interned.
5518  */
5519 MonoString*
5520 mono_string_is_interned (MonoString *o)
5521 {
5522         MONO_REQ_GC_UNSAFE_MODE;
5523
5524         return mono_string_is_interned_lookup (o, FALSE);
5525 }
5526
5527 /**
5528  * mono_string_intern:
5529  * @o: String to intern
5530  *
5531  * Interns the string passed.  
5532  * Returns: The interned string.
5533  */
5534 MonoString*
5535 mono_string_intern (MonoString *str)
5536 {
5537         MONO_REQ_GC_UNSAFE_MODE;
5538
5539         return mono_string_is_interned_lookup (str, TRUE);
5540 }
5541
5542 /**
5543  * mono_ldstr:
5544  * @domain: the domain where the string will be used.
5545  * @image: a metadata context
5546  * @idx: index into the user string table.
5547  * 
5548  * Implementation for the ldstr opcode.
5549  * Returns: a loaded string from the @image/@idx combination.
5550  */
5551 MonoString*
5552 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5553 {
5554         MONO_REQ_GC_UNSAFE_MODE;
5555
5556         if (image->dynamic) {
5557                 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5558                 return str;
5559         } else {
5560                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5561                         return NULL; /*FIXME we should probably be raising an exception here*/
5562                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5563         }
5564 }
5565
5566 /**
5567  * mono_ldstr_metadata_sig
5568  * @domain: the domain for the string
5569  * @sig: the signature of a metadata string
5570  *
5571  * Returns: a MonoString for a string stored in the metadata
5572  */
5573 static MonoString*
5574 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5575 {
5576         MONO_REQ_GC_UNSAFE_MODE;
5577
5578         const char *str = sig;
5579         MonoString *o, *interned;
5580         size_t len2;
5581
5582         len2 = mono_metadata_decode_blob_size (str, &str);
5583         len2 >>= 1;
5584
5585         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5586 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5587         {
5588                 int i;
5589                 guint16 *p2 = (guint16*)mono_string_chars (o);
5590                 for (i = 0; i < len2; ++i) {
5591                         *p2 = GUINT16_FROM_LE (*p2);
5592                         ++p2;
5593                 }
5594         }
5595 #endif
5596         ldstr_lock ();
5597         interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5598         ldstr_unlock ();
5599         if (interned)
5600                 return interned; /* o will get garbage collected */
5601
5602         o = mono_string_get_pinned (o);
5603         if (o) {
5604                 ldstr_lock ();
5605                 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5606                 if (!interned) {
5607                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
5608                         interned = o;
5609                 }
5610                 ldstr_unlock ();
5611         }
5612
5613         return interned;
5614 }
5615
5616 /**
5617  * mono_string_to_utf8:
5618  * @s: a System.String
5619  *
5620  * Returns the UTF8 representation for @s.
5621  * The resulting buffer needs to be freed with mono_free().
5622  *
5623  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5624  */
5625 char *
5626 mono_string_to_utf8 (MonoString *s)
5627 {
5628         MONO_REQ_GC_UNSAFE_MODE;
5629
5630         MonoError error;
5631         char *result = mono_string_to_utf8_checked (s, &error);
5632         
5633         if (!mono_error_ok (&error))
5634                 mono_error_raise_exception (&error);
5635         return result;
5636 }
5637
5638 /**
5639  * mono_string_to_utf8_checked:
5640  * @s: a System.String
5641  * @error: a MonoError.
5642  * 
5643  * Converts a MonoString to its UTF8 representation. May fail; check 
5644  * @error to determine whether the conversion was successful.
5645  * The resulting buffer should be freed with mono_free().
5646  */
5647 char *
5648 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5649 {
5650         MONO_REQ_GC_UNSAFE_MODE;
5651
5652         long written = 0;
5653         char *as;
5654         GError *gerror = NULL;
5655
5656         mono_error_init (error);
5657
5658         if (s == NULL)
5659                 return NULL;
5660
5661         if (!s->length)
5662                 return g_strdup ("");
5663
5664         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5665         if (gerror) {
5666                 mono_error_set_argument (error, "string", "%s", gerror->message);
5667                 g_error_free (gerror);
5668                 return NULL;
5669         }
5670         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5671         if (s->length > written) {
5672                 /* allocate the total length and copy the part of the string that has been converted */
5673                 char *as2 = g_malloc0 (s->length);
5674                 memcpy (as2, as, written);
5675                 g_free (as);
5676                 as = as2;
5677         }
5678
5679         return as;
5680 }
5681
5682 /**
5683  * mono_string_to_utf8_ignore:
5684  * @s: a MonoString
5685  *
5686  * Converts a MonoString to its UTF8 representation. Will ignore
5687  * invalid surrogate pairs.
5688  * The resulting buffer should be freed with mono_free().
5689  * 
5690  */
5691 char *
5692 mono_string_to_utf8_ignore (MonoString *s)
5693 {
5694         MONO_REQ_GC_UNSAFE_MODE;
5695
5696         long written = 0;
5697         char *as;
5698
5699         if (s == NULL)
5700                 return NULL;
5701
5702         if (!s->length)
5703                 return g_strdup ("");
5704
5705         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5706
5707         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5708         if (s->length > written) {
5709                 /* allocate the total length and copy the part of the string that has been converted */
5710                 char *as2 = g_malloc0 (s->length);
5711                 memcpy (as2, as, written);
5712                 g_free (as);
5713                 as = as2;
5714         }
5715
5716         return as;
5717 }
5718
5719 /**
5720  * mono_string_to_utf8_image_ignore:
5721  * @s: a System.String
5722  *
5723  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5724  */
5725 char *
5726 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5727 {
5728         MONO_REQ_GC_UNSAFE_MODE;
5729
5730         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5731 }
5732
5733 /**
5734  * mono_string_to_utf8_mp_ignore:
5735  * @s: a System.String
5736  *
5737  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5738  */
5739 char *
5740 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5741 {
5742         MONO_REQ_GC_UNSAFE_MODE;
5743
5744         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5745 }
5746
5747
5748 /**
5749  * mono_string_to_utf16:
5750  * @s: a MonoString
5751  *
5752  * Return an null-terminated array of the utf-16 chars
5753  * contained in @s. The result must be freed with g_free().
5754  * This is a temporary helper until our string implementation
5755  * is reworked to always include the null terminating char.
5756  */
5757 mono_unichar2*
5758 mono_string_to_utf16 (MonoString *s)
5759 {
5760         MONO_REQ_GC_UNSAFE_MODE;
5761
5762         char *as;
5763
5764         if (s == NULL)
5765                 return NULL;
5766
5767         as = g_malloc ((s->length * 2) + 2);
5768         as [(s->length * 2)] = '\0';
5769         as [(s->length * 2) + 1] = '\0';
5770
5771         if (!s->length) {
5772                 return (gunichar2 *)(as);
5773         }
5774         
5775         memcpy (as, mono_string_chars(s), s->length * 2);
5776         return (gunichar2 *)(as);
5777 }
5778
5779 /**
5780  * mono_string_to_utf32:
5781  * @s: a MonoString
5782  *
5783  * Return an null-terminated array of the UTF-32 (UCS-4) chars
5784  * contained in @s. The result must be freed with g_free().
5785  */
5786 mono_unichar4*
5787 mono_string_to_utf32 (MonoString *s)
5788 {
5789         MONO_REQ_GC_UNSAFE_MODE;
5790
5791         mono_unichar4 *utf32_output = NULL; 
5792         GError *error = NULL;
5793         glong items_written;
5794         
5795         if (s == NULL)
5796                 return NULL;
5797                 
5798         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5799         
5800         if (error)
5801                 g_error_free (error);
5802
5803         return utf32_output;
5804 }
5805
5806 /**
5807  * mono_string_from_utf16:
5808  * @data: the UTF16 string (LPWSTR) to convert
5809  *
5810  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5811  *
5812  * Returns: a MonoString.
5813  */
5814 MonoString *
5815 mono_string_from_utf16 (gunichar2 *data)
5816 {
5817         MONO_REQ_GC_UNSAFE_MODE;
5818
5819         MonoDomain *domain = mono_domain_get ();
5820         int len = 0;
5821
5822         if (!data)
5823                 return NULL;
5824
5825         while (data [len]) len++;
5826
5827         return mono_string_new_utf16 (domain, data, len);
5828 }
5829
5830 /**
5831  * mono_string_from_utf32:
5832  * @data: the UTF32 string (LPWSTR) to convert
5833  *
5834  * Converts a UTF32 (UCS-4)to a MonoString.
5835  *
5836  * Returns: a MonoString.
5837  */
5838 MonoString *
5839 mono_string_from_utf32 (mono_unichar4 *data)
5840 {
5841         MONO_REQ_GC_UNSAFE_MODE;
5842
5843         MonoString* result = NULL;
5844         mono_unichar2 *utf16_output = NULL;
5845         GError *error = NULL;
5846         glong items_written;
5847         int len = 0;
5848
5849         if (!data)
5850                 return NULL;
5851
5852         while (data [len]) len++;
5853
5854         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5855
5856         if (error)
5857                 g_error_free (error);
5858
5859         result = mono_string_from_utf16 (utf16_output);
5860         g_free (utf16_output);
5861         return result;
5862 }
5863
5864 static char *
5865 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5866 {
5867         MONO_REQ_GC_UNSAFE_MODE;
5868
5869         char *r;
5870         char *mp_s;
5871         int len;
5872
5873         if (ignore_error) {
5874                 r = mono_string_to_utf8_ignore (s);
5875         } else {
5876                 r = mono_string_to_utf8_checked (s, error);
5877                 if (!mono_error_ok (error))
5878                         return NULL;
5879         }
5880
5881         if (!mp && !image)
5882                 return r;
5883
5884         len = strlen (r) + 1;
5885         if (mp)
5886                 mp_s = mono_mempool_alloc (mp, len);
5887         else
5888                 mp_s = mono_image_alloc (image, len);
5889
5890         memcpy (mp_s, r, len);
5891
5892         g_free (r);
5893
5894         return mp_s;
5895 }
5896
5897 /**
5898  * mono_string_to_utf8_image:
5899  * @s: a System.String
5900  *
5901  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5902  */
5903 char *
5904 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5905 {
5906         MONO_REQ_GC_UNSAFE_MODE;
5907
5908         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5909 }
5910
5911 /**
5912  * mono_string_to_utf8_mp:
5913  * @s: a System.String
5914  *
5915  * Same as mono_string_to_utf8, but allocate the string from a mempool.
5916  */
5917 char *
5918 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5919 {
5920         MONO_REQ_GC_UNSAFE_MODE;
5921
5922         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5923 }
5924
5925
5926 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5927
5928 void
5929 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5930 {
5931         eh_callbacks = *cbs;
5932 }
5933
5934 MonoRuntimeExceptionHandlingCallbacks *
5935 mono_get_eh_callbacks (void)
5936 {
5937         return &eh_callbacks;
5938 }
5939
5940 /**
5941  * mono_raise_exception:
5942  * @ex: exception object
5943  *
5944  * Signal the runtime that the exception @ex has been raised in unmanaged code.
5945  */
5946 void
5947 mono_raise_exception (MonoException *ex) 
5948 {
5949         MONO_REQ_GC_UNSAFE_MODE;
5950
5951         /*
5952          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5953          * that will cause gcc to omit the function epilog, causing problems when
5954          * the JIT tries to walk the stack, since the return address on the stack
5955          * will point into the next function in the executable, not this one.
5956          */     
5957         eh_callbacks.mono_raise_exception (ex);
5958 }
5959
5960 void
5961 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
5962 {
5963         MONO_REQ_GC_UNSAFE_MODE;
5964
5965         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5966 }
5967
5968 /**
5969  * mono_wait_handle_new:
5970  * @domain: Domain where the object will be created
5971  * @handle: Handle for the wait handle
5972  *
5973  * Returns: A new MonoWaitHandle created in the given domain for the given handle
5974  */
5975 MonoWaitHandle *
5976 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5977 {
5978         MONO_REQ_GC_UNSAFE_MODE;
5979
5980         MonoWaitHandle *res;
5981         gpointer params [1];
5982         static MonoMethod *handle_set;
5983
5984         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5985
5986         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
5987         if (!handle_set)
5988                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5989
5990         params [0] = &handle;
5991         mono_runtime_invoke (handle_set, res, params, NULL);
5992
5993         return res;
5994 }
5995
5996 HANDLE
5997 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5998 {
5999         MONO_REQ_GC_UNSAFE_MODE;
6000
6001         static MonoClassField *f_os_handle;
6002         static MonoClassField *f_safe_handle;
6003
6004         if (!f_os_handle && !f_safe_handle) {
6005                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6006                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6007         }
6008
6009         if (f_os_handle) {
6010                 HANDLE retval;
6011                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6012                 return retval;
6013         } else {
6014                 MonoSafeHandle *sh;
6015                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6016                 return sh->handle;
6017         }
6018 }
6019
6020
6021 static MonoObject*
6022 mono_runtime_capture_context (MonoDomain *domain)
6023 {
6024         MONO_REQ_GC_UNSAFE_MODE;
6025
6026         RuntimeInvokeFunction runtime_invoke;
6027
6028         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6029                 MonoMethod *method = mono_get_context_capture_method ();
6030                 MonoMethod *wrapper;
6031                 if (!method)
6032                         return NULL;
6033                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
6034                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6035                 domain->capture_context_method = mono_compile_method (method);
6036         }
6037
6038         runtime_invoke = domain->capture_context_runtime_invoke;
6039
6040         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6041 }
6042 /**
6043  * mono_async_result_new:
6044  * @domain:domain where the object will be created.
6045  * @handle: wait handle.
6046  * @state: state to pass to AsyncResult
6047  * @data: C closure data.
6048  *
6049  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6050  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6051  *
6052  */
6053 MonoAsyncResult *
6054 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6055 {
6056         MONO_REQ_GC_UNSAFE_MODE;
6057
6058         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6059         MonoObject *context = mono_runtime_capture_context (domain);
6060         /* we must capture the execution context from the original thread */
6061         if (context) {
6062                 MONO_OBJECT_SETREF (res, execution_context, context);
6063                 /* note: result may be null if the flow is suppressed */
6064         }
6065
6066         res->data = data;
6067         MONO_OBJECT_SETREF (res, object_data, object_data);
6068         MONO_OBJECT_SETREF (res, async_state, state);
6069         if (handle != NULL)
6070                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6071
6072         res->sync_completed = FALSE;
6073         res->completed = FALSE;
6074
6075         return res;
6076 }
6077
6078 MonoObject *
6079 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6080 {
6081         MONO_REQ_GC_UNSAFE_MODE;
6082
6083         MonoAsyncCall *ac;
6084         MonoObject *res;
6085
6086         g_assert (ares);
6087         g_assert (ares->async_delegate);
6088
6089         ac = (MonoAsyncCall*) ares->object_data;
6090         if (!ac) {
6091                 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6092         } else {
6093                 gpointer wait_event = NULL;
6094
6095                 ac->msg->exc = NULL;
6096                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6097                 MONO_OBJECT_SETREF (ac, res, res);
6098
6099                 mono_monitor_enter ((MonoObject*) ares);
6100                 ares->completed = 1;
6101                 if (ares->handle)
6102                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6103                 mono_monitor_exit ((MonoObject*) ares);
6104
6105                 if (wait_event != NULL)
6106                         SetEvent (wait_event);
6107
6108                 if (ac->cb_method) {
6109                         /* we swallow the excepton as it is the behavior on .NET */
6110                         MonoObject *exc = NULL;
6111                         mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6112                         if (exc)
6113                                 mono_unhandled_exception (exc);
6114                 }
6115         }
6116
6117         return res;
6118 }
6119
6120 void
6121 mono_message_init (MonoDomain *domain,
6122                    MonoMethodMessage *this_obj, 
6123                    MonoReflectionMethod *method,
6124                    MonoArray *out_args)
6125 {
6126         MONO_REQ_GC_UNSAFE_MODE;
6127
6128         static MonoClass *object_array_klass;
6129         static MonoClass *byte_array_klass;
6130         static MonoClass *string_array_klass;
6131         MonoMethodSignature *sig = mono_method_signature (method->method);
6132         MonoString *name;
6133         int i, j;
6134         char **names;
6135         guint8 arg_type;
6136
6137         if (!object_array_klass) {
6138                 MonoClass *klass;
6139
6140                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6141                 g_assert (klass);
6142                 byte_array_klass = klass;
6143
6144                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6145                 g_assert (klass);
6146                 string_array_klass = klass;
6147
6148                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6149                 g_assert (klass);
6150
6151                 mono_atomic_store_release (&object_array_klass, klass);
6152         }
6153
6154         MONO_OBJECT_SETREF (this_obj, method, method);
6155
6156         MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6157         MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6158         this_obj->async_result = NULL;
6159         this_obj->call_type = CallType_Sync;
6160
6161         names = g_new (char *, sig->param_count);
6162         mono_method_get_param_names (method->method, (const char **) names);
6163         MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6164         
6165         for (i = 0; i < sig->param_count; i++) {
6166                 name = mono_string_new (domain, names [i]);
6167                 mono_array_setref (this_obj->names, i, name);   
6168         }
6169
6170         g_free (names);
6171         for (i = 0, j = 0; i < sig->param_count; i++) {
6172                 if (sig->params [i]->byref) {
6173                         if (out_args) {
6174                                 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6175                                 mono_array_setref (this_obj->args, i, arg);
6176                                 j++;
6177                         }
6178                         arg_type = 2;
6179                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6180                                 arg_type |= 1;
6181                 } else {
6182                         arg_type = 1;
6183                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6184                                 arg_type |= 4;
6185                 }
6186                 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6187         }
6188 }
6189
6190 #ifndef DISABLE_REMOTING
6191 /**
6192  * mono_remoting_invoke:
6193  * @real_proxy: pointer to a RealProxy object
6194  * @msg: The MonoMethodMessage to execute
6195  * @exc: used to store exceptions
6196  * @out_args: used to store output arguments
6197  *
6198  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6199  * IMessage interface and it is not trivial to extract results from there. So
6200  * we call an helper method PrivateInvoke instead of calling
6201  * RealProxy::Invoke() directly.
6202  *
6203  * Returns: the result object.
6204  */
6205 MonoObject *
6206 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
6207                       MonoObject **exc, MonoArray **out_args)
6208 {
6209         MONO_REQ_GC_UNSAFE_MODE;
6210
6211         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6212         gpointer pa [4];
6213
6214         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6215
6216         if (!im) {
6217                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6218                 if (!im)
6219                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6220                 real_proxy->vtable->domain->private_invoke_method = im;
6221         }
6222
6223         pa [0] = real_proxy;
6224         pa [1] = msg;
6225         pa [2] = exc;
6226         pa [3] = out_args;
6227
6228         return mono_runtime_invoke (im, NULL, pa, exc);
6229 }
6230 #endif
6231
6232 MonoObject *
6233 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6234                      MonoObject **exc, MonoArray **out_args) 
6235 {
6236         MONO_REQ_GC_UNSAFE_MODE;
6237
6238         static MonoClass *object_array_klass;
6239         MonoDomain *domain; 
6240         MonoMethod *method;
6241         MonoMethodSignature *sig;
6242         MonoObject *ret;
6243         int i, j, outarg_count = 0;
6244
6245 #ifndef DISABLE_REMOTING
6246         if (target && mono_object_is_transparent_proxy (target)) {
6247                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6248                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6249                         target = tp->rp->unwrapped_server;
6250                 } else {
6251                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6252                 }
6253         }
6254 #endif
6255
6256         domain = mono_domain_get (); 
6257         method = msg->method->method;
6258         sig = mono_method_signature (method);
6259
6260         for (i = 0; i < sig->param_count; i++) {
6261                 if (sig->params [i]->byref) 
6262                         outarg_count++;
6263         }
6264
6265         if (!object_array_klass) {
6266                 MonoClass *klass;
6267
6268                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6269                 g_assert (klass);
6270
6271                 mono_memory_barrier ();
6272                 object_array_klass = klass;
6273         }
6274
6275         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
6276         *exc = NULL;
6277
6278         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6279
6280         for (i = 0, j = 0; i < sig->param_count; i++) {
6281                 if (sig->params [i]->byref) {
6282                         MonoObject* arg;
6283                         arg = mono_array_get (msg->args, gpointer, i);
6284                         mono_array_setref (*out_args, j, arg);
6285                         j++;
6286                 }
6287         }
6288
6289         return ret;
6290 }
6291
6292 /**
6293  * mono_object_to_string:
6294  * @obj: The object
6295  * @exc: Any exception thrown by ToString (). May be NULL.
6296  *
6297  * Returns: the result of calling ToString () on an object.
6298  */
6299 MonoString *
6300 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6301 {
6302         MONO_REQ_GC_UNSAFE_MODE;
6303
6304         static MonoMethod *to_string = NULL;
6305         MonoMethod *method;
6306         void *target = obj;
6307
6308         g_assert (obj);
6309
6310         if (!to_string)
6311                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6312
6313         method = mono_object_get_virtual_method (obj, to_string);
6314
6315         // Unbox value type if needed
6316         if (mono_class_is_valuetype (mono_method_get_class (method))) {
6317                 target = mono_object_unbox (obj);
6318         }
6319
6320         return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6321 }
6322
6323 /**
6324  * mono_print_unhandled_exception:
6325  * @exc: The exception
6326  *
6327  * Prints the unhandled exception.
6328  */
6329 void
6330 mono_print_unhandled_exception (MonoObject *exc)
6331 {
6332         MONO_REQ_GC_UNSAFE_MODE;
6333
6334         MonoString * str;
6335         char *message = (char*)"";
6336         gboolean free_message = FALSE;
6337         MonoError error;
6338
6339         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6340                 message = g_strdup ("OutOfMemoryException");
6341                 free_message = TRUE;
6342         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6343                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6344                 free_message = TRUE;
6345         } else {
6346                 
6347                 if (((MonoException*)exc)->native_trace_ips) {
6348                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
6349                         free_message = TRUE;
6350                 } else {
6351                         MonoObject *other_exc = NULL;
6352                         str = mono_object_to_string (exc, &other_exc);
6353                         if (other_exc) {
6354                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6355                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6356                                 
6357                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6358                                         original_backtrace, nested_backtrace);
6359
6360                                 g_free (original_backtrace);
6361                                 g_free (nested_backtrace);
6362                                 free_message = TRUE;
6363                         } else if (str) {
6364                                 message = mono_string_to_utf8_checked (str, &error);
6365                                 if (!mono_error_ok (&error)) {
6366                                         mono_error_cleanup (&error);
6367                                         message = (char *) "";
6368                                 } else {
6369                                         free_message = TRUE;
6370                                 }
6371                         }
6372                 }
6373         }
6374
6375         /*
6376          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
6377          *         exc->vtable->klass->name, message);
6378          */
6379         g_printerr ("\nUnhandled Exception:\n%s\n", message);
6380         
6381         if (free_message)
6382                 g_free (message);
6383 }
6384
6385 /**
6386  * mono_delegate_ctor:
6387  * @this: pointer to an uninitialized delegate object
6388  * @target: target object
6389  * @addr: pointer to native code
6390  * @method: method
6391  *
6392  * Initialize a delegate and sets a specific method, not the one
6393  * associated with addr.  This is useful when sharing generic code.
6394  * In that case addr will most probably not be associated with the
6395  * correct instantiation of the method.
6396  */
6397 void
6398 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6399 {
6400         MONO_REQ_GC_UNSAFE_MODE;
6401
6402         MonoDelegate *delegate = (MonoDelegate *)this_obj;
6403
6404         g_assert (this_obj);
6405         g_assert (addr);
6406
6407         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6408
6409         if (method)
6410                 delegate->method = method;
6411
6412         mono_stats.delegate_creations++;
6413
6414 #ifndef DISABLE_REMOTING
6415         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6416                 g_assert (method);
6417                 method = mono_marshal_get_remoting_invoke (method);
6418                 delegate->method_ptr = mono_compile_method (method);
6419                 MONO_OBJECT_SETREF (delegate, target, target);
6420         } else
6421 #endif
6422         {
6423                 delegate->method_ptr = addr;
6424                 MONO_OBJECT_SETREF (delegate, target, target);
6425         }
6426
6427         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6428 }
6429
6430 /**
6431  * mono_delegate_ctor:
6432  * @this: pointer to an uninitialized delegate object
6433  * @target: target object
6434  * @addr: pointer to native code
6435  *
6436  * This is used to initialize a delegate.
6437  */
6438 void
6439 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6440 {
6441         MONO_REQ_GC_UNSAFE_MODE;
6442
6443         MonoDomain *domain = mono_domain_get ();
6444         MonoJitInfo *ji;
6445         MonoMethod *method = NULL;
6446
6447         g_assert (addr);
6448
6449         ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6450         /* Shared code */
6451         if (!ji && domain != mono_get_root_domain ())
6452                 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6453         if (ji) {
6454                 method = mono_jit_info_get_method (ji);
6455                 g_assert (!method->klass->generic_container);
6456         }
6457
6458         mono_delegate_ctor_with_method (this_obj, target, addr, method);
6459 }
6460
6461 /**
6462  * mono_method_call_message_new:
6463  * @method: method to encapsulate
6464  * @params: parameters to the method
6465  * @invoke: optional, delegate invoke.
6466  * @cb: async callback delegate.
6467  * @state: state passed to the async callback.
6468  *
6469  * Translates arguments pointers into a MonoMethodMessage.
6470  */
6471 MonoMethodMessage *
6472 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
6473                               MonoDelegate **cb, MonoObject **state)
6474 {
6475         MONO_REQ_GC_UNSAFE_MODE;
6476
6477         MonoDomain *domain = mono_domain_get ();
6478         MonoMethodSignature *sig = mono_method_signature (method);
6479         MonoMethodMessage *msg;
6480         int i, count;
6481
6482         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
6483         
6484         if (invoke) {
6485                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6486                 count =  sig->param_count - 2;
6487         } else {
6488                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6489                 count =  sig->param_count;
6490         }
6491
6492         for (i = 0; i < count; i++) {
6493                 gpointer vpos;
6494                 MonoClass *class;
6495                 MonoObject *arg;
6496
6497                 if (sig->params [i]->byref)
6498                         vpos = *((gpointer *)params [i]);
6499                 else 
6500                         vpos = params [i];
6501
6502                 class = mono_class_from_mono_type (sig->params [i]);
6503
6504                 if (class->valuetype)
6505                         arg = mono_value_box (domain, class, vpos);
6506                 else 
6507                         arg = *((MonoObject **)vpos);
6508                       
6509                 mono_array_setref (msg->args, i, arg);
6510         }
6511
6512         if (cb != NULL && state != NULL) {
6513                 *cb = *((MonoDelegate **)params [i]);
6514                 i++;
6515                 *state = *((MonoObject **)params [i]);
6516         }
6517
6518         return msg;
6519 }
6520
6521 /**
6522  * mono_method_return_message_restore:
6523  *
6524  * Restore results from message based processing back to arguments pointers
6525  */
6526 void
6527 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6528 {
6529         MONO_REQ_GC_UNSAFE_MODE;
6530
6531         MonoMethodSignature *sig = mono_method_signature (method);
6532         int i, j, type, size, out_len;
6533         
6534         if (out_args == NULL)
6535                 return;
6536         out_len = mono_array_length (out_args);
6537         if (out_len == 0)
6538                 return;
6539
6540         for (i = 0, j = 0; i < sig->param_count; i++) {
6541                 MonoType *pt = sig->params [i];
6542
6543                 if (pt->byref) {
6544                         char *arg;
6545                         if (j >= out_len)
6546                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6547
6548                         arg = mono_array_get (out_args, gpointer, j);
6549                         type = pt->type;
6550
6551                         g_assert (type != MONO_TYPE_VOID);
6552
6553                         if (MONO_TYPE_IS_REFERENCE (pt)) {
6554                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6555                         } else {
6556                                 if (arg) {
6557                                         MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6558                                         size = mono_class_value_size (class, NULL);
6559                                         if (class->has_references)
6560                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6561                                         else
6562                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6563                                 } else {
6564                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6565                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6566                                 }
6567                         }
6568
6569                         j++;
6570                 }
6571         }
6572 }
6573
6574 #ifndef DISABLE_REMOTING
6575
6576 /**
6577  * mono_load_remote_field:
6578  * @this: pointer to an object
6579  * @klass: klass of the object containing @field
6580  * @field: the field to load
6581  * @res: a storage to store the result
6582  *
6583  * This method is called by the runtime on attempts to load fields of
6584  * transparent proxy objects. @this points to such TP, @klass is the class of
6585  * the object containing @field. @res is a storage location which can be
6586  * used to store the result.
6587  *
6588  * Returns: an address pointing to the value of field.
6589  */
6590 gpointer
6591 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6592 {
6593         MONO_REQ_GC_UNSAFE_MODE;
6594
6595         static MonoMethod *getter = NULL;
6596         MonoDomain *domain = mono_domain_get ();
6597         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6598         MonoClass *field_class;
6599         MonoMethodMessage *msg;
6600         MonoArray *out_args;
6601         MonoObject *exc;
6602         char* full_name;
6603
6604         g_assert (mono_object_is_transparent_proxy (this_obj));
6605         g_assert (res != NULL);
6606
6607         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6608                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6609                 return res;
6610         }
6611         
6612         if (!getter) {
6613                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6614                 if (!getter)
6615                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6616         }
6617         
6618         field_class = mono_class_from_mono_type (field->type);
6619
6620         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6621         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6622         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6623
6624         full_name = mono_type_get_full_name (klass);
6625         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6626         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6627         g_free (full_name);
6628
6629         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6630
6631         if (exc) mono_raise_exception ((MonoException *)exc);
6632
6633         if (mono_array_length (out_args) == 0)
6634                 return NULL;
6635
6636         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6637
6638         if (field_class->valuetype) {
6639                 return ((char *)*res) + sizeof (MonoObject);
6640         } else
6641                 return res;
6642 }
6643
6644 /**
6645  * mono_load_remote_field_new:
6646  * @this: 
6647  * @klass: 
6648  * @field:
6649  *
6650  * Missing documentation.
6651  */
6652 MonoObject *
6653 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6654 {
6655         MONO_REQ_GC_UNSAFE_MODE;
6656
6657         static MonoMethod *getter = NULL;
6658         MonoDomain *domain = mono_domain_get ();
6659         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6660         MonoClass *field_class;
6661         MonoMethodMessage *msg;
6662         MonoArray *out_args;
6663         MonoObject *exc, *res;
6664         char* full_name;
6665
6666         g_assert (mono_object_is_transparent_proxy (this_obj));
6667
6668         field_class = mono_class_from_mono_type (field->type);
6669
6670         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6671                 gpointer val;
6672                 if (field_class->valuetype) {
6673                         res = mono_object_new (domain, field_class);
6674                         val = ((gchar *) res) + sizeof (MonoObject);
6675                 } else {
6676                         val = &res;
6677                 }
6678                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6679                 return res;
6680         }
6681
6682         if (!getter) {
6683                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6684                 if (!getter)
6685                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6686         }
6687         
6688         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6689         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6690
6691         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6692
6693         full_name = mono_type_get_full_name (klass);
6694         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6695         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6696         g_free (full_name);
6697
6698         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6699
6700         if (exc) mono_raise_exception ((MonoException *)exc);
6701
6702         if (mono_array_length (out_args) == 0)
6703                 res = NULL;
6704         else
6705                 res = mono_array_get (out_args, MonoObject *, 0);
6706
6707         return res;
6708 }
6709
6710 /**
6711  * mono_store_remote_field:
6712  * @this_obj: pointer to an object
6713  * @klass: klass of the object containing @field
6714  * @field: the field to load
6715  * @val: the value/object to store
6716  *
6717  * This method is called by the runtime on attempts to store fields of
6718  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6719  * the object containing @field. @val is the new value to store in @field.
6720  */
6721 void
6722 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6723 {
6724         MONO_REQ_GC_UNSAFE_MODE;
6725
6726         static MonoMethod *setter = NULL;
6727         MonoDomain *domain = mono_domain_get ();
6728         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6729         MonoClass *field_class;
6730         MonoMethodMessage *msg;
6731         MonoArray *out_args;
6732         MonoObject *exc;
6733         MonoObject *arg;
6734         char* full_name;
6735
6736         g_assert (mono_object_is_transparent_proxy (this_obj));
6737
6738         field_class = mono_class_from_mono_type (field->type);
6739
6740         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6741                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6742                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6743                 return;
6744         }
6745
6746         if (!setter) {
6747                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6748                 if (!setter)
6749                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6750         }
6751
6752         if (field_class->valuetype)
6753                 arg = mono_value_box (domain, field_class, val);
6754         else 
6755                 arg = *((MonoObject **)val);
6756                 
6757
6758         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6759         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6760
6761         full_name = mono_type_get_full_name (klass);
6762         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6763         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6764         mono_array_setref (msg->args, 2, arg);
6765         g_free (full_name);
6766
6767         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6768
6769         if (exc) mono_raise_exception ((MonoException *)exc);
6770 }
6771
6772 /**
6773  * mono_store_remote_field_new:
6774  * @this_obj:
6775  * @klass:
6776  * @field:
6777  * @arg:
6778  *
6779  * Missing documentation
6780  */
6781 void
6782 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6783 {
6784         MONO_REQ_GC_UNSAFE_MODE;
6785
6786         static MonoMethod *setter = NULL;
6787         MonoDomain *domain = mono_domain_get ();
6788         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6789         MonoClass *field_class;
6790         MonoMethodMessage *msg;
6791         MonoArray *out_args;
6792         MonoObject *exc;
6793         char* full_name;
6794
6795         g_assert (mono_object_is_transparent_proxy (this_obj));
6796
6797         field_class = mono_class_from_mono_type (field->type);
6798
6799         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6800                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6801                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6802                 return;
6803         }
6804
6805         if (!setter) {
6806                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6807                 if (!setter)
6808                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6809         }
6810
6811         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6812         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6813
6814         full_name = mono_type_get_full_name (klass);
6815         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6816         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6817         mono_array_setref (msg->args, 2, arg);
6818         g_free (full_name);
6819
6820         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6821
6822         if (exc) mono_raise_exception ((MonoException *)exc);
6823 }
6824 #endif
6825
6826 /*
6827  * mono_create_ftnptr:
6828  *
6829  *   Given a function address, create a function descriptor for it.
6830  * This is only needed on some platforms.
6831  */
6832 gpointer
6833 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6834 {
6835         return callbacks.create_ftnptr (domain, addr);
6836 }
6837
6838 /*
6839  * mono_get_addr_from_ftnptr:
6840  *
6841  *   Given a pointer to a function descriptor, return the function address.
6842  * This is only needed on some platforms.
6843  */
6844 gpointer
6845 mono_get_addr_from_ftnptr (gpointer descr)
6846 {
6847         return callbacks.get_addr_from_ftnptr (descr);
6848 }       
6849
6850 /**
6851  * mono_string_chars:
6852  * @s: a MonoString
6853  *
6854  * Returns a pointer to the UCS16 characters stored in the MonoString
6855  */
6856 gunichar2 *
6857 mono_string_chars (MonoString *s)
6858 {
6859         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
6860
6861         return s->chars;
6862 }
6863
6864 /**
6865  * mono_string_length:
6866  * @s: MonoString
6867  *
6868  * Returns the lenght in characters of the string
6869  */
6870 int
6871 mono_string_length (MonoString *s)
6872 {
6873         MONO_REQ_GC_UNSAFE_MODE;
6874
6875         return s->length;
6876 }
6877
6878 /**
6879  * mono_array_length:
6880  * @array: a MonoArray*
6881  *
6882  * Returns the total number of elements in the array. This works for
6883  * both vectors and multidimensional arrays.
6884  */
6885 uintptr_t
6886 mono_array_length (MonoArray *array)
6887 {
6888         MONO_REQ_GC_UNSAFE_MODE;
6889
6890         return array->max_length;
6891 }
6892
6893 /**
6894  * mono_array_addr_with_size:
6895  * @array: a MonoArray*
6896  * @size: size of the array elements
6897  * @idx: index into the array
6898  *
6899  * Returns the address of the @idx element in the array.
6900  */
6901 char*
6902 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6903 {
6904         MONO_REQ_GC_UNSAFE_MODE;
6905
6906         return ((char*)(array)->vector) + size * idx;
6907 }
6908
6909
6910 MonoArray *
6911 mono_glist_to_array (GList *list, MonoClass *eclass) 
6912 {
6913         MonoDomain *domain = mono_domain_get ();
6914         MonoArray *res;
6915         int len, i;
6916
6917         if (!list)
6918                 return NULL;
6919
6920         len = g_list_length (list);
6921         res = mono_array_new (domain, eclass, len);
6922
6923         for (i = 0; list; list = list->next, i++)
6924                 mono_array_set (res, gpointer, i, list->data);
6925
6926         return res;
6927 }
6928