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