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