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