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