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