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