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