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