Merge pull request #1949 from lewurm/fixtype
[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                         // Special static fields do not have a domain-level static slot
729                         if (static_fields && mono_class_field_is_special_static (field))
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->offset == -1)
2423                         return TRUE;
2424                 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2425                         return TRUE;
2426         }
2427         return FALSE;
2428 }
2429
2430 /**
2431  * mono_class_field_get_special_static_type:
2432  * @field: The MonoClassField describing the field.
2433  *
2434  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2435  * SPECIAL_STATIC_NONE otherwise.
2436  */
2437 guint32
2438 mono_class_field_get_special_static_type (MonoClassField *field)
2439 {
2440         MONO_REQ_GC_NEUTRAL_MODE
2441
2442         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2443                 return SPECIAL_STATIC_NONE;
2444         if (mono_field_is_deleted (field))
2445                 return SPECIAL_STATIC_NONE;
2446         if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2447                 return field_is_special_static (field->parent, field);
2448         return SPECIAL_STATIC_NONE;
2449 }
2450
2451 /**
2452  * mono_class_has_special_static_fields:
2453  * 
2454  *   Returns whenever @klass has any thread/context static fields.
2455  */
2456 gboolean
2457 mono_class_has_special_static_fields (MonoClass *klass)
2458 {
2459         MONO_REQ_GC_NEUTRAL_MODE
2460
2461         MonoClassField *field;
2462         gpointer iter;
2463
2464         iter = NULL;
2465         while ((field = mono_class_get_fields (klass, &iter))) {
2466                 g_assert (field->parent == klass);
2467                 if (mono_class_field_is_special_static (field))
2468                         return TRUE;
2469         }
2470
2471         return FALSE;
2472 }
2473
2474 #ifndef DISABLE_REMOTING
2475 /**
2476  * create_remote_class_key:
2477  * Creates an array of pointers that can be used as a hash key for a remote class.
2478  * The first element of the array is the number of pointers.
2479  */
2480 static gpointer*
2481 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2482 {
2483         MONO_REQ_GC_NEUTRAL_MODE;
2484
2485         gpointer *key;
2486         int i, j;
2487         
2488         if (remote_class == NULL) {
2489                 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2490                         key = g_malloc (sizeof(gpointer) * 3);
2491                         key [0] = GINT_TO_POINTER (2);
2492                         key [1] = mono_defaults.marshalbyrefobject_class;
2493                         key [2] = extra_class;
2494                 } else {
2495                         key = g_malloc (sizeof(gpointer) * 2);
2496                         key [0] = GINT_TO_POINTER (1);
2497                         key [1] = extra_class;
2498                 }
2499         } else {
2500                 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2501                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2502                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2503                         key [1] = remote_class->proxy_class;
2504
2505                         // Keep the list of interfaces sorted
2506                         for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2507                                 if (extra_class && remote_class->interfaces [i] > extra_class) {
2508                                         key [j++] = extra_class;
2509                                         extra_class = NULL;
2510                                 }
2511                                 key [j] = remote_class->interfaces [i];
2512                         }
2513                         if (extra_class)
2514                                 key [j] = extra_class;
2515                 } else {
2516                         // Replace the old class. The interface list is the same
2517                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2518                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2519                         key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2520                         for (i = 0; i < remote_class->interface_count; i++)
2521                                 key [2 + i] = remote_class->interfaces [i];
2522                 }
2523         }
2524         
2525         return key;
2526 }
2527
2528 /**
2529  * copy_remote_class_key:
2530  *
2531  *   Make a copy of KEY in the domain and return the copy.
2532  */
2533 static gpointer*
2534 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2535 {
2536         MONO_REQ_GC_NEUTRAL_MODE
2537
2538         int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2539         gpointer *mp_key = mono_domain_alloc (domain, key_size);
2540
2541         memcpy (mp_key, key, key_size);
2542
2543         return mp_key;
2544 }
2545
2546 /**
2547  * mono_remote_class:
2548  * @domain: the application domain
2549  * @class_name: name of the remote class
2550  *
2551  * Creates and initializes a MonoRemoteClass object for a remote type. 
2552  *
2553  * Can raise an exception on failure. 
2554  */
2555 MonoRemoteClass*
2556 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2557 {
2558         MONO_REQ_GC_UNSAFE_MODE;
2559
2560         MonoError error;
2561         MonoRemoteClass *rc;
2562         gpointer* key, *mp_key;
2563         char *name;
2564         
2565         key = create_remote_class_key (NULL, proxy_class);
2566         
2567         mono_domain_lock (domain);
2568         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2569
2570         if (rc) {
2571                 g_free (key);
2572                 mono_domain_unlock (domain);
2573                 return rc;
2574         }
2575
2576         name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2577         if (!mono_error_ok (&error)) {
2578                 g_free (key);
2579                 mono_domain_unlock (domain);
2580                 mono_error_raise_exception (&error);
2581         }
2582
2583         mp_key = copy_remote_class_key (domain, key);
2584         g_free (key);
2585         key = mp_key;
2586
2587         if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2588                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2589                 rc->interface_count = 1;
2590                 rc->interfaces [0] = proxy_class;
2591                 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2592         } else {
2593                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2594                 rc->interface_count = 0;
2595                 rc->proxy_class = proxy_class;
2596         }
2597         
2598         rc->default_vtable = NULL;
2599         rc->xdomain_vtable = NULL;
2600         rc->proxy_class_name = name;
2601 #ifndef DISABLE_PERFCOUNTERS
2602         mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2603 #endif
2604
2605         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2606
2607         mono_domain_unlock (domain);
2608         return rc;
2609 }
2610
2611 /**
2612  * clone_remote_class:
2613  * Creates a copy of the remote_class, adding the provided class or interface
2614  */
2615 static MonoRemoteClass*
2616 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2617 {
2618         MONO_REQ_GC_NEUTRAL_MODE;
2619
2620         MonoRemoteClass *rc;
2621         gpointer* key, *mp_key;
2622         
2623         key = create_remote_class_key (remote_class, extra_class);
2624         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2625         if (rc != NULL) {
2626                 g_free (key);
2627                 return rc;
2628         }
2629
2630         mp_key = copy_remote_class_key (domain, key);
2631         g_free (key);
2632         key = mp_key;
2633
2634         if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2635                 int i,j;
2636                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2637                 rc->proxy_class = remote_class->proxy_class;
2638                 rc->interface_count = remote_class->interface_count + 1;
2639                 
2640                 // Keep the list of interfaces sorted, since the hash key of
2641                 // the remote class depends on this
2642                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2643                         if (remote_class->interfaces [i] > extra_class && i == j)
2644                                 rc->interfaces [j++] = extra_class;
2645                         rc->interfaces [j] = remote_class->interfaces [i];
2646                 }
2647                 if (i == j)
2648                         rc->interfaces [j] = extra_class;
2649         } else {
2650                 // Replace the old class. The interface array is the same
2651                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2652                 rc->proxy_class = extra_class;
2653                 rc->interface_count = remote_class->interface_count;
2654                 if (rc->interface_count > 0)
2655                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2656         }
2657         
2658         rc->default_vtable = NULL;
2659         rc->xdomain_vtable = NULL;
2660         rc->proxy_class_name = remote_class->proxy_class_name;
2661
2662         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2663
2664         return rc;
2665 }
2666
2667 gpointer
2668 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2669 {
2670         MONO_REQ_GC_UNSAFE_MODE;
2671
2672         mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2673         mono_domain_lock (domain);
2674         if (rp->target_domain_id != -1) {
2675                 if (remote_class->xdomain_vtable == NULL)
2676                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2677                 mono_domain_unlock (domain);
2678                 mono_loader_unlock ();
2679                 return remote_class->xdomain_vtable;
2680         }
2681         if (remote_class->default_vtable == NULL) {
2682                 MonoType *type;
2683                 MonoClass *klass;
2684                 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2685                 klass = mono_class_from_mono_type (type);
2686 #ifndef DISABLE_COM
2687                 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)))
2688                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2689                 else
2690 #endif
2691                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2692         }
2693         
2694         mono_domain_unlock (domain);
2695         mono_loader_unlock ();
2696         return remote_class->default_vtable;
2697 }
2698
2699 /**
2700  * mono_upgrade_remote_class:
2701  * @domain: the application domain
2702  * @tproxy: the proxy whose remote class has to be upgraded.
2703  * @klass: class to which the remote class can be casted.
2704  *
2705  * Updates the vtable of the remote class by adding the necessary method slots
2706  * and interface offsets so it can be safely casted to klass. klass can be a
2707  * class or an interface.
2708  */
2709 void
2710 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2711 {
2712         MONO_REQ_GC_UNSAFE_MODE;
2713
2714         MonoTransparentProxy *tproxy;
2715         MonoRemoteClass *remote_class;
2716         gboolean redo_vtable;
2717
2718         mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2719         mono_domain_lock (domain);
2720
2721         tproxy = (MonoTransparentProxy*) proxy_object;
2722         remote_class = tproxy->remote_class;
2723         
2724         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2725                 int i;
2726                 redo_vtable = TRUE;
2727                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2728                         if (remote_class->interfaces [i] == klass)
2729                                 redo_vtable = FALSE;
2730         }
2731         else {
2732                 redo_vtable = (remote_class->proxy_class != klass);
2733         }
2734
2735         if (redo_vtable) {
2736                 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2737                 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2738         }
2739         
2740         mono_domain_unlock (domain);
2741         mono_loader_unlock ();
2742 }
2743 #endif /* DISABLE_REMOTING */
2744
2745
2746 /**
2747  * mono_object_get_virtual_method:
2748  * @obj: object to operate on.
2749  * @method: method 
2750  *
2751  * Retrieves the MonoMethod that would be called on obj if obj is passed as
2752  * the instance of a callvirt of method.
2753  */
2754 MonoMethod*
2755 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2756 {
2757         MONO_REQ_GC_UNSAFE_MODE;
2758
2759         MonoClass *klass;
2760         MonoMethod **vtable;
2761         gboolean is_proxy = FALSE;
2762         MonoMethod *res = NULL;
2763
2764         klass = mono_object_class (obj);
2765 #ifndef DISABLE_REMOTING
2766         if (klass == mono_defaults.transparent_proxy_class) {
2767                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2768                 is_proxy = TRUE;
2769         }
2770 #endif
2771
2772         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2773                         return method;
2774
2775         mono_class_setup_vtable (klass);
2776         vtable = klass->vtable;
2777
2778         if (method->slot == -1) {
2779                 /* method->slot might not be set for instances of generic methods */
2780                 if (method->is_inflated) {
2781                         g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2782                         method->slot = ((MonoMethodInflated*)method)->declaring->slot; 
2783                 } else {
2784                         if (!is_proxy)
2785                                 g_assert_not_reached ();
2786                 }
2787         }
2788
2789         /* check method->slot is a valid index: perform isinstance? */
2790         if (method->slot != -1) {
2791                 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2792                         if (!is_proxy) {
2793                                 gboolean variance_used = FALSE;
2794                                 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2795                                 g_assert (iface_offset > 0);
2796                                 res = vtable [iface_offset + method->slot];
2797                         }
2798                 } else {
2799                         res = vtable [method->slot];
2800                 }
2801     }
2802
2803 #ifndef DISABLE_REMOTING
2804         if (is_proxy) {
2805                 /* It may be an interface, abstract class method or generic method */
2806                 if (!res || mono_method_signature (res)->generic_param_count)
2807                         res = method;
2808
2809                 /* generic methods demand invoke_with_check */
2810                 if (mono_method_signature (res)->generic_param_count)
2811                         res = mono_marshal_get_remoting_invoke_with_check (res);
2812                 else {
2813 #ifndef DISABLE_COM
2814                         if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2815                                 res = mono_cominterop_get_invoke (res);
2816                         else
2817 #endif
2818                                 res = mono_marshal_get_remoting_invoke (res);
2819                 }
2820         } else
2821 #endif
2822         {
2823                 if (method->is_inflated) {
2824                         MonoError error;
2825                         /* Have to inflate the result */
2826                         res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2827                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2828                 }
2829         }
2830
2831         g_assert (res);
2832         
2833         return res;
2834 }
2835
2836 static MonoObject*
2837 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2838 {
2839         g_error ("runtime invoke called on uninitialized runtime");
2840         return NULL;
2841 }
2842
2843 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2844
2845 /**
2846  * mono_runtime_invoke:
2847  * @method: method to invoke
2848  * @obJ: object instance
2849  * @params: arguments to the method
2850  * @exc: exception information.
2851  *
2852  * Invokes the method represented by @method on the object @obj.
2853  *
2854  * obj is the 'this' pointer, it should be NULL for static
2855  * methods, a MonoObject* for object instances and a pointer to
2856  * the value type for value types.
2857  *
2858  * The params array contains the arguments to the method with the
2859  * same convention: MonoObject* pointers for object instances and
2860  * pointers to the value type otherwise. 
2861  * 
2862  * From unmanaged code you'll usually use the
2863  * mono_runtime_invoke() variant.
2864  *
2865  * Note that this function doesn't handle virtual methods for
2866  * you, it will exec the exact method you pass: we still need to
2867  * expose a function to lookup the derived class implementation
2868  * of a virtual method (there are examples of this in the code,
2869  * though).
2870  * 
2871  * You can pass NULL as the exc argument if you don't want to
2872  * catch exceptions, otherwise, *exc will be set to the exception
2873  * thrown, if any.  if an exception is thrown, you can't use the
2874  * MonoObject* result from the function.
2875  * 
2876  * If the method returns a value type, it is boxed in an object
2877  * reference.
2878  */
2879 MonoObject*
2880 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2881 {
2882         MONO_REQ_GC_UNSAFE_MODE;
2883
2884         MonoObject *result;
2885
2886         if (mono_runtime_get_no_exec ())
2887                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2888
2889         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2890                 mono_profiler_method_start_invoke (method);
2891
2892         result = default_mono_runtime_invoke (method, obj, params, exc);
2893
2894         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2895                 mono_profiler_method_end_invoke (method);
2896
2897         return result;
2898 }
2899
2900 /**
2901  * mono_method_get_unmanaged_thunk:
2902  * @method: method to generate a thunk for.
2903  *
2904  * Returns an unmanaged->managed thunk that can be used to call
2905  * a managed method directly from C.
2906  *
2907  * The thunk's C signature closely matches the managed signature:
2908  *
2909  * C#: public bool Equals (object obj);
2910  * C:  typedef MonoBoolean (*Equals)(MonoObject*,
2911  *             MonoObject*, MonoException**);
2912  *
2913  * The 1st ("this") parameter must not be used with static methods:
2914  *
2915  * C#: public static bool ReferenceEquals (object a, object b);
2916  * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2917  *             MonoException**);
2918  *
2919  * The last argument must be a non-null pointer of a MonoException* pointer.
2920  * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2921  * exception has been thrown in managed code. Otherwise it will point
2922  * to the MonoException* caught by the thunk. In this case, the result of
2923  * the thunk is undefined:
2924  *
2925  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2926  * MonoException *ex = NULL;
2927  * Equals func = mono_method_get_unmanaged_thunk (method);
2928  * MonoBoolean res = func (thisObj, objToCompare, &ex);
2929  * if (ex) {
2930  *    // handle exception
2931  * }
2932  *
2933  * The calling convention of the thunk matches the platform's default
2934  * convention. This means that under Windows, C declarations must
2935  * contain the __stdcall attribute:
2936  *
2937  * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2938  *             MonoObject*, MonoException**);
2939  *
2940  * LIMITATIONS
2941  *
2942  * Value type arguments and return values are treated as they were objects:
2943  *
2944  * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2945  * C:  typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2946  *
2947  * Arguments must be properly boxed upon trunk's invocation, while return
2948  * values must be unboxed.
2949  */
2950 gpointer
2951 mono_method_get_unmanaged_thunk (MonoMethod *method)
2952 {
2953         MONO_REQ_GC_NEUTRAL_MODE;
2954         MONO_REQ_API_ENTRYPOINT;
2955
2956         gpointer res;
2957
2958         MONO_PREPARE_RESET_BLOCKING
2959         method = mono_marshal_get_thunk_invoke_wrapper (method);
2960         res = mono_compile_method (method);
2961         MONO_FINISH_RESET_BLOCKING
2962
2963         return res;
2964 }
2965
2966 void
2967 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2968 {
2969         MONO_REQ_GC_UNSAFE_MODE;
2970
2971         int t;
2972         if (type->byref) {
2973                 /* object fields cannot be byref, so we don't need a
2974                    wbarrier here */
2975                 gpointer *p = (gpointer*)dest;
2976                 *p = value;
2977                 return;
2978         }
2979         t = type->type;
2980 handle_enum:
2981         switch (t) {
2982         case MONO_TYPE_BOOLEAN:
2983         case MONO_TYPE_I1:
2984         case MONO_TYPE_U1: {
2985                 guint8 *p = (guint8*)dest;
2986                 *p = value ? *(guint8*)value : 0;
2987                 return;
2988         }
2989         case MONO_TYPE_I2:
2990         case MONO_TYPE_U2:
2991         case MONO_TYPE_CHAR: {
2992                 guint16 *p = (guint16*)dest;
2993                 *p = value ? *(guint16*)value : 0;
2994                 return;
2995         }
2996 #if SIZEOF_VOID_P == 4
2997         case MONO_TYPE_I:
2998         case MONO_TYPE_U:
2999 #endif
3000         case MONO_TYPE_I4:
3001         case MONO_TYPE_U4: {
3002                 gint32 *p = (gint32*)dest;
3003                 *p = value ? *(gint32*)value : 0;
3004                 return;
3005         }
3006 #if SIZEOF_VOID_P == 8
3007         case MONO_TYPE_I:
3008         case MONO_TYPE_U:
3009 #endif
3010         case MONO_TYPE_I8:
3011         case MONO_TYPE_U8: {
3012                 gint64 *p = (gint64*)dest;
3013                 *p = value ? *(gint64*)value : 0;
3014                 return;
3015         }
3016         case MONO_TYPE_R4: {
3017                 float *p = (float*)dest;
3018                 *p = value ? *(float*)value : 0;
3019                 return;
3020         }
3021         case MONO_TYPE_R8: {
3022                 double *p = (double*)dest;
3023                 *p = value ? *(double*)value : 0;
3024                 return;
3025         }
3026         case MONO_TYPE_STRING:
3027         case MONO_TYPE_SZARRAY:
3028         case MONO_TYPE_CLASS:
3029         case MONO_TYPE_OBJECT:
3030         case MONO_TYPE_ARRAY:
3031                 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
3032                 return;
3033         case MONO_TYPE_FNPTR:
3034         case MONO_TYPE_PTR: {
3035                 gpointer *p = (gpointer*)dest;
3036                 *p = deref_pointer? *(gpointer*)value: value;
3037                 return;
3038         }
3039         case MONO_TYPE_VALUETYPE:
3040                 /* note that 't' and 'type->type' can be different */
3041                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3042                         t = mono_class_enum_basetype (type->data.klass)->type;
3043                         goto handle_enum;
3044                 } else {
3045                         MonoClass *class = mono_class_from_mono_type (type);
3046                         int size = mono_class_value_size (class, NULL);
3047                         if (value == NULL)
3048                                 mono_gc_bzero_atomic (dest, size);
3049                         else
3050                                 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3051                 }
3052                 return;
3053         case MONO_TYPE_GENERICINST:
3054                 t = type->data.generic_class->container_class->byval_arg.type;
3055                 goto handle_enum;
3056         default:
3057                 g_error ("got type %x", type->type);
3058         }
3059 }
3060
3061 /**
3062  * mono_field_set_value:
3063  * @obj: Instance object
3064  * @field: MonoClassField describing the field to set
3065  * @value: The value to be set
3066  *
3067  * Sets the value of the field described by @field in the object instance @obj
3068  * to the value passed in @value.   This method should only be used for instance
3069  * fields.   For static fields, use mono_field_static_set_value.
3070  *
3071  * The value must be on the native format of the field type. 
3072  */
3073 void
3074 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3075 {
3076         MONO_REQ_GC_UNSAFE_MODE;
3077
3078         void *dest;
3079
3080         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3081
3082         dest = (char*)obj + field->offset;
3083         mono_copy_value (field->type, dest, value, FALSE);
3084 }
3085
3086 /**
3087  * mono_field_static_set_value:
3088  * @field: MonoClassField describing the field to set
3089  * @value: The value to be set
3090  *
3091  * Sets the value of the static field described by @field
3092  * to the value passed in @value.
3093  *
3094  * The value must be on the native format of the field type. 
3095  */
3096 void
3097 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3098 {
3099         MONO_REQ_GC_UNSAFE_MODE;
3100
3101         void *dest;
3102
3103         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3104         /* you cant set a constant! */
3105         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3106
3107         if (field->offset == -1) {
3108                 /* Special static */
3109                 gpointer addr;
3110
3111                 mono_domain_lock (vt->domain);
3112                 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3113                 mono_domain_unlock (vt->domain);
3114                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3115         } else {
3116                 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3117         }
3118         mono_copy_value (field->type, dest, value, FALSE);
3119 }
3120
3121 /**
3122  * mono_vtable_get_static_field_data:
3123  *
3124  * Internal use function: return a pointer to the memory holding the static fields
3125  * for a class or NULL if there are no static fields.
3126  * This is exported only for use by the debugger.
3127  */
3128 void *
3129 mono_vtable_get_static_field_data (MonoVTable *vt)
3130 {
3131         MONO_REQ_GC_NEUTRAL_MODE
3132
3133         if (!vt->has_static_fields)
3134                 return NULL;
3135         return vt->vtable [vt->klass->vtable_size];
3136 }
3137
3138 static guint8*
3139 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3140 {
3141         MONO_REQ_GC_UNSAFE_MODE;
3142
3143         guint8 *src;
3144
3145         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3146                 if (field->offset == -1) {
3147                         /* Special static */
3148                         gpointer addr;
3149
3150                         mono_domain_lock (vt->domain);
3151                         addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3152                         mono_domain_unlock (vt->domain);
3153                         src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3154                 } else {
3155                         src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3156                 }
3157         } else {
3158                 src = (guint8*)obj + field->offset;
3159         }
3160
3161         return src;
3162 }
3163
3164 /**
3165  * mono_field_get_value:
3166  * @obj: Object instance
3167  * @field: MonoClassField describing the field to fetch information from
3168  * @value: pointer to the location where the value will be stored
3169  *
3170  * Use this routine to get the value of the field @field in the object
3171  * passed.
3172  *
3173  * The pointer provided by value must be of the field type, for reference
3174  * types this is a MonoObject*, for value types its the actual pointer to
3175  * the value type.
3176  *
3177  * For example:
3178  *     int i;
3179  *     mono_field_get_value (obj, int_field, &i);
3180  */
3181 void
3182 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3183 {
3184         MONO_REQ_GC_UNSAFE_MODE;
3185
3186         void *src;
3187
3188         g_assert (obj);
3189
3190         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3191
3192         src = (char*)obj + field->offset;
3193         mono_copy_value (field->type, value, src, TRUE);
3194 }
3195
3196 /**
3197  * mono_field_get_value_object:
3198  * @domain: domain where the object will be created (if boxing)
3199  * @field: MonoClassField describing the field to fetch information from
3200  * @obj: The object instance for the field.
3201  *
3202  * Returns: a new MonoObject with the value from the given field.  If the
3203  * field represents a value type, the value is boxed.
3204  *
3205  */
3206 MonoObject *
3207 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3208 {       
3209         MONO_REQ_GC_UNSAFE_MODE;
3210
3211         MonoObject *o;
3212         MonoClass *klass;
3213         MonoVTable *vtable = NULL;
3214         gchar *v;
3215         gboolean is_static = FALSE;
3216         gboolean is_ref = FALSE;
3217         gboolean is_literal = FALSE;
3218         gboolean is_ptr = FALSE;
3219         MonoError error;
3220         MonoType *type = mono_field_get_type_checked (field, &error);
3221
3222         if (!mono_error_ok (&error))
3223                 mono_error_raise_exception (&error);
3224
3225         switch (type->type) {
3226         case MONO_TYPE_STRING:
3227         case MONO_TYPE_OBJECT:
3228         case MONO_TYPE_CLASS:
3229         case MONO_TYPE_ARRAY:
3230         case MONO_TYPE_SZARRAY:
3231                 is_ref = TRUE;
3232                 break;
3233         case MONO_TYPE_U1:
3234         case MONO_TYPE_I1:
3235         case MONO_TYPE_BOOLEAN:
3236         case MONO_TYPE_U2:
3237         case MONO_TYPE_I2:
3238         case MONO_TYPE_CHAR:
3239         case MONO_TYPE_U:
3240         case MONO_TYPE_I:
3241         case MONO_TYPE_U4:
3242         case MONO_TYPE_I4:
3243         case MONO_TYPE_R4:
3244         case MONO_TYPE_U8:
3245         case MONO_TYPE_I8:
3246         case MONO_TYPE_R8:
3247         case MONO_TYPE_VALUETYPE:
3248                 is_ref = type->byref;
3249                 break;
3250         case MONO_TYPE_GENERICINST:
3251                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3252                 break;
3253         case MONO_TYPE_PTR:
3254                 is_ptr = TRUE;
3255                 break;
3256         default:
3257                 g_error ("type 0x%x not handled in "
3258                          "mono_field_get_value_object", type->type);
3259                 return NULL;
3260         }
3261
3262         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3263                 is_literal = TRUE;
3264
3265         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3266                 is_static = TRUE;
3267
3268                 if (!is_literal) {
3269                         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3270                         if (!vtable->initialized)
3271                                 mono_runtime_class_init (vtable);
3272                 }
3273         } else {
3274                 g_assert (obj);
3275         }
3276         
3277         if (is_ref) {
3278                 if (is_literal) {
3279                         get_default_field_value (domain, field, &o);
3280                 } else if (is_static) {
3281                         mono_field_static_get_value (vtable, field, &o);
3282                 } else {
3283                         mono_field_get_value (obj, field, &o);
3284                 }
3285                 return o;
3286         }
3287
3288         if (is_ptr) {
3289                 static MonoMethod *m;
3290                 gpointer args [2];
3291                 gpointer *ptr;
3292                 gpointer v;
3293
3294                 if (!m) {
3295                         MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3296                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3297                         g_assert (m);
3298                 }
3299
3300                 v = &ptr;
3301                 if (is_literal) {
3302                         get_default_field_value (domain, field, v);
3303                 } else if (is_static) {
3304                         mono_field_static_get_value (vtable, field, v);
3305                 } else {
3306                         mono_field_get_value (obj, field, v);
3307                 }
3308
3309                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3310                 args [0] = ptr ? *ptr : NULL;
3311                 args [1] = mono_type_get_object (mono_domain_get (), type);
3312
3313                 return mono_runtime_invoke (m, NULL, args, NULL);
3314         }
3315
3316         /* boxed value type */
3317         klass = mono_class_from_mono_type (type);
3318
3319         if (mono_class_is_nullable (klass))
3320                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3321
3322         o = mono_object_new (domain, klass);
3323         v = ((gchar *) o) + sizeof (MonoObject);
3324
3325         if (is_literal) {
3326                 get_default_field_value (domain, field, v);
3327         } else if (is_static) {
3328                 mono_field_static_get_value (vtable, field, v);
3329         } else {
3330                 mono_field_get_value (obj, field, v);
3331         }
3332
3333         return o;
3334 }
3335
3336 int
3337 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3338 {
3339         MONO_REQ_GC_UNSAFE_MODE;
3340
3341         int retval = 0;
3342         const char *p = blob;
3343         mono_metadata_decode_blob_size (p, &p);
3344
3345         switch (type) {
3346         case MONO_TYPE_BOOLEAN:
3347         case MONO_TYPE_U1:
3348         case MONO_TYPE_I1:
3349                 *(guint8 *) value = *p;
3350                 break;
3351         case MONO_TYPE_CHAR:
3352         case MONO_TYPE_U2:
3353         case MONO_TYPE_I2:
3354                 *(guint16*) value = read16 (p);
3355                 break;
3356         case MONO_TYPE_U4:
3357         case MONO_TYPE_I4:
3358                 *(guint32*) value = read32 (p);
3359                 break;
3360         case MONO_TYPE_U8:
3361         case MONO_TYPE_I8:
3362                 *(guint64*) value = read64 (p);
3363                 break;
3364         case MONO_TYPE_R4:
3365                 readr4 (p, (float*) value);
3366                 break;
3367         case MONO_TYPE_R8:
3368                 readr8 (p, (double*) value);
3369                 break;
3370         case MONO_TYPE_STRING:
3371                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3372                 break;
3373         case MONO_TYPE_CLASS:
3374                 *(gpointer*) value = NULL;
3375                 break;
3376         default:
3377                 retval = -1;
3378                 g_warning ("type 0x%02x should not be in constant table", type);
3379         }
3380         return retval;
3381 }
3382
3383 static void
3384 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3385 {
3386         MONO_REQ_GC_NEUTRAL_MODE;
3387
3388         MonoTypeEnum def_type;
3389         const char* data;
3390         
3391         data = mono_class_get_field_default_value (field, &def_type);
3392         mono_get_constant_value_from_blob (domain, def_type, data, value);
3393 }
3394
3395 void
3396 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3397 {
3398         MONO_REQ_GC_UNSAFE_MODE;
3399
3400         void *src;
3401
3402         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3403         
3404         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3405                 get_default_field_value (vt->domain, field, value);
3406                 return;
3407         }
3408
3409         if (field->offset == -1) {
3410                 /* Special static */
3411                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3412                 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3413         } else {
3414                 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3415         }
3416         mono_copy_value (field->type, value, src, TRUE);
3417 }
3418
3419 /**
3420  * mono_field_static_get_value:
3421  * @vt: vtable to the object
3422  * @field: MonoClassField describing the field to fetch information from
3423  * @value: where the value is returned
3424  *
3425  * Use this routine to get the value of the static field @field value.
3426  *
3427  * The pointer provided by value must be of the field type, for reference
3428  * types this is a MonoObject*, for value types its the actual pointer to
3429  * the value type.
3430  *
3431  * For example:
3432  *     int i;
3433  *     mono_field_static_get_value (vt, int_field, &i);
3434  */
3435 void
3436 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3437 {
3438         MONO_REQ_GC_NEUTRAL_MODE;
3439
3440         mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3441 }
3442
3443 /**
3444  * mono_property_set_value:
3445  * @prop: MonoProperty to set
3446  * @obj: instance object on which to act
3447  * @params: parameters to pass to the propery
3448  * @exc: optional exception
3449  *
3450  * Invokes the property's set method with the given arguments on the
3451  * object instance obj (or NULL for static properties). 
3452  * 
3453  * You can pass NULL as the exc argument if you don't want to
3454  * catch exceptions, otherwise, *exc will be set to the exception
3455  * thrown, if any.  if an exception is thrown, you can't use the
3456  * MonoObject* result from the function.
3457  */
3458 void
3459 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3460 {
3461         MONO_REQ_GC_UNSAFE_MODE;
3462
3463         default_mono_runtime_invoke (prop->set, obj, params, exc);
3464 }
3465
3466 /**
3467  * mono_property_get_value:
3468  * @prop: MonoProperty to fetch
3469  * @obj: instance object on which to act
3470  * @params: parameters to pass to the propery
3471  * @exc: optional exception
3472  *
3473  * Invokes the property's get method with the given arguments on the
3474  * object instance obj (or NULL for static properties). 
3475  * 
3476  * You can pass NULL as the exc argument if you don't want to
3477  * catch exceptions, otherwise, *exc will be set to the exception
3478  * thrown, if any.  if an exception is thrown, you can't use the
3479  * MonoObject* result from the function.
3480  *
3481  * Returns: the value from invoking the get method on the property.
3482  */
3483 MonoObject*
3484 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3485 {
3486         MONO_REQ_GC_UNSAFE_MODE;
3487
3488         return default_mono_runtime_invoke (prop->get, obj, params, exc);
3489 }
3490
3491 /*
3492  * mono_nullable_init:
3493  * @buf: The nullable structure to initialize.
3494  * @value: the value to initialize from
3495  * @klass: the type for the object
3496  *
3497  * Initialize the nullable structure pointed to by @buf from @value which
3498  * should be a boxed value type.   The size of @buf should be able to hold
3499  * as much data as the @klass->instance_size (which is the number of bytes
3500  * that will be copies).
3501  *
3502  * Since Nullables have variable structure, we can not define a C
3503  * structure for them.
3504  */
3505 void
3506 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3507 {
3508         MONO_REQ_GC_UNSAFE_MODE;
3509
3510         MonoClass *param_class = klass->cast_class;
3511
3512         mono_class_setup_fields_locking (klass);
3513         g_assert (klass->fields_inited);
3514                                 
3515         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3516         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3517
3518         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3519         if (value) {
3520                 if (param_class->has_references)
3521                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3522                 else
3523                         mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3524         } else {
3525                 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3526         }
3527 }
3528
3529 /**
3530  * mono_nullable_box:
3531  * @buf: The buffer representing the data to be boxed
3532  * @klass: the type to box it as.
3533  *
3534  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3535  * @buf.
3536  */
3537 MonoObject*
3538 mono_nullable_box (guint8 *buf, MonoClass *klass)
3539 {
3540         MONO_REQ_GC_UNSAFE_MODE;
3541
3542         MonoClass *param_class = klass->cast_class;
3543
3544         mono_class_setup_fields_locking (klass);
3545         g_assert (klass->fields_inited);
3546
3547         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3548         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3549
3550         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3551                 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3552                 if (param_class->has_references)
3553                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3554                 else
3555                         mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3556                 return o;
3557         }
3558         else
3559                 return NULL;
3560 }
3561
3562 /**
3563  * mono_get_delegate_invoke:
3564  * @klass: The delegate class
3565  *
3566  * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3567  */
3568 MonoMethod *
3569 mono_get_delegate_invoke (MonoClass *klass)
3570 {
3571         MONO_REQ_GC_NEUTRAL_MODE;
3572
3573         MonoMethod *im;
3574
3575         /* This is called at runtime, so avoid the slower search in metadata */
3576         mono_class_setup_methods (klass);
3577         if (klass->exception_type)
3578                 return NULL;
3579         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3580         return im;
3581 }
3582
3583 /**
3584  * mono_get_delegate_begin_invoke:
3585  * @klass: The delegate class
3586  *
3587  * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3588  */
3589 MonoMethod *
3590 mono_get_delegate_begin_invoke (MonoClass *klass)
3591 {
3592         MONO_REQ_GC_NEUTRAL_MODE;
3593
3594         MonoMethod *im;
3595
3596         /* This is called at runtime, so avoid the slower search in metadata */
3597         mono_class_setup_methods (klass);
3598         if (klass->exception_type)
3599                 return NULL;
3600         im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3601         return im;
3602 }
3603
3604 /**
3605  * mono_get_delegate_end_invoke:
3606  * @klass: The delegate class
3607  *
3608  * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3609  */
3610 MonoMethod *
3611 mono_get_delegate_end_invoke (MonoClass *klass)
3612 {
3613         MONO_REQ_GC_NEUTRAL_MODE;
3614
3615         MonoMethod *im;
3616
3617         /* This is called at runtime, so avoid the slower search in metadata */
3618         mono_class_setup_methods (klass);
3619         if (klass->exception_type)
3620                 return NULL;
3621         im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3622         return im;
3623 }
3624
3625 /**
3626  * mono_runtime_delegate_invoke:
3627  * @delegate: pointer to a delegate object.
3628  * @params: parameters for the delegate.
3629  * @exc: Pointer to the exception result.
3630  *
3631  * Invokes the delegate method @delegate with the parameters provided.
3632  *
3633  * You can pass NULL as the exc argument if you don't want to
3634  * catch exceptions, otherwise, *exc will be set to the exception
3635  * thrown, if any.  if an exception is thrown, you can't use the
3636  * MonoObject* result from the function.
3637  */
3638 MonoObject*
3639 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3640 {
3641         MONO_REQ_GC_UNSAFE_MODE;
3642
3643         MonoMethod *im;
3644         MonoClass *klass = delegate->vtable->klass;
3645
3646         im = mono_get_delegate_invoke (klass);
3647         if (!im)
3648                 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3649
3650         return mono_runtime_invoke (im, delegate, params, exc);
3651 }
3652
3653 static char **main_args = NULL;
3654 static int num_main_args = 0;
3655
3656 /**
3657  * mono_runtime_get_main_args:
3658  *
3659  * Returns: a MonoArray with the arguments passed to the main program
3660  */
3661 MonoArray*
3662 mono_runtime_get_main_args (void)
3663 {
3664         MONO_REQ_GC_UNSAFE_MODE;
3665
3666         MonoArray *res;
3667         int i;
3668         MonoDomain *domain = mono_domain_get ();
3669
3670         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3671
3672         for (i = 0; i < num_main_args; ++i)
3673                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3674
3675         return res;
3676 }
3677
3678 static void
3679 free_main_args (void)
3680 {
3681         MONO_REQ_GC_NEUTRAL_MODE;
3682
3683         int i;
3684
3685         for (i = 0; i < num_main_args; ++i)
3686                 g_free (main_args [i]);
3687         g_free (main_args);
3688         num_main_args = 0;
3689         main_args = NULL;
3690 }
3691
3692 /**
3693  * mono_runtime_set_main_args:
3694  * @argc: number of arguments from the command line
3695  * @argv: array of strings from the command line
3696  *
3697  * Set the command line arguments from an embedding application that doesn't otherwise call
3698  * mono_runtime_run_main ().
3699  */
3700 int
3701 mono_runtime_set_main_args (int argc, char* argv[])
3702 {
3703         MONO_REQ_GC_NEUTRAL_MODE;
3704
3705         int i;
3706
3707         free_main_args ();
3708         main_args = g_new0 (char*, argc);
3709         num_main_args = argc;
3710
3711         for (i = 0; i < argc; ++i) {
3712                 gchar *utf8_arg;
3713
3714                 utf8_arg = mono_utf8_from_external (argv[i]);
3715                 if (utf8_arg == NULL) {
3716                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3717                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3718                         exit (-1);
3719                 }
3720
3721                 main_args [i] = utf8_arg;
3722         }
3723
3724         return 0;
3725 }
3726
3727 /**
3728  * mono_runtime_run_main:
3729  * @method: the method to start the application with (usually Main)
3730  * @argc: number of arguments from the command line
3731  * @argv: array of strings from the command line
3732  * @exc: excetption results
3733  *
3734  * Execute a standard Main() method (argc/argv contains the
3735  * executable name). This method also sets the command line argument value
3736  * needed by System.Environment.
3737  *
3738  * 
3739  */
3740 int
3741 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3742                        MonoObject **exc)
3743 {
3744         MONO_REQ_GC_UNSAFE_MODE;
3745
3746         int i;
3747         MonoArray *args = NULL;
3748         MonoDomain *domain = mono_domain_get ();
3749         gchar *utf8_fullpath;
3750         MonoMethodSignature *sig;
3751
3752         g_assert (method != NULL);
3753         
3754         mono_thread_set_main (mono_thread_current ());
3755
3756         main_args = g_new0 (char*, argc);
3757         num_main_args = argc;
3758
3759         if (!g_path_is_absolute (argv [0])) {
3760                 gchar *basename = g_path_get_basename (argv [0]);
3761                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3762                                                     basename,
3763                                                     NULL);
3764
3765                 utf8_fullpath = mono_utf8_from_external (fullpath);
3766                 if(utf8_fullpath == NULL) {
3767                         /* Printing the arg text will cause glib to
3768                          * whinge about "Invalid UTF-8", but at least
3769                          * its relevant, and shows the problem text
3770                          * string.
3771                          */
3772                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3773                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3774                         exit (-1);
3775                 }
3776
3777                 g_free (fullpath);
3778                 g_free (basename);
3779         } else {
3780                 utf8_fullpath = mono_utf8_from_external (argv[0]);
3781                 if(utf8_fullpath == NULL) {
3782                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3783                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3784                         exit (-1);
3785                 }
3786         }
3787
3788         main_args [0] = utf8_fullpath;
3789
3790         for (i = 1; i < argc; ++i) {
3791                 gchar *utf8_arg;
3792
3793                 utf8_arg=mono_utf8_from_external (argv[i]);
3794                 if(utf8_arg==NULL) {
3795                         /* Ditto the comment about Invalid UTF-8 here */
3796                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3797                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3798                         exit (-1);
3799                 }
3800
3801                 main_args [i] = utf8_arg;
3802         }
3803         argc--;
3804         argv++;
3805
3806         sig = mono_method_signature (method);
3807         if (!sig) {
3808                 g_print ("Unable to load Main method.\n");
3809                 exit (-1);
3810         }
3811
3812         if (sig->param_count) {
3813                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3814                 for (i = 0; i < argc; ++i) {
3815                         /* The encodings should all work, given that
3816                          * we've checked all these args for the
3817                          * main_args array.
3818                          */
3819                         gchar *str = mono_utf8_from_external (argv [i]);
3820                         MonoString *arg = mono_string_new (domain, str);
3821                         mono_array_setref (args, i, arg);
3822                         g_free (str);
3823                 }
3824         } else {
3825                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3826         }
3827         
3828         mono_assembly_set_main (method->klass->image->assembly);
3829
3830         return mono_runtime_exec_main (method, args, exc);
3831 }
3832
3833 static MonoObject*
3834 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3835 {
3836         static MonoMethod *serialize_method;
3837
3838         void *params [1];
3839         MonoObject *array;
3840
3841         if (!serialize_method) {
3842                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3843                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3844         }
3845
3846         if (!serialize_method) {
3847                 *failure = TRUE;
3848                 return NULL;
3849         }
3850
3851         g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3852
3853         params [0] = obj;
3854         *exc = NULL;
3855         array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3856         if (*exc)
3857                 *failure = TRUE;
3858
3859         return array;
3860 }
3861
3862 static MonoObject*
3863 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3864 {
3865         MONO_REQ_GC_UNSAFE_MODE;
3866
3867         static MonoMethod *deserialize_method;
3868
3869         void *params [1];
3870         MonoObject *result;
3871
3872         if (!deserialize_method) {
3873                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3874                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3875         }
3876         if (!deserialize_method) {
3877                 *failure = TRUE;
3878                 return NULL;
3879         }
3880
3881         params [0] = obj;
3882         *exc = NULL;
3883         result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3884         if (*exc)
3885                 *failure = TRUE;
3886
3887         return result;
3888 }
3889
3890 #ifndef DISABLE_REMOTING
3891 static MonoObject*
3892 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3893 {
3894         MONO_REQ_GC_UNSAFE_MODE;
3895
3896         static MonoMethod *get_proxy_method;
3897
3898         MonoDomain *domain = mono_domain_get ();
3899         MonoRealProxy *real_proxy;
3900         MonoReflectionType *reflection_type;
3901         MonoTransparentProxy *transparent_proxy;
3902
3903         if (!get_proxy_method)
3904                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3905
3906         g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3907
3908         real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3909         reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3910
3911         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3912         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3913
3914         *exc = NULL;
3915         transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3916         if (*exc)
3917                 *failure = TRUE;
3918
3919         return (MonoObject*) transparent_proxy;
3920 }
3921 #endif /* DISABLE_REMOTING */
3922
3923 /**
3924  * mono_object_xdomain_representation
3925  * @obj: an object
3926  * @target_domain: a domain
3927  * @exc: pointer to a MonoObject*
3928  *
3929  * Creates a representation of obj in the domain target_domain.  This
3930  * is either a copy of obj arrived through via serialization and
3931  * deserialization or a proxy, depending on whether the object is
3932  * serializable or marshal by ref.  obj must not be in target_domain.
3933  *
3934  * If the object cannot be represented in target_domain, NULL is
3935  * returned and *exc is set to an appropriate exception.
3936  */
3937 MonoObject*
3938 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3939 {
3940         MONO_REQ_GC_UNSAFE_MODE;
3941
3942         MonoObject *deserialized = NULL;
3943         gboolean failure = FALSE;
3944
3945         *exc = NULL;
3946
3947 #ifndef DISABLE_REMOTING
3948         if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3949                 deserialized = make_transparent_proxy (obj, &failure, exc);
3950         } 
3951         else
3952 #endif
3953         {
3954                 MonoDomain *domain = mono_domain_get ();
3955                 MonoObject *serialized;
3956
3957                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3958                 serialized = serialize_object (obj, &failure, exc);
3959                 mono_domain_set_internal_with_options (target_domain, FALSE);
3960                 if (!failure)
3961                         deserialized = deserialize_object (serialized, &failure, exc);
3962                 if (domain != target_domain)
3963                         mono_domain_set_internal_with_options (domain, FALSE);
3964         }
3965
3966         return deserialized;
3967 }
3968
3969 /* Used in call_unhandled_exception_delegate */
3970 static MonoObject *
3971 create_unhandled_exception_eventargs (MonoObject *exc)
3972 {
3973         MONO_REQ_GC_UNSAFE_MODE;
3974
3975         MonoClass *klass;
3976         gpointer args [2];
3977         MonoMethod *method = NULL;
3978         MonoBoolean is_terminating = TRUE;
3979         MonoObject *obj;
3980
3981         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3982         g_assert (klass);
3983
3984         mono_class_init (klass);
3985
3986         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3987         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3988         g_assert (method);
3989
3990         args [0] = exc;
3991         args [1] = &is_terminating;
3992
3993         obj = mono_object_new (mono_domain_get (), klass);
3994         mono_runtime_invoke (method, obj, args, NULL);
3995
3996         return obj;
3997 }
3998
3999 /* Used in mono_unhandled_exception */
4000 static void
4001 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4002         MONO_REQ_GC_UNSAFE_MODE;
4003
4004         MonoObject *e = NULL;
4005         gpointer pa [2];
4006         MonoDomain *current_domain = mono_domain_get ();
4007
4008         if (domain != current_domain)
4009                 mono_domain_set_internal_with_options (domain, FALSE);
4010
4011         g_assert (domain == mono_object_domain (domain->domain));
4012
4013         if (mono_object_domain (exc) != domain) {
4014                 MonoObject *serialization_exc;
4015
4016                 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4017                 if (!exc) {
4018                         if (serialization_exc) {
4019                                 MonoObject *dummy;
4020                                 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4021                                 g_assert (exc);
4022                         } else {
4023                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4024                                                 "System.Runtime.Serialization", "SerializationException",
4025                                                 "Could not serialize unhandled exception.");
4026                         }
4027                 }
4028         }
4029         g_assert (mono_object_domain (exc) == domain);
4030
4031         pa [0] = domain->domain;
4032         pa [1] = create_unhandled_exception_eventargs (exc);
4033         mono_runtime_delegate_invoke (delegate, pa, &e);
4034
4035         if (domain != current_domain)
4036                 mono_domain_set_internal_with_options (current_domain, FALSE);
4037
4038         if (e) {
4039                 MonoError error;
4040                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4041                 if (!mono_error_ok (&error)) {
4042                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4043                         mono_error_cleanup (&error);
4044                 } else {
4045                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
4046                         g_free (msg);
4047                 }
4048         }
4049 }
4050
4051 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4052
4053 /**
4054  * mono_runtime_unhandled_exception_policy_set:
4055  * @policy: the new policy
4056  * 
4057  * This is a VM internal routine.
4058  *
4059  * Sets the runtime policy for handling unhandled exceptions.
4060  */
4061 void
4062 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4063         runtime_unhandled_exception_policy = policy;
4064 }
4065
4066 /**
4067  * mono_runtime_unhandled_exception_policy_get:
4068  *
4069  * This is a VM internal routine.
4070  *
4071  * Gets the runtime policy for handling unhandled exceptions.
4072  */
4073 MonoRuntimeUnhandledExceptionPolicy
4074 mono_runtime_unhandled_exception_policy_get (void) {
4075         return runtime_unhandled_exception_policy;
4076 }
4077
4078 /**
4079  * mono_unhandled_exception:
4080  * @exc: exception thrown
4081  *
4082  * This is a VM internal routine.
4083  *
4084  * We call this function when we detect an unhandled exception
4085  * in the default domain.
4086  *
4087  * It invokes the * UnhandledException event in AppDomain or prints
4088  * a warning to the console 
4089  */
4090 void
4091 mono_unhandled_exception (MonoObject *exc)
4092 {
4093         MONO_REQ_GC_UNSAFE_MODE;
4094
4095         MonoClassField *field;
4096         MonoDomain *current_domain, *root_domain;
4097         MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4098
4099         if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4100                 return;
4101
4102         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4103         g_assert (field);
4104
4105         current_domain = mono_domain_get ();
4106         root_domain = mono_get_root_domain ();
4107
4108         root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4109         if (current_domain != root_domain)
4110                 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4111
4112         /* set exitcode only if we will abort the process */
4113         if (!current_appdomain_delegate && !root_appdomain_delegate) {
4114                 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4115                      || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4116                 {
4117                         mono_environment_exitcode_set (1);
4118                 }
4119
4120                 mono_print_unhandled_exception (exc);
4121         } else {
4122                 if (root_appdomain_delegate)
4123                         call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4124                 if (current_appdomain_delegate)
4125                         call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4126         }
4127 }
4128
4129 /**
4130  * mono_runtime_exec_managed_code:
4131  * @domain: Application domain
4132  * @main_func: function to invoke from the execution thread
4133  * @main_args: parameter to the main_func
4134  *
4135  * Launch a new thread to execute a function
4136  *
4137  * main_func is called back from the thread with main_args as the
4138  * parameter.  The callback function is expected to start Main()
4139  * eventually.  This function then waits for all managed threads to
4140  * finish.
4141  * It is not necesseray anymore to execute managed code in a subthread,
4142  * so this function should not be used anymore by default: just
4143  * execute the code and then call mono_thread_manage ().
4144  */
4145 void
4146 mono_runtime_exec_managed_code (MonoDomain *domain,
4147                                 MonoMainThreadFunc main_func,
4148                                 gpointer main_args)
4149 {
4150         mono_thread_create (domain, main_func, main_args);
4151
4152         mono_thread_manage ();
4153 }
4154
4155 /*
4156  * Execute a standard Main() method (args doesn't contain the
4157  * executable name).
4158  */
4159 int
4160 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4161 {
4162         MONO_REQ_GC_UNSAFE_MODE;
4163
4164         MonoDomain *domain;
4165         gpointer pa [1];
4166         int rval;
4167         MonoCustomAttrInfo* cinfo;
4168         gboolean has_stathread_attribute;
4169         MonoInternalThread* thread = mono_thread_internal_current ();
4170
4171         g_assert (args);
4172
4173         pa [0] = args;
4174
4175         domain = mono_object_domain (args);
4176         if (!domain->entry_assembly) {
4177                 gchar *str;
4178                 MonoAssembly *assembly;
4179
4180                 assembly = method->klass->image->assembly;
4181                 domain->entry_assembly = assembly;
4182                 /* Domains created from another domain already have application_base and configuration_file set */
4183                 if (domain->setup->application_base == NULL) {
4184                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4185                 }
4186
4187                 if (domain->setup->configuration_file == NULL) {
4188                         str = g_strconcat (assembly->image->name, ".config", NULL);
4189                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4190                         g_free (str);
4191                         mono_set_private_bin_path_from_config (domain);
4192                 }
4193         }
4194
4195         cinfo = mono_custom_attrs_from_method (method);
4196         if (cinfo) {
4197                 static MonoClass *stathread_attribute = NULL;
4198                 if (!stathread_attribute)
4199                         stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4200                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4201                 if (!cinfo->cached)
4202                         mono_custom_attrs_free (cinfo);
4203         } else {
4204                 has_stathread_attribute = FALSE;
4205         }
4206         if (has_stathread_attribute) {
4207                 thread->apartment_state = ThreadApartmentState_STA;
4208         } else {
4209                 thread->apartment_state = ThreadApartmentState_MTA;
4210         }
4211         mono_thread_init_apartment_state ();
4212
4213         /* FIXME: check signature of method */
4214         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4215                 MonoObject *res;
4216                 res = mono_runtime_invoke (method, NULL, pa, exc);
4217                 if (!exc || !*exc)
4218                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4219                 else
4220                         rval = -1;
4221
4222                 mono_environment_exitcode_set (rval);
4223         } else {
4224                 mono_runtime_invoke (method, NULL, pa, exc);
4225                 if (!exc || !*exc)
4226                         rval = 0;
4227                 else {
4228                         /* If the return type of Main is void, only
4229                          * set the exitcode if an exception was thrown
4230                          * (we don't want to blow away an
4231                          * explicitly-set exit code)
4232                          */
4233                         rval = -1;
4234                         mono_environment_exitcode_set (rval);
4235                 }
4236         }
4237
4238         return rval;
4239 }
4240
4241 /**
4242  * mono_install_runtime_invoke:
4243  * @func: Function to install
4244  *
4245  * This is a VM internal routine
4246  */
4247 void
4248 mono_install_runtime_invoke (MonoInvokeFunc func)
4249 {
4250         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4251 }
4252
4253
4254 /**
4255  * mono_runtime_invoke_array:
4256  * @method: method to invoke
4257  * @obJ: object instance
4258  * @params: arguments to the method
4259  * @exc: exception information.
4260  *
4261  * Invokes the method represented by @method on the object @obj.
4262  *
4263  * obj is the 'this' pointer, it should be NULL for static
4264  * methods, a MonoObject* for object instances and a pointer to
4265  * the value type for value types.
4266  *
4267  * The params array contains the arguments to the method with the
4268  * same convention: MonoObject* pointers for object instances and
4269  * pointers to the value type otherwise. The _invoke_array
4270  * variant takes a C# object[] as the params argument (MonoArray
4271  * *params): in this case the value types are boxed inside the
4272  * respective reference representation.
4273  * 
4274  * From unmanaged code you'll usually use the
4275  * mono_runtime_invoke() variant.
4276  *
4277  * Note that this function doesn't handle virtual methods for
4278  * you, it will exec the exact method you pass: we still need to
4279  * expose a function to lookup the derived class implementation
4280  * of a virtual method (there are examples of this in the code,
4281  * though).
4282  * 
4283  * You can pass NULL as the exc argument if you don't want to
4284  * catch exceptions, otherwise, *exc will be set to the exception
4285  * thrown, if any.  if an exception is thrown, you can't use the
4286  * MonoObject* result from the function.
4287  * 
4288  * If the method returns a value type, it is boxed in an object
4289  * reference.
4290  */
4291 MonoObject*
4292 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4293                            MonoObject **exc)
4294 {
4295         MONO_REQ_GC_UNSAFE_MODE;
4296
4297         MonoMethodSignature *sig = mono_method_signature (method);
4298         gpointer *pa = NULL;
4299         MonoObject *res;
4300         int i;
4301         gboolean has_byref_nullables = FALSE;
4302
4303         if (NULL != params) {
4304                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4305                 for (i = 0; i < mono_array_length (params); i++) {
4306                         MonoType *t = sig->params [i];
4307
4308                 again:
4309                         switch (t->type) {
4310                         case MONO_TYPE_U1:
4311                         case MONO_TYPE_I1:
4312                         case MONO_TYPE_BOOLEAN:
4313                         case MONO_TYPE_U2:
4314                         case MONO_TYPE_I2:
4315                         case MONO_TYPE_CHAR:
4316                         case MONO_TYPE_U:
4317                         case MONO_TYPE_I:
4318                         case MONO_TYPE_U4:
4319                         case MONO_TYPE_I4:
4320                         case MONO_TYPE_U8:
4321                         case MONO_TYPE_I8:
4322                         case MONO_TYPE_R4:
4323                         case MONO_TYPE_R8:
4324                         case MONO_TYPE_VALUETYPE:
4325                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4326                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4327                                         pa [i] = mono_array_get (params, MonoObject*, i);
4328                                         if (t->byref)
4329                                                 has_byref_nullables = TRUE;
4330                                 } else {
4331                                         /* MS seems to create the objects if a null is passed in */
4332                                         if (!mono_array_get (params, MonoObject*, i))
4333                                                 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
4334
4335                                         if (t->byref) {
4336                                                 /*
4337                                                  * We can't pass the unboxed vtype byref to the callee, since
4338                                                  * that would mean the callee would be able to modify boxed
4339                                                  * primitive types. So we (and MS) make a copy of the boxed
4340                                                  * object, pass that to the callee, and replace the original
4341                                                  * boxed object in the arg array with the copy.
4342                                                  */
4343                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4344                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4345                                                 mono_array_setref (params, i, copy);
4346                                         }
4347                                                 
4348                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4349                                 }
4350                                 break;
4351                         case MONO_TYPE_STRING:
4352                         case MONO_TYPE_OBJECT:
4353                         case MONO_TYPE_CLASS:
4354                         case MONO_TYPE_ARRAY:
4355                         case MONO_TYPE_SZARRAY:
4356                                 if (t->byref)
4357                                         pa [i] = mono_array_addr (params, MonoObject*, i);
4358                                         // FIXME: I need to check this code path
4359                                 else
4360                                         pa [i] = mono_array_get (params, MonoObject*, i);
4361                                 break;
4362                         case MONO_TYPE_GENERICINST:
4363                                 if (t->byref)
4364                                         t = &t->data.generic_class->container_class->this_arg;
4365                                 else
4366                                         t = &t->data.generic_class->container_class->byval_arg;
4367                                 goto again;
4368                         case MONO_TYPE_PTR: {
4369                                 MonoObject *arg;
4370
4371                                 /* The argument should be an IntPtr */
4372                                 arg = mono_array_get (params, MonoObject*, i);
4373                                 if (arg == NULL) {
4374                                         pa [i] = NULL;
4375                                 } else {
4376                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4377                                         pa [i] = ((MonoIntPtr*)arg)->m_value;
4378                                 }
4379                                 break;
4380                         }
4381                         default:
4382                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4383                         }
4384                 }
4385         }
4386
4387         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4388                 void *o = obj;
4389
4390                 if (mono_class_is_nullable (method->klass)) {
4391                         /* Need to create a boxed vtype instead */
4392                         g_assert (!obj);
4393
4394                         if (!params)
4395                                 return NULL;
4396                         else
4397                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4398                 }
4399
4400                 if (!obj) {
4401                         obj = mono_object_new (mono_domain_get (), method->klass);
4402                         g_assert (obj); /*maybe we should raise a TLE instead?*/
4403 #ifndef DISABLE_REMOTING
4404                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4405                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4406                         }
4407 #endif
4408                         if (method->klass->valuetype)
4409                                 o = mono_object_unbox (obj);
4410                         else
4411                                 o = obj;
4412                 } else if (method->klass->valuetype) {
4413                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
4414                 }
4415
4416                 mono_runtime_invoke (method, o, pa, exc);
4417                 return obj;
4418         } else {
4419                 if (mono_class_is_nullable (method->klass)) {
4420                         MonoObject *nullable;
4421
4422                         /* Convert the unboxed vtype into a Nullable structure */
4423                         nullable = mono_object_new (mono_domain_get (), method->klass);
4424
4425                         mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4426                         obj = mono_object_unbox (nullable);
4427                 }
4428
4429                 /* obj must be already unboxed if needed */
4430                 res = mono_runtime_invoke (method, obj, pa, exc);
4431
4432                 if (sig->ret->type == MONO_TYPE_PTR) {
4433                         MonoClass *pointer_class;
4434                         static MonoMethod *box_method;
4435                         void *box_args [2];
4436                         MonoObject *box_exc;
4437
4438                         /* 
4439                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
4440                          * convert it to a Pointer object.
4441                          */
4442                         pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4443                         if (!box_method)
4444                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4445
4446                         g_assert (res->vtable->klass == mono_defaults.int_class);
4447                         box_args [0] = ((MonoIntPtr*)res)->m_value;
4448                         box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4449                         res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4450                         g_assert (!box_exc);
4451                 }
4452
4453                 if (has_byref_nullables) {
4454                         /* 
4455                          * The runtime invoke wrapper already converted byref nullables back,
4456                          * and stored them in pa, we just need to copy them back to the
4457                          * managed array.
4458                          */
4459                         for (i = 0; i < mono_array_length (params); i++) {
4460                                 MonoType *t = sig->params [i];
4461
4462                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4463                                         mono_array_setref (params, i, pa [i]);
4464                         }
4465                 }
4466
4467                 return res;
4468         }
4469 }
4470
4471 static void
4472 arith_overflow (void)
4473 {
4474         MONO_REQ_GC_UNSAFE_MODE;
4475
4476         mono_raise_exception (mono_get_exception_overflow ());
4477 }
4478
4479 /**
4480  * mono_object_new:
4481  * @klass: the class of the object that we want to create
4482  *
4483  * Returns: a newly created object whose definition is
4484  * looked up using @klass.   This will not invoke any constructors, 
4485  * so the consumer of this routine has to invoke any constructors on
4486  * its own to initialize the object.
4487  * 
4488  * It returns NULL on failure.
4489  */
4490 MonoObject *
4491 mono_object_new (MonoDomain *domain, MonoClass *klass)
4492 {
4493         MONO_REQ_GC_UNSAFE_MODE;
4494
4495         MonoVTable *vtable;
4496
4497         vtable = mono_class_vtable (domain, klass);
4498         if (!vtable)
4499                 return NULL;
4500         return mono_object_new_specific (vtable);
4501 }
4502
4503 /**
4504  * mono_object_new_pinned:
4505  *
4506  *   Same as mono_object_new, but the returned object will be pinned.
4507  * For SGEN, these objects will only be freed at appdomain unload.
4508  */
4509 MonoObject *
4510 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4511 {
4512         MONO_REQ_GC_UNSAFE_MODE;
4513
4514         MonoVTable *vtable;
4515
4516         vtable = mono_class_vtable (domain, klass);
4517         if (!vtable)
4518                 return NULL;
4519
4520 #ifdef HAVE_SGEN_GC
4521         return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4522 #else
4523         return mono_object_new_specific (vtable);
4524 #endif
4525 }
4526
4527 /**
4528  * mono_object_new_specific:
4529  * @vtable: the vtable of the object that we want to create
4530  *
4531  * Returns: A newly created object with class and domain specified
4532  * by @vtable
4533  */
4534 MonoObject *
4535 mono_object_new_specific (MonoVTable *vtable)
4536 {
4537         MONO_REQ_GC_UNSAFE_MODE;
4538
4539         MonoObject *o;
4540
4541         /* check for is_com_object for COM Interop */
4542         if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4543         {
4544                 gpointer pa [1];
4545                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4546
4547                 if (im == NULL) {
4548                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4549
4550                         if (!klass->inited)
4551                                 mono_class_init (klass);
4552
4553                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4554                         if (!im)
4555                                 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
4556                         vtable->domain->create_proxy_for_type_method = im;
4557                 }
4558         
4559                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4560
4561                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
4562                 if (o != NULL) return o;
4563         }
4564
4565         return mono_object_new_alloc_specific (vtable);
4566 }
4567
4568 MonoObject *
4569 mono_object_new_alloc_specific (MonoVTable *vtable)
4570 {
4571         MONO_REQ_GC_UNSAFE_MODE;
4572
4573         MonoObject *o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4574
4575         if (G_UNLIKELY (vtable->klass->has_finalize))
4576                 mono_object_register_finalizer (o);
4577
4578         return o;
4579 }
4580
4581 MonoObject*
4582 mono_object_new_fast (MonoVTable *vtable)
4583 {
4584         MONO_REQ_GC_UNSAFE_MODE;
4585
4586         return mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4587 }
4588
4589 /**
4590  * mono_class_get_allocation_ftn:
4591  * @vtable: vtable
4592  * @for_box: the object will be used for boxing
4593  * @pass_size_in_words: 
4594  *
4595  * Return the allocation function appropriate for the given class.
4596  */
4597
4598 void*
4599 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4600 {
4601         MONO_REQ_GC_NEUTRAL_MODE;
4602
4603         *pass_size_in_words = FALSE;
4604
4605         if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4606                 return mono_object_new_specific;
4607
4608         if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4609
4610                 return mono_object_new_fast;
4611
4612                 /* 
4613                  * FIXME: This is actually slower than mono_object_new_fast, because
4614                  * of the overhead of parameter passing.
4615                  */
4616                 /*
4617                 *pass_size_in_words = TRUE;
4618 #ifdef GC_REDIRECT_TO_LOCAL
4619                 return GC_local_gcj_fast_malloc;
4620 #else
4621                 return GC_gcj_fast_malloc;
4622 #endif
4623                 */
4624         }
4625
4626         return mono_object_new_specific;
4627 }
4628
4629 /**
4630  * mono_object_new_from_token:
4631  * @image: Context where the type_token is hosted
4632  * @token: a token of the type that we want to create
4633  *
4634  * Returns: A newly created object whose definition is
4635  * looked up using @token in the @image image
4636  */
4637 MonoObject *
4638 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
4639 {
4640         MONO_REQ_GC_UNSAFE_MODE;
4641
4642         MonoError error;
4643         MonoClass *class;
4644
4645         class = mono_class_get_checked (image, token, &error);
4646         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4647
4648         return mono_object_new (domain, class);
4649 }
4650
4651
4652 /**
4653  * mono_object_clone:
4654  * @obj: the object to clone
4655  *
4656  * Returns: A newly created object who is a shallow copy of @obj
4657  */
4658 MonoObject *
4659 mono_object_clone (MonoObject *obj)
4660 {
4661         MONO_REQ_GC_UNSAFE_MODE;
4662
4663         MonoObject *o;
4664         int size = obj->vtable->klass->instance_size;
4665
4666         if (obj->vtable->klass->rank)
4667                 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4668
4669         o = mono_gc_alloc_obj (obj->vtable, size);
4670
4671         /* If the object doesn't contain references this will do a simple memmove. */
4672         mono_gc_wbarrier_object_copy (o, obj);
4673
4674         if (obj->vtable->klass->has_finalize)
4675                 mono_object_register_finalizer (o);
4676         return o;
4677 }
4678
4679 /**
4680  * mono_array_full_copy:
4681  * @src: source array to copy
4682  * @dest: destination array
4683  *
4684  * Copies the content of one array to another with exactly the same type and size.
4685  */
4686 void
4687 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4688 {
4689         MONO_REQ_GC_UNSAFE_MODE;
4690
4691         uintptr_t size;
4692         MonoClass *klass = src->obj.vtable->klass;
4693
4694         g_assert (klass == dest->obj.vtable->klass);
4695
4696         size = mono_array_length (src);
4697         g_assert (size == mono_array_length (dest));
4698         size *= mono_array_element_size (klass);
4699 #ifdef HAVE_SGEN_GC
4700         if (klass->element_class->valuetype) {
4701                 if (klass->element_class->has_references)
4702                         mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4703                 else
4704                         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4705         } else {
4706                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4707         }
4708 #else
4709         mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4710 #endif
4711 }
4712
4713 /**
4714  * mono_array_clone_in_domain:
4715  * @domain: the domain in which the array will be cloned into
4716  * @array: the array to clone
4717  *
4718  * This routine returns a copy of the array that is hosted on the
4719  * specified MonoDomain.
4720  */
4721 MonoArray*
4722 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4723 {
4724         MONO_REQ_GC_UNSAFE_MODE;
4725
4726         MonoArray *o;
4727         uintptr_t size, i;
4728         uintptr_t *sizes;
4729         MonoClass *klass = array->obj.vtable->klass;
4730
4731         if (array->bounds == NULL) {
4732                 size = mono_array_length (array);
4733                 o = mono_array_new_full (domain, klass, &size, NULL);
4734
4735                 size *= mono_array_element_size (klass);
4736 #ifdef HAVE_SGEN_GC
4737                 if (klass->element_class->valuetype) {
4738                         if (klass->element_class->has_references)
4739                                 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4740                         else
4741                                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4742                 } else {
4743                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4744                 }
4745 #else
4746                 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4747 #endif
4748                 return o;
4749         }
4750         
4751         sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4752         size = mono_array_element_size (klass);
4753         for (i = 0; i < klass->rank; ++i) {
4754                 sizes [i] = array->bounds [i].length;
4755                 size *= array->bounds [i].length;
4756                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4757         }
4758         o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4759 #ifdef HAVE_SGEN_GC
4760         if (klass->element_class->valuetype) {
4761                 if (klass->element_class->has_references)
4762                         mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4763                 else
4764                         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4765         } else {
4766                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4767         }
4768 #else
4769         mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4770 #endif
4771
4772         return o;
4773 }
4774
4775 /**
4776  * mono_array_clone:
4777  * @array: the array to clone
4778  *
4779  * Returns: A newly created array who is a shallow copy of @array
4780  */
4781 MonoArray*
4782 mono_array_clone (MonoArray *array)
4783 {
4784         MONO_REQ_GC_UNSAFE_MODE;
4785
4786         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4787 }
4788
4789 /* helper macros to check for overflow when calculating the size of arrays */
4790 #ifdef MONO_BIG_ARRAYS
4791 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4792 #define MYGUINT_MAX MYGUINT64_MAX
4793 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4794             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4795 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4796             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
4797                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4798 #else
4799 #define MYGUINT32_MAX 4294967295U
4800 #define MYGUINT_MAX MYGUINT32_MAX
4801 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4802             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4803 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4804             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
4805                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4806 #endif
4807
4808 gboolean
4809 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4810 {
4811         MONO_REQ_GC_NEUTRAL_MODE;
4812
4813         uintptr_t byte_len;
4814
4815         byte_len = mono_array_element_size (class);
4816         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4817                 return FALSE;
4818         byte_len *= len;
4819         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4820                 return FALSE;
4821         byte_len += sizeof (MonoArray);
4822
4823         *res = byte_len;
4824
4825         return TRUE;
4826 }
4827
4828 /**
4829  * mono_array_new_full:
4830  * @domain: domain where the object is created
4831  * @array_class: array class
4832  * @lengths: lengths for each dimension in the array
4833  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4834  *
4835  * This routine creates a new array objects with the given dimensions,
4836  * lower bounds and type.
4837  */
4838 MonoArray*
4839 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4840 {
4841         MONO_REQ_GC_UNSAFE_MODE;
4842
4843         uintptr_t byte_len = 0, len, bounds_size;
4844         MonoObject *o;
4845         MonoArray *array;
4846         MonoArrayBounds *bounds;
4847         MonoVTable *vtable;
4848         int i;
4849
4850         if (!array_class->inited)
4851                 mono_class_init (array_class);
4852
4853         len = 1;
4854
4855         /* A single dimensional array with a 0 lower bound is the same as an szarray */
4856         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4857                 len = lengths [0];
4858                 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4859                         arith_overflow ();
4860                 bounds_size = 0;
4861         } else {
4862                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4863
4864                 for (i = 0; i < array_class->rank; ++i) {
4865                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4866                                 arith_overflow ();
4867                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4868                                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4869                         len *= lengths [i];
4870                 }
4871         }
4872
4873         if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4874                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4875
4876         if (bounds_size) {
4877                 /* align */
4878                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4879                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4880                 byte_len = (byte_len + 3) & ~3;
4881                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4882                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4883                 byte_len += bounds_size;
4884         }
4885         /* 
4886          * Following three lines almost taken from mono_object_new ():
4887          * they need to be kept in sync.
4888          */
4889         vtable = mono_class_vtable_full (domain, array_class, TRUE);
4890         if (bounds_size)
4891                 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4892         else
4893                 o = mono_gc_alloc_vector (vtable, byte_len, len);
4894         array = (MonoArray*)o;
4895
4896         bounds = array->bounds;
4897
4898         if (bounds_size) {
4899                 for (i = 0; i < array_class->rank; ++i) {
4900                         bounds [i].length = lengths [i];
4901                         if (lower_bounds)
4902                                 bounds [i].lower_bound = lower_bounds [i];
4903                 }
4904         }
4905
4906         return array;
4907 }
4908
4909 /**
4910  * mono_array_new:
4911  * @domain: domain where the object is created
4912  * @eclass: element class
4913  * @n: number of array elements
4914  *
4915  * This routine creates a new szarray with @n elements of type @eclass.
4916  */
4917 MonoArray *
4918 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4919 {
4920         MONO_REQ_GC_UNSAFE_MODE;
4921
4922         MonoClass *ac;
4923
4924         ac = mono_array_class_get (eclass, 1);
4925         g_assert (ac);
4926
4927         return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4928 }
4929
4930 /**
4931  * mono_array_new_specific:
4932  * @vtable: a vtable in the appropriate domain for an initialized class
4933  * @n: number of array elements
4934  *
4935  * This routine is a fast alternative to mono_array_new() for code which
4936  * can be sure about the domain it operates in.
4937  */
4938 MonoArray *
4939 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4940 {
4941         MONO_REQ_GC_UNSAFE_MODE;
4942
4943         MonoObject *o;
4944         MonoArray *ao;
4945         uintptr_t byte_len;
4946
4947         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4948                 arith_overflow ();
4949                 return NULL;
4950         }
4951
4952         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4953                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4954                 return NULL;
4955         }
4956         o = mono_gc_alloc_vector (vtable, byte_len, n);
4957         ao = (MonoArray*)o;
4958
4959         return ao;
4960 }
4961
4962 /**
4963  * mono_string_new_utf16:
4964  * @text: a pointer to an utf16 string
4965  * @len: the length of the string
4966  *
4967  * Returns: A newly created string object which contains @text.
4968  */
4969 MonoString *
4970 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4971 {
4972         MONO_REQ_GC_UNSAFE_MODE;
4973
4974         MonoString *s;
4975         
4976         s = mono_string_new_size (domain, len);
4977         g_assert (s != NULL);
4978
4979         memcpy (mono_string_chars (s), text, len * 2);
4980
4981         return s;
4982 }
4983
4984 /**
4985  * mono_string_new_utf32:
4986  * @text: a pointer to an utf32 string
4987  * @len: the length of the string
4988  *
4989  * Returns: A newly created string object which contains @text.
4990  */
4991 MonoString *
4992 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4993 {
4994         MONO_REQ_GC_UNSAFE_MODE;
4995
4996         MonoString *s;
4997         mono_unichar2 *utf16_output = NULL;
4998         gint32 utf16_len = 0;
4999         GError *error = NULL;
5000         glong items_written;
5001         
5002         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5003         
5004         if (error)
5005                 g_error_free (error);
5006
5007         while (utf16_output [utf16_len]) utf16_len++;
5008         
5009         s = mono_string_new_size (domain, utf16_len);
5010         g_assert (s != NULL);
5011
5012         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5013
5014         g_free (utf16_output);
5015         
5016         return s;
5017 }
5018
5019 /**
5020  * mono_string_new_size:
5021  * @text: a pointer to an utf16 string
5022  * @len: the length of the string
5023  *
5024  * Returns: A newly created string object of @len
5025  */
5026 MonoString *
5027 mono_string_new_size (MonoDomain *domain, gint32 len)
5028 {
5029         MONO_REQ_GC_UNSAFE_MODE;
5030
5031         MonoString *s;
5032         MonoVTable *vtable;
5033         size_t size;
5034
5035         /* check for overflow */
5036         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5037                 mono_gc_out_of_memory (-1);
5038
5039         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5040         g_assert (size > 0);
5041
5042         vtable = mono_class_vtable (domain, mono_defaults.string_class);
5043         g_assert (vtable);
5044
5045         s = mono_gc_alloc_string (vtable, size, len);
5046
5047         return s;
5048 }
5049
5050 /**
5051  * mono_string_new_len:
5052  * @text: a pointer to an utf8 string
5053  * @length: number of bytes in @text to consider
5054  *
5055  * Returns: A newly created string object which contains @text.
5056  */
5057 MonoString*
5058 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5059 {
5060         MONO_REQ_GC_UNSAFE_MODE;
5061
5062         GError *error = NULL;
5063         MonoString *o = NULL;
5064         guint16 *ut;
5065         glong items_written;
5066
5067         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5068
5069         if (!error)
5070                 o = mono_string_new_utf16 (domain, ut, items_written);
5071         else 
5072                 g_error_free (error);
5073
5074         g_free (ut);
5075
5076         return o;
5077 }
5078
5079 /**
5080  * mono_string_new:
5081  * @text: a pointer to an utf8 string
5082  *
5083  * Returns: A newly created string object which contains @text.
5084  */
5085 MonoString*
5086 mono_string_new (MonoDomain *domain, const char *text)
5087 {
5088         MONO_REQ_GC_UNSAFE_MODE;
5089
5090     GError *error = NULL;
5091     MonoString *o = NULL;
5092     guint16 *ut;
5093     glong items_written;
5094     int l;
5095
5096     l = strlen (text);
5097    
5098     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5099
5100     if (!error)
5101         o = mono_string_new_utf16 (domain, ut, items_written);
5102     else
5103         g_error_free (error);
5104
5105     g_free (ut);
5106 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5107 #if 0
5108         gunichar2 *str;
5109         const gchar *end;
5110         int len;
5111         MonoString *o = NULL;
5112
5113         if (!g_utf8_validate (text, -1, &end))
5114                 return NULL;
5115
5116         len = g_utf8_strlen (text, -1);
5117         o = mono_string_new_size (domain, len);
5118         str = mono_string_chars (o);
5119
5120         while (text < end) {
5121                 *str++ = g_utf8_get_char (text);
5122                 text = g_utf8_next_char (text);
5123         }
5124 #endif
5125         return o;
5126 }
5127
5128 /**
5129  * mono_string_new_wrapper:
5130  * @text: pointer to utf8 characters.
5131  *
5132  * Helper function to create a string object from @text in the current domain.
5133  */
5134 MonoString*
5135 mono_string_new_wrapper (const char *text)
5136 {
5137         MONO_REQ_GC_UNSAFE_MODE;
5138
5139         MonoDomain *domain = mono_domain_get ();
5140
5141         if (text)
5142                 return mono_string_new (domain, text);
5143
5144         return NULL;
5145 }
5146
5147 /**
5148  * mono_value_box:
5149  * @class: the class of the value
5150  * @value: a pointer to the unboxed data
5151  *
5152  * Returns: A newly created object which contains @value.
5153  */
5154 MonoObject *
5155 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5156 {
5157         MONO_REQ_GC_UNSAFE_MODE;
5158
5159         MonoObject *res;
5160         int size;
5161         MonoVTable *vtable;
5162
5163         g_assert (class->valuetype);
5164         if (mono_class_is_nullable (class))
5165                 return mono_nullable_box (value, class);
5166
5167         vtable = mono_class_vtable (domain, class);
5168         if (!vtable)
5169                 return NULL;
5170         size = mono_class_instance_size (class);
5171         res = mono_object_new_alloc_specific (vtable);
5172
5173         size = size - sizeof (MonoObject);
5174
5175 #ifdef HAVE_SGEN_GC
5176         g_assert (size == mono_class_value_size (class, NULL));
5177         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5178 #else
5179 #if NO_UNALIGNED_ACCESS
5180         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5181 #else
5182         switch (size) {
5183         case 1:
5184                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5185                 break;
5186         case 2:
5187                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5188                 break;
5189         case 4:
5190                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5191                 break;
5192         case 8:
5193                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5194                 break;
5195         default:
5196                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5197         }
5198 #endif
5199 #endif
5200         if (class->has_finalize)
5201                 mono_object_register_finalizer (res);
5202         return res;
5203 }
5204
5205 /*
5206  * mono_value_copy:
5207  * @dest: destination pointer
5208  * @src: source pointer
5209  * @klass: a valuetype class
5210  *
5211  * Copy a valuetype from @src to @dest. This function must be used
5212  * when @klass contains references fields.
5213  */
5214 void
5215 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5216 {
5217         MONO_REQ_GC_UNSAFE_MODE;
5218
5219         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5220 }
5221
5222 /*
5223  * mono_value_copy_array:
5224  * @dest: destination array
5225  * @dest_idx: index in the @dest array
5226  * @src: source pointer
5227  * @count: number of items
5228  *
5229  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
5230  * This function must be used when @klass contains references fields.
5231  * Overlap is handled.
5232  */
5233 void
5234 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5235 {
5236         MONO_REQ_GC_UNSAFE_MODE;
5237
5238         int size = mono_array_element_size (dest->obj.vtable->klass);
5239         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5240         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5241         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5242 }
5243
5244 /**
5245  * mono_object_get_domain:
5246  * @obj: object to query
5247  * 
5248  * Returns: the MonoDomain where the object is hosted
5249  */
5250 MonoDomain*
5251 mono_object_get_domain (MonoObject *obj)
5252 {
5253         MONO_REQ_GC_UNSAFE_MODE;
5254
5255         return mono_object_domain (obj);
5256 }
5257
5258 /**
5259  * mono_object_get_class:
5260  * @obj: object to query
5261  * 
5262  * Returns: the MonOClass of the object.
5263  */
5264 MonoClass*
5265 mono_object_get_class (MonoObject *obj)
5266 {
5267         MONO_REQ_GC_UNSAFE_MODE;
5268
5269         return mono_object_class (obj);
5270 }
5271 /**
5272  * mono_object_get_size:
5273  * @o: object to query
5274  * 
5275  * Returns: the size, in bytes, of @o
5276  */
5277 guint
5278 mono_object_get_size (MonoObject* o)
5279 {
5280         MONO_REQ_GC_UNSAFE_MODE;
5281
5282         MonoClass* klass = mono_object_class (o);
5283         if (klass == mono_defaults.string_class) {
5284                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5285         } else if (o->vtable->rank) {
5286                 MonoArray *array = (MonoArray*)o;
5287                 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5288                 if (array->bounds) {
5289                         size += 3;
5290                         size &= ~3;
5291                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
5292                 }
5293                 return size;
5294         } else {
5295                 return mono_class_instance_size (klass);
5296         }
5297 }
5298
5299 /**
5300  * mono_object_unbox:
5301  * @obj: object to unbox
5302  * 
5303  * Returns: a pointer to the start of the valuetype boxed in this
5304  * object.
5305  *
5306  * This method will assert if the object passed is not a valuetype.
5307  */
5308 gpointer
5309 mono_object_unbox (MonoObject *obj)
5310 {
5311         MONO_REQ_GC_UNSAFE_MODE;
5312
5313         /* add assert for valuetypes? */
5314         g_assert (obj->vtable->klass->valuetype);
5315         return ((char*)obj) + sizeof (MonoObject);
5316 }
5317
5318 /**
5319  * mono_object_isinst:
5320  * @obj: an object
5321  * @klass: a pointer to a class 
5322  *
5323  * Returns: @obj if @obj is derived from @klass
5324  */
5325 MonoObject *
5326 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5327 {
5328         MONO_REQ_GC_UNSAFE_MODE;
5329
5330         if (!klass->inited)
5331                 mono_class_init (klass);
5332
5333         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5334                 return mono_object_isinst_mbyref (obj, klass);
5335
5336         if (!obj)
5337                 return NULL;
5338
5339         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5340 }
5341
5342 MonoObject *
5343 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5344 {
5345         MONO_REQ_GC_UNSAFE_MODE;
5346
5347         MonoVTable *vt;
5348
5349         if (!obj)
5350                 return NULL;
5351
5352         vt = obj->vtable;
5353         
5354         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5355                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5356                         return obj;
5357                 }
5358
5359                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5360                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5361                         return obj;
5362         } else {
5363                 MonoClass *oklass = vt->klass;
5364                 if (mono_class_is_transparent_proxy (oklass))
5365                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5366
5367                 mono_class_setup_supertypes (klass);    
5368                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5369                         return obj;
5370         }
5371 #ifndef DISABLE_REMOTING
5372         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5373         {
5374                 MonoDomain *domain = mono_domain_get ();
5375                 MonoObject *res;
5376                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5377                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5378                 MonoMethod *im = NULL;
5379                 gpointer pa [2];
5380
5381                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5382                 if (!im)
5383                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5384                 im = mono_object_get_virtual_method (rp, im);
5385                 g_assert (im);
5386         
5387                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5388                 pa [1] = obj;
5389
5390                 res = mono_runtime_invoke (im, rp, pa, NULL);
5391         
5392                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5393                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5394                         mono_upgrade_remote_class (domain, obj, klass);
5395                         return obj;
5396                 }
5397         }
5398 #endif /* DISABLE_REMOTING */
5399         return NULL;
5400 }
5401
5402 /**
5403  * mono_object_castclass_mbyref:
5404  * @obj: an object
5405  * @klass: a pointer to a class 
5406  *
5407  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5408  */
5409 MonoObject *
5410 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5411 {
5412         MONO_REQ_GC_UNSAFE_MODE;
5413
5414         if (!obj) return NULL;
5415         if (mono_object_isinst_mbyref (obj, klass)) return obj;
5416                 
5417         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5418                                                         "System",
5419                                                         "InvalidCastException"));
5420         return NULL;
5421 }
5422
5423 typedef struct {
5424         MonoDomain *orig_domain;
5425         MonoString *ins;
5426         MonoString *res;
5427 } LDStrInfo;
5428
5429 static void
5430 str_lookup (MonoDomain *domain, gpointer user_data)
5431 {
5432         MONO_REQ_GC_UNSAFE_MODE;
5433
5434         LDStrInfo *info = user_data;
5435         if (info->res || domain == info->orig_domain)
5436                 return;
5437         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5438 }
5439
5440 #ifdef HAVE_SGEN_GC
5441
5442 static MonoString*
5443 mono_string_get_pinned (MonoString *str)
5444 {
5445         MONO_REQ_GC_UNSAFE_MODE;
5446
5447         int size;
5448         MonoString *news;
5449         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5450         news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5451         if (news) {
5452                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5453                 news->length = mono_string_length (str);
5454         }
5455         return news;
5456 }
5457
5458 #else
5459 #define mono_string_get_pinned(str) (str)
5460 #endif
5461
5462 static MonoString*
5463 mono_string_is_interned_lookup (MonoString *str, int insert)
5464 {
5465         MONO_REQ_GC_UNSAFE_MODE;
5466
5467         MonoGHashTable *ldstr_table;
5468         MonoString *s, *res;
5469         MonoDomain *domain;
5470         
5471         domain = ((MonoObject *)str)->vtable->domain;
5472         ldstr_table = domain->ldstr_table;
5473         ldstr_lock ();
5474         res = mono_g_hash_table_lookup (ldstr_table, str);
5475         if (res) {
5476                 ldstr_unlock ();
5477                 return res;
5478         }
5479         if (insert) {
5480                 /* Allocate outside the lock */
5481                 ldstr_unlock ();
5482                 s = mono_string_get_pinned (str);
5483                 if (s) {
5484                         ldstr_lock ();
5485                         res = mono_g_hash_table_lookup (ldstr_table, str);
5486                         if (res) {
5487                                 ldstr_unlock ();
5488                                 return res;
5489                         }
5490                         mono_g_hash_table_insert (ldstr_table, s, s);
5491                         ldstr_unlock ();
5492                 }
5493                 return s;
5494         } else {
5495                 LDStrInfo ldstr_info;
5496                 ldstr_info.orig_domain = domain;
5497                 ldstr_info.ins = str;
5498                 ldstr_info.res = NULL;
5499
5500                 mono_domain_foreach (str_lookup, &ldstr_info);
5501                 if (ldstr_info.res) {
5502                         /* 
5503                          * the string was already interned in some other domain:
5504                          * intern it in the current one as well.
5505                          */
5506                         mono_g_hash_table_insert (ldstr_table, str, str);
5507                         ldstr_unlock ();
5508                         return str;
5509                 }
5510         }
5511         ldstr_unlock ();
5512         return NULL;
5513 }
5514
5515 /**
5516  * mono_string_is_interned:
5517  * @o: String to probe
5518  *
5519  * Returns whether the string has been interned.
5520  */
5521 MonoString*
5522 mono_string_is_interned (MonoString *o)
5523 {
5524         MONO_REQ_GC_UNSAFE_MODE;
5525
5526         return mono_string_is_interned_lookup (o, FALSE);
5527 }
5528
5529 /**
5530  * mono_string_intern:
5531  * @o: String to intern
5532  *
5533  * Interns the string passed.  
5534  * Returns: The interned string.
5535  */
5536 MonoString*
5537 mono_string_intern (MonoString *str)
5538 {
5539         MONO_REQ_GC_UNSAFE_MODE;
5540
5541         return mono_string_is_interned_lookup (str, TRUE);
5542 }
5543
5544 /**
5545  * mono_ldstr:
5546  * @domain: the domain where the string will be used.
5547  * @image: a metadata context
5548  * @idx: index into the user string table.
5549  * 
5550  * Implementation for the ldstr opcode.
5551  * Returns: a loaded string from the @image/@idx combination.
5552  */
5553 MonoString*
5554 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5555 {
5556         MONO_REQ_GC_UNSAFE_MODE;
5557
5558         if (image->dynamic) {
5559                 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5560                 return str;
5561         } else {
5562                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5563                         return NULL; /*FIXME we should probably be raising an exception here*/
5564                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5565         }
5566 }
5567
5568 /**
5569  * mono_ldstr_metadata_sig
5570  * @domain: the domain for the string
5571  * @sig: the signature of a metadata string
5572  *
5573  * Returns: a MonoString for a string stored in the metadata
5574  */
5575 static MonoString*
5576 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5577 {
5578         MONO_REQ_GC_UNSAFE_MODE;
5579
5580         const char *str = sig;
5581         MonoString *o, *interned;
5582         size_t len2;
5583
5584         len2 = mono_metadata_decode_blob_size (str, &str);
5585         len2 >>= 1;
5586
5587         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5588 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5589         {
5590                 int i;
5591                 guint16 *p2 = (guint16*)mono_string_chars (o);
5592                 for (i = 0; i < len2; ++i) {
5593                         *p2 = GUINT16_FROM_LE (*p2);
5594                         ++p2;
5595                 }
5596         }
5597 #endif
5598         ldstr_lock ();
5599         interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5600         ldstr_unlock ();
5601         if (interned)
5602                 return interned; /* o will get garbage collected */
5603
5604         o = mono_string_get_pinned (o);
5605         if (o) {
5606                 ldstr_lock ();
5607                 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5608                 if (!interned) {
5609                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
5610                         interned = o;
5611                 }
5612                 ldstr_unlock ();
5613         }
5614
5615         return interned;
5616 }
5617
5618 /**
5619  * mono_string_to_utf8:
5620  * @s: a System.String
5621  *
5622  * Returns the UTF8 representation for @s.
5623  * The resulting buffer needs to be freed with mono_free().
5624  *
5625  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5626  */
5627 char *
5628 mono_string_to_utf8 (MonoString *s)
5629 {
5630         MONO_REQ_GC_UNSAFE_MODE;
5631
5632         MonoError error;
5633         char *result = mono_string_to_utf8_checked (s, &error);
5634         
5635         if (!mono_error_ok (&error))
5636                 mono_error_raise_exception (&error);
5637         return result;
5638 }
5639
5640 /**
5641  * mono_string_to_utf8_checked:
5642  * @s: a System.String
5643  * @error: a MonoError.
5644  * 
5645  * Converts a MonoString to its UTF8 representation. May fail; check 
5646  * @error to determine whether the conversion was successful.
5647  * The resulting buffer should be freed with mono_free().
5648  */
5649 char *
5650 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5651 {
5652         MONO_REQ_GC_UNSAFE_MODE;
5653
5654         long written = 0;
5655         char *as;
5656         GError *gerror = NULL;
5657
5658         mono_error_init (error);
5659
5660         if (s == NULL)
5661                 return NULL;
5662
5663         if (!s->length)
5664                 return g_strdup ("");
5665
5666         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5667         if (gerror) {
5668                 mono_error_set_argument (error, "string", "%s", gerror->message);
5669                 g_error_free (gerror);
5670                 return NULL;
5671         }
5672         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5673         if (s->length > written) {
5674                 /* allocate the total length and copy the part of the string that has been converted */
5675                 char *as2 = g_malloc0 (s->length);
5676                 memcpy (as2, as, written);
5677                 g_free (as);
5678                 as = as2;
5679         }
5680
5681         return as;
5682 }
5683
5684 /**
5685  * mono_string_to_utf8_ignore:
5686  * @s: a MonoString
5687  *
5688  * Converts a MonoString to its UTF8 representation. Will ignore
5689  * invalid surrogate pairs.
5690  * The resulting buffer should be freed with mono_free().
5691  * 
5692  */
5693 char *
5694 mono_string_to_utf8_ignore (MonoString *s)
5695 {
5696         MONO_REQ_GC_UNSAFE_MODE;
5697
5698         long written = 0;
5699         char *as;
5700
5701         if (s == NULL)
5702                 return NULL;
5703
5704         if (!s->length)
5705                 return g_strdup ("");
5706
5707         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5708
5709         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5710         if (s->length > written) {
5711                 /* allocate the total length and copy the part of the string that has been converted */
5712                 char *as2 = g_malloc0 (s->length);
5713                 memcpy (as2, as, written);
5714                 g_free (as);
5715                 as = as2;
5716         }
5717
5718         return as;
5719 }
5720
5721 /**
5722  * mono_string_to_utf8_image_ignore:
5723  * @s: a System.String
5724  *
5725  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5726  */
5727 char *
5728 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5729 {
5730         MONO_REQ_GC_UNSAFE_MODE;
5731
5732         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5733 }
5734
5735 /**
5736  * mono_string_to_utf8_mp_ignore:
5737  * @s: a System.String
5738  *
5739  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5740  */
5741 char *
5742 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5743 {
5744         MONO_REQ_GC_UNSAFE_MODE;
5745
5746         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5747 }
5748
5749
5750 /**
5751  * mono_string_to_utf16:
5752  * @s: a MonoString
5753  *
5754  * Return an null-terminated array of the utf-16 chars
5755  * contained in @s. The result must be freed with g_free().
5756  * This is a temporary helper until our string implementation
5757  * is reworked to always include the null terminating char.
5758  */
5759 mono_unichar2*
5760 mono_string_to_utf16 (MonoString *s)
5761 {
5762         MONO_REQ_GC_UNSAFE_MODE;
5763
5764         char *as;
5765
5766         if (s == NULL)
5767                 return NULL;
5768
5769         as = g_malloc ((s->length * 2) + 2);
5770         as [(s->length * 2)] = '\0';
5771         as [(s->length * 2) + 1] = '\0';
5772
5773         if (!s->length) {
5774                 return (gunichar2 *)(as);
5775         }
5776         
5777         memcpy (as, mono_string_chars(s), s->length * 2);
5778         return (gunichar2 *)(as);
5779 }
5780
5781 /**
5782  * mono_string_to_utf32:
5783  * @s: a MonoString
5784  *
5785  * Return an null-terminated array of the UTF-32 (UCS-4) chars
5786  * contained in @s. The result must be freed with g_free().
5787  */
5788 mono_unichar4*
5789 mono_string_to_utf32 (MonoString *s)
5790 {
5791         MONO_REQ_GC_UNSAFE_MODE;
5792
5793         mono_unichar4 *utf32_output = NULL; 
5794         GError *error = NULL;
5795         glong items_written;
5796         
5797         if (s == NULL)
5798                 return NULL;
5799                 
5800         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5801         
5802         if (error)
5803                 g_error_free (error);
5804
5805         return utf32_output;
5806 }
5807
5808 /**
5809  * mono_string_from_utf16:
5810  * @data: the UTF16 string (LPWSTR) to convert
5811  *
5812  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5813  *
5814  * Returns: a MonoString.
5815  */
5816 MonoString *
5817 mono_string_from_utf16 (gunichar2 *data)
5818 {
5819         MONO_REQ_GC_UNSAFE_MODE;
5820
5821         MonoDomain *domain = mono_domain_get ();
5822         int len = 0;
5823
5824         if (!data)
5825                 return NULL;
5826
5827         while (data [len]) len++;
5828
5829         return mono_string_new_utf16 (domain, data, len);
5830 }
5831
5832 /**
5833  * mono_string_from_utf32:
5834  * @data: the UTF32 string (LPWSTR) to convert
5835  *
5836  * Converts a UTF32 (UCS-4)to a MonoString.
5837  *
5838  * Returns: a MonoString.
5839  */
5840 MonoString *
5841 mono_string_from_utf32 (mono_unichar4 *data)
5842 {
5843         MONO_REQ_GC_UNSAFE_MODE;
5844
5845         MonoString* result = NULL;
5846         mono_unichar2 *utf16_output = NULL;
5847         GError *error = NULL;
5848         glong items_written;
5849         int len = 0;
5850
5851         if (!data)
5852                 return NULL;
5853
5854         while (data [len]) len++;
5855
5856         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5857
5858         if (error)
5859                 g_error_free (error);
5860
5861         result = mono_string_from_utf16 (utf16_output);
5862         g_free (utf16_output);
5863         return result;
5864 }
5865
5866 static char *
5867 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5868 {
5869         MONO_REQ_GC_UNSAFE_MODE;
5870
5871         char *r;
5872         char *mp_s;
5873         int len;
5874
5875         if (ignore_error) {
5876                 r = mono_string_to_utf8_ignore (s);
5877         } else {
5878                 r = mono_string_to_utf8_checked (s, error);
5879                 if (!mono_error_ok (error))
5880                         return NULL;
5881         }
5882
5883         if (!mp && !image)
5884                 return r;
5885
5886         len = strlen (r) + 1;
5887         if (mp)
5888                 mp_s = mono_mempool_alloc (mp, len);
5889         else
5890                 mp_s = mono_image_alloc (image, len);
5891
5892         memcpy (mp_s, r, len);
5893
5894         g_free (r);
5895
5896         return mp_s;
5897 }
5898
5899 /**
5900  * mono_string_to_utf8_image:
5901  * @s: a System.String
5902  *
5903  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5904  */
5905 char *
5906 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5907 {
5908         MONO_REQ_GC_UNSAFE_MODE;
5909
5910         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5911 }
5912
5913 /**
5914  * mono_string_to_utf8_mp:
5915  * @s: a System.String
5916  *
5917  * Same as mono_string_to_utf8, but allocate the string from a mempool.
5918  */
5919 char *
5920 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5921 {
5922         MONO_REQ_GC_UNSAFE_MODE;
5923
5924         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5925 }
5926
5927
5928 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5929
5930 void
5931 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5932 {
5933         eh_callbacks = *cbs;
5934 }
5935
5936 MonoRuntimeExceptionHandlingCallbacks *
5937 mono_get_eh_callbacks (void)
5938 {
5939         return &eh_callbacks;
5940 }
5941
5942 /**
5943  * mono_raise_exception:
5944  * @ex: exception object
5945  *
5946  * Signal the runtime that the exception @ex has been raised in unmanaged code.
5947  */
5948 void
5949 mono_raise_exception (MonoException *ex) 
5950 {
5951         MONO_REQ_GC_UNSAFE_MODE;
5952
5953         /*
5954          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5955          * that will cause gcc to omit the function epilog, causing problems when
5956          * the JIT tries to walk the stack, since the return address on the stack
5957          * will point into the next function in the executable, not this one.
5958          */     
5959         eh_callbacks.mono_raise_exception (ex);
5960 }
5961
5962 void
5963 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
5964 {
5965         MONO_REQ_GC_UNSAFE_MODE;
5966
5967         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5968 }
5969
5970 /**
5971  * mono_wait_handle_new:
5972  * @domain: Domain where the object will be created
5973  * @handle: Handle for the wait handle
5974  *
5975  * Returns: A new MonoWaitHandle created in the given domain for the given handle
5976  */
5977 MonoWaitHandle *
5978 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5979 {
5980         MONO_REQ_GC_UNSAFE_MODE;
5981
5982         MonoWaitHandle *res;
5983         gpointer params [1];
5984         static MonoMethod *handle_set;
5985
5986         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5987
5988         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
5989         if (!handle_set)
5990                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5991
5992         params [0] = &handle;
5993         mono_runtime_invoke (handle_set, res, params, NULL);
5994
5995         return res;
5996 }
5997
5998 HANDLE
5999 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6000 {
6001         MONO_REQ_GC_UNSAFE_MODE;
6002
6003         static MonoClassField *f_os_handle;
6004         static MonoClassField *f_safe_handle;
6005
6006         if (!f_os_handle && !f_safe_handle) {
6007                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6008                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6009         }
6010
6011         if (f_os_handle) {
6012                 HANDLE retval;
6013                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6014                 return retval;
6015         } else {
6016                 MonoSafeHandle *sh;
6017                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6018                 return sh->handle;
6019         }
6020 }
6021
6022
6023 static MonoObject*
6024 mono_runtime_capture_context (MonoDomain *domain)
6025 {
6026         MONO_REQ_GC_UNSAFE_MODE;
6027
6028         RuntimeInvokeFunction runtime_invoke;
6029
6030         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6031                 MonoMethod *method = mono_get_context_capture_method ();
6032                 MonoMethod *wrapper;
6033                 if (!method)
6034                         return NULL;
6035                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6036                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6037                 domain->capture_context_method = mono_compile_method (method);
6038         }
6039
6040         runtime_invoke = domain->capture_context_runtime_invoke;
6041
6042         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6043 }
6044 /**
6045  * mono_async_result_new:
6046  * @domain:domain where the object will be created.
6047  * @handle: wait handle.
6048  * @state: state to pass to AsyncResult
6049  * @data: C closure data.
6050  *
6051  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6052  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6053  *
6054  */
6055 MonoAsyncResult *
6056 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6057 {
6058         MONO_REQ_GC_UNSAFE_MODE;
6059
6060         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6061         MonoObject *context = mono_runtime_capture_context (domain);
6062         /* we must capture the execution context from the original thread */
6063         if (context) {
6064                 MONO_OBJECT_SETREF (res, execution_context, context);
6065                 /* note: result may be null if the flow is suppressed */
6066         }
6067
6068         res->data = data;
6069         MONO_OBJECT_SETREF (res, object_data, object_data);
6070         MONO_OBJECT_SETREF (res, async_state, state);
6071         if (handle != NULL)
6072                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6073
6074         res->sync_completed = FALSE;
6075         res->completed = FALSE;
6076
6077         return res;
6078 }
6079
6080 MonoObject *
6081 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6082 {
6083         MONO_REQ_GC_UNSAFE_MODE;
6084
6085         MonoAsyncCall *ac;
6086         MonoObject *res;
6087
6088         g_assert (ares);
6089         g_assert (ares->async_delegate);
6090
6091         ac = (MonoAsyncCall*) ares->object_data;
6092         if (!ac) {
6093                 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6094         } else {
6095                 gpointer wait_event = NULL;
6096
6097                 ac->msg->exc = NULL;
6098                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6099                 MONO_OBJECT_SETREF (ac, res, res);
6100
6101                 mono_monitor_enter ((MonoObject*) ares);
6102                 ares->completed = 1;
6103                 if (ares->handle)
6104                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6105                 mono_monitor_exit ((MonoObject*) ares);
6106
6107                 if (wait_event != NULL)
6108                         SetEvent (wait_event);
6109
6110                 if (ac->cb_method) {
6111                         /* we swallow the excepton as it is the behavior on .NET */
6112                         MonoObject *exc = NULL;
6113                         mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6114                         if (exc)
6115                                 mono_unhandled_exception (exc);
6116                 }
6117         }
6118
6119         return res;
6120 }
6121
6122 void
6123 mono_message_init (MonoDomain *domain,
6124                    MonoMethodMessage *this_obj, 
6125                    MonoReflectionMethod *method,
6126                    MonoArray *out_args)
6127 {
6128         MONO_REQ_GC_UNSAFE_MODE;
6129
6130         static MonoClass *object_array_klass;
6131         static MonoClass *byte_array_klass;
6132         static MonoClass *string_array_klass;
6133         MonoMethodSignature *sig = mono_method_signature (method->method);
6134         MonoString *name;
6135         int i, j;
6136         char **names;
6137         guint8 arg_type;
6138
6139         if (!object_array_klass) {
6140                 MonoClass *klass;
6141
6142                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6143                 g_assert (klass);
6144                 byte_array_klass = klass;
6145
6146                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6147                 g_assert (klass);
6148                 string_array_klass = klass;
6149
6150                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6151                 g_assert (klass);
6152
6153                 mono_atomic_store_release (&object_array_klass, klass);
6154         }
6155
6156         MONO_OBJECT_SETREF (this_obj, method, method);
6157
6158         MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6159         MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6160         this_obj->async_result = NULL;
6161         this_obj->call_type = CallType_Sync;
6162
6163         names = g_new (char *, sig->param_count);
6164         mono_method_get_param_names (method->method, (const char **) names);
6165         MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6166         
6167         for (i = 0; i < sig->param_count; i++) {
6168                 name = mono_string_new (domain, names [i]);
6169                 mono_array_setref (this_obj->names, i, name);   
6170         }
6171
6172         g_free (names);
6173         for (i = 0, j = 0; i < sig->param_count; i++) {
6174                 if (sig->params [i]->byref) {
6175                         if (out_args) {
6176                                 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6177                                 mono_array_setref (this_obj->args, i, arg);
6178                                 j++;
6179                         }
6180                         arg_type = 2;
6181                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6182                                 arg_type |= 1;
6183                 } else {
6184                         arg_type = 1;
6185                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6186                                 arg_type |= 4;
6187                 }
6188                 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6189         }
6190 }
6191
6192 #ifndef DISABLE_REMOTING
6193 /**
6194  * mono_remoting_invoke:
6195  * @real_proxy: pointer to a RealProxy object
6196  * @msg: The MonoMethodMessage to execute
6197  * @exc: used to store exceptions
6198  * @out_args: used to store output arguments
6199  *
6200  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6201  * IMessage interface and it is not trivial to extract results from there. So
6202  * we call an helper method PrivateInvoke instead of calling
6203  * RealProxy::Invoke() directly.
6204  *
6205  * Returns: the result object.
6206  */
6207 MonoObject *
6208 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
6209                       MonoObject **exc, MonoArray **out_args)
6210 {
6211         MONO_REQ_GC_UNSAFE_MODE;
6212
6213         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6214         gpointer pa [4];
6215
6216         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6217
6218         if (!im) {
6219                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6220                 if (!im)
6221                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6222                 real_proxy->vtable->domain->private_invoke_method = im;
6223         }
6224
6225         pa [0] = real_proxy;
6226         pa [1] = msg;
6227         pa [2] = exc;
6228         pa [3] = out_args;
6229
6230         return mono_runtime_invoke (im, NULL, pa, exc);
6231 }
6232 #endif
6233
6234 MonoObject *
6235 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6236                      MonoObject **exc, MonoArray **out_args) 
6237 {
6238         MONO_REQ_GC_UNSAFE_MODE;
6239
6240         static MonoClass *object_array_klass;
6241         MonoDomain *domain; 
6242         MonoMethod *method;
6243         MonoMethodSignature *sig;
6244         MonoObject *ret;
6245         int i, j, outarg_count = 0;
6246
6247 #ifndef DISABLE_REMOTING
6248         if (target && mono_object_is_transparent_proxy (target)) {
6249                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6250                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6251                         target = tp->rp->unwrapped_server;
6252                 } else {
6253                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6254                 }
6255         }
6256 #endif
6257
6258         domain = mono_domain_get (); 
6259         method = msg->method->method;
6260         sig = mono_method_signature (method);
6261
6262         for (i = 0; i < sig->param_count; i++) {
6263                 if (sig->params [i]->byref) 
6264                         outarg_count++;
6265         }
6266
6267         if (!object_array_klass) {
6268                 MonoClass *klass;
6269
6270                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6271                 g_assert (klass);
6272
6273                 mono_memory_barrier ();
6274                 object_array_klass = klass;
6275         }
6276
6277         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
6278         *exc = NULL;
6279
6280         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6281
6282         for (i = 0, j = 0; i < sig->param_count; i++) {
6283                 if (sig->params [i]->byref) {
6284                         MonoObject* arg;
6285                         arg = mono_array_get (msg->args, gpointer, i);
6286                         mono_array_setref (*out_args, j, arg);
6287                         j++;
6288                 }
6289         }
6290
6291         return ret;
6292 }
6293
6294 /**
6295  * mono_object_to_string:
6296  * @obj: The object
6297  * @exc: Any exception thrown by ToString (). May be NULL.
6298  *
6299  * Returns: the result of calling ToString () on an object.
6300  */
6301 MonoString *
6302 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6303 {
6304         MONO_REQ_GC_UNSAFE_MODE;
6305
6306         static MonoMethod *to_string = NULL;
6307         MonoMethod *method;
6308         void *target = obj;
6309
6310         g_assert (obj);
6311
6312         if (!to_string)
6313                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6314
6315         method = mono_object_get_virtual_method (obj, to_string);
6316
6317         // Unbox value type if needed
6318         if (mono_class_is_valuetype (mono_method_get_class (method))) {
6319                 target = mono_object_unbox (obj);
6320         }
6321
6322         return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6323 }
6324
6325 /**
6326  * mono_print_unhandled_exception:
6327  * @exc: The exception
6328  *
6329  * Prints the unhandled exception.
6330  */
6331 void
6332 mono_print_unhandled_exception (MonoObject *exc)
6333 {
6334         MONO_REQ_GC_UNSAFE_MODE;
6335
6336         MonoString * str;
6337         char *message = (char*)"";
6338         gboolean free_message = FALSE;
6339         MonoError error;
6340
6341         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6342                 message = g_strdup ("OutOfMemoryException");
6343                 free_message = TRUE;
6344         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6345                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6346                 free_message = TRUE;
6347         } else {
6348                 
6349                 if (((MonoException*)exc)->native_trace_ips) {
6350                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
6351                         free_message = TRUE;
6352                 } else {
6353                         MonoObject *other_exc = NULL;
6354                         str = mono_object_to_string (exc, &other_exc);
6355                         if (other_exc) {
6356                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6357                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6358                                 
6359                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6360                                         original_backtrace, nested_backtrace);
6361
6362                                 g_free (original_backtrace);
6363                                 g_free (nested_backtrace);
6364                                 free_message = TRUE;
6365                         } else if (str) {
6366                                 message = mono_string_to_utf8_checked (str, &error);
6367                                 if (!mono_error_ok (&error)) {
6368                                         mono_error_cleanup (&error);
6369                                         message = (char *) "";
6370                                 } else {
6371                                         free_message = TRUE;
6372                                 }
6373                         }
6374                 }
6375         }
6376
6377         /*
6378          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
6379          *         exc->vtable->klass->name, message);
6380          */
6381         g_printerr ("\nUnhandled Exception:\n%s\n", message);
6382         
6383         if (free_message)
6384                 g_free (message);
6385 }
6386
6387 /**
6388  * mono_delegate_ctor:
6389  * @this: pointer to an uninitialized delegate object
6390  * @target: target object
6391  * @addr: pointer to native code
6392  * @method: method
6393  *
6394  * Initialize a delegate and sets a specific method, not the one
6395  * associated with addr.  This is useful when sharing generic code.
6396  * In that case addr will most probably not be associated with the
6397  * correct instantiation of the method.
6398  */
6399 void
6400 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6401 {
6402         MONO_REQ_GC_UNSAFE_MODE;
6403
6404         MonoDelegate *delegate = (MonoDelegate *)this_obj;
6405
6406         g_assert (this_obj);
6407         g_assert (addr);
6408
6409         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6410
6411         if (method)
6412                 delegate->method = method;
6413
6414         mono_stats.delegate_creations++;
6415
6416 #ifndef DISABLE_REMOTING
6417         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6418                 g_assert (method);
6419                 method = mono_marshal_get_remoting_invoke (method);
6420                 delegate->method_ptr = mono_compile_method (method);
6421                 MONO_OBJECT_SETREF (delegate, target, target);
6422         } else
6423 #endif
6424         {
6425                 delegate->method_ptr = addr;
6426                 MONO_OBJECT_SETREF (delegate, target, target);
6427         }
6428
6429         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6430 }
6431
6432 /**
6433  * mono_delegate_ctor:
6434  * @this: pointer to an uninitialized delegate object
6435  * @target: target object
6436  * @addr: pointer to native code
6437  *
6438  * This is used to initialize a delegate.
6439  */
6440 void
6441 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6442 {
6443         MONO_REQ_GC_UNSAFE_MODE;
6444
6445         MonoDomain *domain = mono_domain_get ();
6446         MonoJitInfo *ji;
6447         MonoMethod *method = NULL;
6448
6449         g_assert (addr);
6450
6451         ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6452         /* Shared code */
6453         if (!ji && domain != mono_get_root_domain ())
6454                 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6455         if (ji) {
6456                 method = mono_jit_info_get_method (ji);
6457                 g_assert (!method->klass->generic_container);
6458         }
6459
6460         mono_delegate_ctor_with_method (this_obj, target, addr, method);
6461 }
6462
6463 /**
6464  * mono_method_call_message_new:
6465  * @method: method to encapsulate
6466  * @params: parameters to the method
6467  * @invoke: optional, delegate invoke.
6468  * @cb: async callback delegate.
6469  * @state: state passed to the async callback.
6470  *
6471  * Translates arguments pointers into a MonoMethodMessage.
6472  */
6473 MonoMethodMessage *
6474 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
6475                               MonoDelegate **cb, MonoObject **state)
6476 {
6477         MONO_REQ_GC_UNSAFE_MODE;
6478
6479         MonoDomain *domain = mono_domain_get ();
6480         MonoMethodSignature *sig = mono_method_signature (method);
6481         MonoMethodMessage *msg;
6482         int i, count;
6483
6484         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
6485         
6486         if (invoke) {
6487                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6488                 count =  sig->param_count - 2;
6489         } else {
6490                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6491                 count =  sig->param_count;
6492         }
6493
6494         for (i = 0; i < count; i++) {
6495                 gpointer vpos;
6496                 MonoClass *class;
6497                 MonoObject *arg;
6498
6499                 if (sig->params [i]->byref)
6500                         vpos = *((gpointer *)params [i]);
6501                 else 
6502                         vpos = params [i];
6503
6504                 class = mono_class_from_mono_type (sig->params [i]);
6505
6506                 if (class->valuetype)
6507                         arg = mono_value_box (domain, class, vpos);
6508                 else 
6509                         arg = *((MonoObject **)vpos);
6510                       
6511                 mono_array_setref (msg->args, i, arg);
6512         }
6513
6514         if (cb != NULL && state != NULL) {
6515                 *cb = *((MonoDelegate **)params [i]);
6516                 i++;
6517                 *state = *((MonoObject **)params [i]);
6518         }
6519
6520         return msg;
6521 }
6522
6523 /**
6524  * mono_method_return_message_restore:
6525  *
6526  * Restore results from message based processing back to arguments pointers
6527  */
6528 void
6529 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6530 {
6531         MONO_REQ_GC_UNSAFE_MODE;
6532
6533         MonoMethodSignature *sig = mono_method_signature (method);
6534         int i, j, type, size, out_len;
6535         
6536         if (out_args == NULL)
6537                 return;
6538         out_len = mono_array_length (out_args);
6539         if (out_len == 0)
6540                 return;
6541
6542         for (i = 0, j = 0; i < sig->param_count; i++) {
6543                 MonoType *pt = sig->params [i];
6544
6545                 if (pt->byref) {
6546                         char *arg;
6547                         if (j >= out_len)
6548                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6549
6550                         arg = mono_array_get (out_args, gpointer, j);
6551                         type = pt->type;
6552
6553                         g_assert (type != MONO_TYPE_VOID);
6554
6555                         if (MONO_TYPE_IS_REFERENCE (pt)) {
6556                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6557                         } else {
6558                                 if (arg) {
6559                                         MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6560                                         size = mono_class_value_size (class, NULL);
6561                                         if (class->has_references)
6562                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6563                                         else
6564                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6565                                 } else {
6566                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6567                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6568                                 }
6569                         }
6570
6571                         j++;
6572                 }
6573         }
6574 }
6575
6576 #ifndef DISABLE_REMOTING
6577
6578 /**
6579  * mono_load_remote_field:
6580  * @this: pointer to an object
6581  * @klass: klass of the object containing @field
6582  * @field: the field to load
6583  * @res: a storage to store the result
6584  *
6585  * This method is called by the runtime on attempts to load fields of
6586  * transparent proxy objects. @this points to such TP, @klass is the class of
6587  * the object containing @field. @res is a storage location which can be
6588  * used to store the result.
6589  *
6590  * Returns: an address pointing to the value of field.
6591  */
6592 gpointer
6593 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6594 {
6595         MONO_REQ_GC_UNSAFE_MODE;
6596
6597         static MonoMethod *getter = NULL;
6598         MonoDomain *domain = mono_domain_get ();
6599         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6600         MonoClass *field_class;
6601         MonoMethodMessage *msg;
6602         MonoArray *out_args;
6603         MonoObject *exc;
6604         char* full_name;
6605
6606         g_assert (mono_object_is_transparent_proxy (this_obj));
6607         g_assert (res != NULL);
6608
6609         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6610                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6611                 return res;
6612         }
6613         
6614         if (!getter) {
6615                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6616                 if (!getter)
6617                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6618         }
6619         
6620         field_class = mono_class_from_mono_type (field->type);
6621
6622         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6623         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6624         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6625
6626         full_name = mono_type_get_full_name (klass);
6627         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6628         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6629         g_free (full_name);
6630
6631         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6632
6633         if (exc) mono_raise_exception ((MonoException *)exc);
6634
6635         if (mono_array_length (out_args) == 0)
6636                 return NULL;
6637
6638         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6639
6640         if (field_class->valuetype) {
6641                 return ((char *)*res) + sizeof (MonoObject);
6642         } else
6643                 return res;
6644 }
6645
6646 /**
6647  * mono_load_remote_field_new:
6648  * @this: 
6649  * @klass: 
6650  * @field:
6651  *
6652  * Missing documentation.
6653  */
6654 MonoObject *
6655 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6656 {
6657         MONO_REQ_GC_UNSAFE_MODE;
6658
6659         static MonoMethod *getter = NULL;
6660         MonoDomain *domain = mono_domain_get ();
6661         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6662         MonoClass *field_class;
6663         MonoMethodMessage *msg;
6664         MonoArray *out_args;
6665         MonoObject *exc, *res;
6666         char* full_name;
6667
6668         g_assert (mono_object_is_transparent_proxy (this_obj));
6669
6670         field_class = mono_class_from_mono_type (field->type);
6671
6672         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6673                 gpointer val;
6674                 if (field_class->valuetype) {
6675                         res = mono_object_new (domain, field_class);
6676                         val = ((gchar *) res) + sizeof (MonoObject);
6677                 } else {
6678                         val = &res;
6679                 }
6680                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6681                 return res;
6682         }
6683
6684         if (!getter) {
6685                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6686                 if (!getter)
6687                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6688         }
6689         
6690         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6691         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6692
6693         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6694
6695         full_name = mono_type_get_full_name (klass);
6696         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6697         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6698         g_free (full_name);
6699
6700         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6701
6702         if (exc) mono_raise_exception ((MonoException *)exc);
6703
6704         if (mono_array_length (out_args) == 0)
6705                 res = NULL;
6706         else
6707                 res = mono_array_get (out_args, MonoObject *, 0);
6708
6709         return res;
6710 }
6711
6712 /**
6713  * mono_store_remote_field:
6714  * @this_obj: pointer to an object
6715  * @klass: klass of the object containing @field
6716  * @field: the field to load
6717  * @val: the value/object to store
6718  *
6719  * This method is called by the runtime on attempts to store fields of
6720  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6721  * the object containing @field. @val is the new value to store in @field.
6722  */
6723 void
6724 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6725 {
6726         MONO_REQ_GC_UNSAFE_MODE;
6727
6728         static MonoMethod *setter = NULL;
6729         MonoDomain *domain = mono_domain_get ();
6730         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6731         MonoClass *field_class;
6732         MonoMethodMessage *msg;
6733         MonoArray *out_args;
6734         MonoObject *exc;
6735         MonoObject *arg;
6736         char* full_name;
6737
6738         g_assert (mono_object_is_transparent_proxy (this_obj));
6739
6740         field_class = mono_class_from_mono_type (field->type);
6741
6742         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6743                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6744                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6745                 return;
6746         }
6747
6748         if (!setter) {
6749                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6750                 if (!setter)
6751                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6752         }
6753
6754         if (field_class->valuetype)
6755                 arg = mono_value_box (domain, field_class, val);
6756         else 
6757                 arg = *((MonoObject **)val);
6758                 
6759
6760         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6761         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6762
6763         full_name = mono_type_get_full_name (klass);
6764         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6765         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6766         mono_array_setref (msg->args, 2, arg);
6767         g_free (full_name);
6768
6769         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6770
6771         if (exc) mono_raise_exception ((MonoException *)exc);
6772 }
6773
6774 /**
6775  * mono_store_remote_field_new:
6776  * @this_obj:
6777  * @klass:
6778  * @field:
6779  * @arg:
6780  *
6781  * Missing documentation
6782  */
6783 void
6784 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6785 {
6786         MONO_REQ_GC_UNSAFE_MODE;
6787
6788         static MonoMethod *setter = NULL;
6789         MonoDomain *domain = mono_domain_get ();
6790         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6791         MonoClass *field_class;
6792         MonoMethodMessage *msg;
6793         MonoArray *out_args;
6794         MonoObject *exc;
6795         char* full_name;
6796
6797         g_assert (mono_object_is_transparent_proxy (this_obj));
6798
6799         field_class = mono_class_from_mono_type (field->type);
6800
6801         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6802                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6803                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6804                 return;
6805         }
6806
6807         if (!setter) {
6808                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6809                 if (!setter)
6810                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6811         }
6812
6813         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6814         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6815
6816         full_name = mono_type_get_full_name (klass);
6817         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6818         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6819         mono_array_setref (msg->args, 2, arg);
6820         g_free (full_name);
6821
6822         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6823
6824         if (exc) mono_raise_exception ((MonoException *)exc);
6825 }
6826 #endif
6827
6828 /*
6829  * mono_create_ftnptr:
6830  *
6831  *   Given a function address, create a function descriptor for it.
6832  * This is only needed on some platforms.
6833  */
6834 gpointer
6835 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6836 {
6837         return callbacks.create_ftnptr (domain, addr);
6838 }
6839
6840 /*
6841  * mono_get_addr_from_ftnptr:
6842  *
6843  *   Given a pointer to a function descriptor, return the function address.
6844  * This is only needed on some platforms.
6845  */
6846 gpointer
6847 mono_get_addr_from_ftnptr (gpointer descr)
6848 {
6849         return callbacks.get_addr_from_ftnptr (descr);
6850 }       
6851
6852 /**
6853  * mono_string_chars:
6854  * @s: a MonoString
6855  *
6856  * Returns a pointer to the UCS16 characters stored in the MonoString
6857  */
6858 gunichar2 *
6859 mono_string_chars (MonoString *s)
6860 {
6861         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
6862
6863         return s->chars;
6864 }
6865
6866 /**
6867  * mono_string_length:
6868  * @s: MonoString
6869  *
6870  * Returns the lenght in characters of the string
6871  */
6872 int
6873 mono_string_length (MonoString *s)
6874 {
6875         MONO_REQ_GC_UNSAFE_MODE;
6876
6877         return s->length;
6878 }
6879
6880 /**
6881  * mono_array_length:
6882  * @array: a MonoArray*
6883  *
6884  * Returns the total number of elements in the array. This works for
6885  * both vectors and multidimensional arrays.
6886  */
6887 uintptr_t
6888 mono_array_length (MonoArray *array)
6889 {
6890         MONO_REQ_GC_UNSAFE_MODE;
6891
6892         return array->max_length;
6893 }
6894
6895 /**
6896  * mono_array_addr_with_size:
6897  * @array: a MonoArray*
6898  * @size: size of the array elements
6899  * @idx: index into the array
6900  *
6901  * Returns the address of the @idx element in the array.
6902  */
6903 char*
6904 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6905 {
6906         MONO_REQ_GC_UNSAFE_MODE;
6907
6908         return ((char*)(array)->vector) + size * idx;
6909 }
6910