2010-05-07 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  */
11 #include <config.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <signal.h>
18 #include <string.h>
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/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  * Launch a new thread to execute a function
3750  *
3751  * main_func is called back from the thread with main_args as the
3752  * parameter.  The callback function is expected to start Main()
3753  * eventually.  This function then waits for all managed threads to
3754  * finish.
3755  * It is not necesseray anymore to execute managed code in a subthread,
3756  * so this function should not be used anymore by default: just
3757  * execute the code and then call mono_thread_manage ().
3758  */
3759 void
3760 mono_runtime_exec_managed_code (MonoDomain *domain,
3761                                 MonoMainThreadFunc main_func,
3762                                 gpointer main_args)
3763 {
3764         mono_thread_create (domain, main_func, main_args);
3765
3766         mono_thread_manage ();
3767 }
3768
3769 /*
3770  * Execute a standard Main() method (args doesn't contain the
3771  * executable name).
3772  */
3773 int
3774 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3775 {
3776         MonoDomain *domain;
3777         gpointer pa [1];
3778         int rval;
3779         MonoCustomAttrInfo* cinfo;
3780         gboolean has_stathread_attribute;
3781         MonoInternalThread* thread = mono_thread_internal_current ();
3782
3783         g_assert (args);
3784
3785         pa [0] = args;
3786
3787         domain = mono_object_domain (args);
3788         if (!domain->entry_assembly) {
3789                 gchar *str;
3790                 MonoAssembly *assembly;
3791
3792                 assembly = method->klass->image->assembly;
3793                 domain->entry_assembly = assembly;
3794                 /* Domains created from another domain already have application_base and configuration_file set */
3795                 if (domain->setup->application_base == NULL) {
3796                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3797                 }
3798
3799                 if (domain->setup->configuration_file == NULL) {
3800                         str = g_strconcat (assembly->image->name, ".config", NULL);
3801                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3802                         g_free (str);
3803                         mono_set_private_bin_path_from_config (domain);
3804                 }
3805         }
3806
3807         cinfo = mono_custom_attrs_from_method (method);
3808         if (cinfo) {
3809                 static MonoClass *stathread_attribute = NULL;
3810                 if (!stathread_attribute)
3811                         stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3812                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3813                 if (!cinfo->cached)
3814                         mono_custom_attrs_free (cinfo);
3815         } else {
3816                 has_stathread_attribute = FALSE;
3817         }
3818         if (has_stathread_attribute) {
3819                 thread->apartment_state = ThreadApartmentState_STA;
3820         } else {
3821                 thread->apartment_state = ThreadApartmentState_MTA;
3822         }
3823         mono_thread_init_apartment_state ();
3824
3825         mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3826
3827         /* FIXME: check signature of method */
3828         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3829                 MonoObject *res;
3830                 res = mono_runtime_invoke (method, NULL, pa, exc);
3831                 if (!exc || !*exc)
3832                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3833                 else
3834                         rval = -1;
3835
3836                 mono_environment_exitcode_set (rval);
3837         } else {
3838                 mono_runtime_invoke (method, NULL, pa, exc);
3839                 if (!exc || !*exc)
3840                         rval = 0;
3841                 else {
3842                         /* If the return type of Main is void, only
3843                          * set the exitcode if an exception was thrown
3844                          * (we don't want to blow away an
3845                          * explicitly-set exit code)
3846                          */
3847                         rval = -1;
3848                         mono_environment_exitcode_set (rval);
3849                 }
3850         }
3851
3852         mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3853
3854         return rval;
3855 }
3856
3857 /**
3858  * mono_install_runtime_invoke:
3859  * @func: Function to install
3860  *
3861  * This is a VM internal routine
3862  */
3863 void
3864 mono_install_runtime_invoke (MonoInvokeFunc func)
3865 {
3866         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3867 }
3868
3869
3870 /**
3871  * mono_runtime_invoke_array:
3872  * @method: method to invoke
3873  * @obJ: object instance
3874  * @params: arguments to the method
3875  * @exc: exception information.
3876  *
3877  * Invokes the method represented by @method on the object @obj.
3878  *
3879  * obj is the 'this' pointer, it should be NULL for static
3880  * methods, a MonoObject* for object instances and a pointer to
3881  * the value type for value types.
3882  *
3883  * The params array contains the arguments to the method with the
3884  * same convention: MonoObject* pointers for object instances and
3885  * pointers to the value type otherwise. The _invoke_array
3886  * variant takes a C# object[] as the params argument (MonoArray
3887  * *params): in this case the value types are boxed inside the
3888  * respective reference representation.
3889  * 
3890  * From unmanaged code you'll usually use the
3891  * mono_runtime_invoke() variant.
3892  *
3893  * Note that this function doesn't handle virtual methods for
3894  * you, it will exec the exact method you pass: we still need to
3895  * expose a function to lookup the derived class implementation
3896  * of a virtual method (there are examples of this in the code,
3897  * though).
3898  * 
3899  * You can pass NULL as the exc argument if you don't want to
3900  * catch exceptions, otherwise, *exc will be set to the exception
3901  * thrown, if any.  if an exception is thrown, you can't use the
3902  * MonoObject* result from the function.
3903  * 
3904  * If the method returns a value type, it is boxed in an object
3905  * reference.
3906  */
3907 MonoObject*
3908 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3909                            MonoObject **exc)
3910 {
3911         MonoMethodSignature *sig = mono_method_signature (method);
3912         gpointer *pa = NULL;
3913         MonoObject *res;
3914         int i;
3915         gboolean has_byref_nullables = FALSE;
3916
3917         if (NULL != params) {
3918                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3919                 for (i = 0; i < mono_array_length (params); i++) {
3920                         MonoType *t = sig->params [i];
3921
3922                 again:
3923                         switch (t->type) {
3924                         case MONO_TYPE_U1:
3925                         case MONO_TYPE_I1:
3926                         case MONO_TYPE_BOOLEAN:
3927                         case MONO_TYPE_U2:
3928                         case MONO_TYPE_I2:
3929                         case MONO_TYPE_CHAR:
3930                         case MONO_TYPE_U:
3931                         case MONO_TYPE_I:
3932                         case MONO_TYPE_U4:
3933                         case MONO_TYPE_I4:
3934                         case MONO_TYPE_U8:
3935                         case MONO_TYPE_I8:
3936                         case MONO_TYPE_R4:
3937                         case MONO_TYPE_R8:
3938                         case MONO_TYPE_VALUETYPE:
3939                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3940                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3941                                         pa [i] = mono_array_get (params, MonoObject*, i);
3942                                         if (t->byref)
3943                                                 has_byref_nullables = TRUE;
3944                                 } else {
3945                                         /* MS seems to create the objects if a null is passed in */
3946                                         if (!mono_array_get (params, MonoObject*, i))
3947                                                 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
3948
3949                                         if (t->byref) {
3950                                                 /*
3951                                                  * We can't pass the unboxed vtype byref to the callee, since
3952                                                  * that would mean the callee would be able to modify boxed
3953                                                  * primitive types. So we (and MS) make a copy of the boxed
3954                                                  * object, pass that to the callee, and replace the original
3955                                                  * boxed object in the arg array with the copy.
3956                                                  */
3957                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3958                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3959                                                 mono_array_setref (params, i, copy);
3960                                         }
3961                                                 
3962                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3963                                 }
3964                                 break;
3965                         case MONO_TYPE_STRING:
3966                         case MONO_TYPE_OBJECT:
3967                         case MONO_TYPE_CLASS:
3968                         case MONO_TYPE_ARRAY:
3969                         case MONO_TYPE_SZARRAY:
3970                                 if (t->byref)
3971                                         pa [i] = mono_array_addr (params, MonoObject*, i);
3972                                         // FIXME: I need to check this code path
3973                                 else
3974                                         pa [i] = mono_array_get (params, MonoObject*, i);
3975                                 break;
3976                         case MONO_TYPE_GENERICINST:
3977                                 if (t->byref)
3978                                         t = &t->data.generic_class->container_class->this_arg;
3979                                 else
3980                                         t = &t->data.generic_class->container_class->byval_arg;
3981                                 goto again;
3982                         case MONO_TYPE_PTR: {
3983                                 MonoObject *arg;
3984
3985                                 /* The argument should be an IntPtr */
3986                                 arg = mono_array_get (params, MonoObject*, i);
3987                                 if (arg == NULL) {
3988                                         pa [i] = NULL;
3989                                 } else {
3990                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
3991                                         pa [i] = ((MonoIntPtr*)arg)->m_value;
3992                                 }
3993                                 break;
3994                         }
3995                         default:
3996                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3997                         }
3998                 }
3999         }
4000
4001         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4002                 void *o = obj;
4003
4004                 if (mono_class_is_nullable (method->klass)) {
4005                         /* Need to create a boxed vtype instead */
4006                         g_assert (!obj);
4007
4008                         if (!params)
4009                                 return NULL;
4010                         else
4011                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4012                 }
4013
4014                 if (!obj) {
4015                         obj = mono_object_new (mono_domain_get (), method->klass);
4016                         g_assert (obj); /*maybe we should raise a TLE instead?*/
4017                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4018                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4019                         }
4020                         if (method->klass->valuetype)
4021                                 o = mono_object_unbox (obj);
4022                         else
4023                                 o = obj;
4024                 } else if (method->klass->valuetype) {
4025                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
4026                 }
4027
4028                 mono_runtime_invoke (method, o, pa, exc);
4029                 return obj;
4030         } else {
4031                 if (mono_class_is_nullable (method->klass)) {
4032                         MonoObject *nullable;
4033
4034                         /* Convert the unboxed vtype into a Nullable structure */
4035                         nullable = mono_object_new (mono_domain_get (), method->klass);
4036
4037                         mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4038                         obj = mono_object_unbox (nullable);
4039                 }
4040
4041                 /* obj must be already unboxed if needed */
4042                 res = mono_runtime_invoke (method, obj, pa, exc);
4043
4044                 if (sig->ret->type == MONO_TYPE_PTR) {
4045                         MonoClass *pointer_class;
4046                         static MonoMethod *box_method;
4047                         void *box_args [2];
4048                         MonoObject *box_exc;
4049
4050                         /* 
4051                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
4052                          * convert it to a Pointer object.
4053                          */
4054                         pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4055                         if (!box_method)
4056                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4057
4058                         g_assert (res->vtable->klass == mono_defaults.int_class);
4059                         box_args [0] = ((MonoIntPtr*)res)->m_value;
4060                         box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4061                         res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4062                         g_assert (!box_exc);
4063                 }
4064
4065                 if (has_byref_nullables) {
4066                         /* 
4067                          * The runtime invoke wrapper already converted byref nullables back,
4068                          * and stored them in pa, we just need to copy them back to the
4069                          * managed array.
4070                          */
4071                         for (i = 0; i < mono_array_length (params); i++) {
4072                                 MonoType *t = sig->params [i];
4073
4074                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4075                                         mono_array_setref (params, i, pa [i]);
4076                         }
4077                 }
4078
4079                 return res;
4080         }
4081 }
4082
4083 static void
4084 arith_overflow (void)
4085 {
4086         mono_raise_exception (mono_get_exception_overflow ());
4087 }
4088
4089 /**
4090  * mono_object_allocate:
4091  * @size: number of bytes to allocate
4092  *
4093  * This is a very simplistic routine until we have our GC-aware
4094  * memory allocator. 
4095  *
4096  * Returns: an allocated object of size @size, or NULL on failure.
4097  */
4098 static inline void *
4099 mono_object_allocate (size_t size, MonoVTable *vtable)
4100 {
4101         MonoObject *o;
4102         mono_stats.new_object_count++;
4103         ALLOC_OBJECT (o, vtable, size);
4104
4105         return o;
4106 }
4107
4108 /**
4109  * mono_object_allocate_ptrfree:
4110  * @size: number of bytes to allocate
4111  *
4112  * Note that the memory allocated is not zeroed.
4113  * Returns: an allocated object of size @size, or NULL on failure.
4114  */
4115 static inline void *
4116 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4117 {
4118         MonoObject *o;
4119         mono_stats.new_object_count++;
4120         ALLOC_PTRFREE (o, vtable, size);
4121         return o;
4122 }
4123
4124 static inline void *
4125 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4126 {
4127         void *o;
4128         ALLOC_TYPED (o, size, vtable);
4129         mono_stats.new_object_count++;
4130
4131         return o;
4132 }
4133
4134 /**
4135  * mono_object_new:
4136  * @klass: the class of the object that we want to create
4137  *
4138  * Returns: a newly created object whose definition is
4139  * looked up using @klass.   This will not invoke any constructors, 
4140  * so the consumer of this routine has to invoke any constructors on
4141  * its own to initialize the object.
4142  * 
4143  * It returns NULL on failure.
4144  */
4145 MonoObject *
4146 mono_object_new (MonoDomain *domain, MonoClass *klass)
4147 {
4148         MonoVTable *vtable;
4149
4150         MONO_ARCH_SAVE_REGS;
4151         vtable = mono_class_vtable (domain, klass);
4152         if (!vtable)
4153                 return NULL;
4154         return mono_object_new_specific (vtable);
4155 }
4156
4157 /**
4158  * mono_object_new_specific:
4159  * @vtable: the vtable of the object that we want to create
4160  *
4161  * Returns: A newly created object with class and domain specified
4162  * by @vtable
4163  */
4164 MonoObject *
4165 mono_object_new_specific (MonoVTable *vtable)
4166 {
4167         MonoObject *o;
4168
4169         MONO_ARCH_SAVE_REGS;
4170         
4171         /* check for is_com_object for COM Interop */
4172         if (vtable->remote || vtable->klass->is_com_object)
4173         {
4174                 gpointer pa [1];
4175                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4176
4177                 if (im == NULL) {
4178                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4179
4180                         if (!klass->inited)
4181                                 mono_class_init (klass);
4182
4183                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4184                         g_assert (im);
4185                         vtable->domain->create_proxy_for_type_method = im;
4186                 }
4187         
4188                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4189
4190                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
4191                 if (o != NULL) return o;
4192         }
4193
4194         return mono_object_new_alloc_specific (vtable);
4195 }
4196
4197 MonoObject *
4198 mono_object_new_alloc_specific (MonoVTable *vtable)
4199 {
4200         MonoObject *o;
4201
4202         if (!vtable->klass->has_references) {
4203                 o = mono_object_new_ptrfree (vtable);
4204         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4205                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4206         } else {
4207 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4208                 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4209         }
4210         if (G_UNLIKELY (vtable->klass->has_finalize))
4211                 mono_object_register_finalizer (o);
4212         
4213         if (G_UNLIKELY (profile_allocs))
4214                 mono_profiler_allocation (o, vtable->klass);
4215         return o;
4216 }
4217
4218 MonoObject*
4219 mono_object_new_fast (MonoVTable *vtable)
4220 {
4221         MonoObject *o;
4222         ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4223         return o;
4224 }
4225
4226 static MonoObject*
4227 mono_object_new_ptrfree (MonoVTable *vtable)
4228 {
4229         MonoObject *obj;
4230         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4231 #if NEED_TO_ZERO_PTRFREE
4232         /* an inline memset is much faster for the common vcase of small objects
4233          * note we assume the allocated size is a multiple of sizeof (void*).
4234          */
4235         if (vtable->klass->instance_size < 128) {
4236                 gpointer *p, *end;
4237                 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4238                 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4239                 while (p < end) {
4240                         *p = NULL;
4241                         ++p;
4242                 }
4243         } else {
4244                 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4245         }
4246 #endif
4247         return obj;
4248 }
4249
4250 static MonoObject*
4251 mono_object_new_ptrfree_box (MonoVTable *vtable)
4252 {
4253         MonoObject *obj;
4254         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4255         /* the object will be boxed right away, no need to memzero it */
4256         return obj;
4257 }
4258
4259 /**
4260  * mono_class_get_allocation_ftn:
4261  * @vtable: vtable
4262  * @for_box: the object will be used for boxing
4263  * @pass_size_in_words: 
4264  *
4265  * Return the allocation function appropriate for the given class.
4266  */
4267
4268 void*
4269 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4270 {
4271         *pass_size_in_words = FALSE;
4272
4273         if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4274                 profile_allocs = FALSE;
4275
4276         if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4277                 return mono_object_new_specific;
4278
4279         if (!vtable->klass->has_references) {
4280                 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4281                 if (for_box)
4282                         return mono_object_new_ptrfree_box;
4283                 return mono_object_new_ptrfree;
4284         }
4285
4286         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4287
4288                 return mono_object_new_fast;
4289
4290                 /* 
4291                  * FIXME: This is actually slower than mono_object_new_fast, because
4292                  * of the overhead of parameter passing.
4293                  */
4294                 /*
4295                 *pass_size_in_words = TRUE;
4296 #ifdef GC_REDIRECT_TO_LOCAL
4297                 return GC_local_gcj_fast_malloc;
4298 #else
4299                 return GC_gcj_fast_malloc;
4300 #endif
4301                 */
4302         }
4303
4304         return mono_object_new_specific;
4305 }
4306
4307 /**
4308  * mono_object_new_from_token:
4309  * @image: Context where the type_token is hosted
4310  * @token: a token of the type that we want to create
4311  *
4312  * Returns: A newly created object whose definition is
4313  * looked up using @token in the @image image
4314  */
4315 MonoObject *
4316 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
4317 {
4318         MonoClass *class;
4319
4320         class = mono_class_get (image, token);
4321
4322         return mono_object_new (domain, class);
4323 }
4324
4325
4326 /**
4327  * mono_object_clone:
4328  * @obj: the object to clone
4329  *
4330  * Returns: A newly created object who is a shallow copy of @obj
4331  */
4332 MonoObject *
4333 mono_object_clone (MonoObject *obj)
4334 {
4335         MonoObject *o;
4336         int size = obj->vtable->klass->instance_size;
4337
4338         o = mono_object_allocate (size, obj->vtable);
4339
4340         if (obj->vtable->klass->has_references) {
4341                 mono_gc_wbarrier_object_copy (o, obj);
4342         } else {
4343                 int size = obj->vtable->klass->instance_size;
4344                 /* do not copy the sync state */
4345                 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4346         }
4347         if (G_UNLIKELY (profile_allocs))
4348                 mono_profiler_allocation (o, obj->vtable->klass);
4349
4350         if (obj->vtable->klass->has_finalize)
4351                 mono_object_register_finalizer (o);
4352         return o;
4353 }
4354
4355 /**
4356  * mono_array_full_copy:
4357  * @src: source array to copy
4358  * @dest: destination array
4359  *
4360  * Copies the content of one array to another with exactly the same type and size.
4361  */
4362 void
4363 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4364 {
4365         uintptr_t size;
4366         MonoClass *klass = src->obj.vtable->klass;
4367
4368         MONO_ARCH_SAVE_REGS;
4369
4370         g_assert (klass == dest->obj.vtable->klass);
4371
4372         size = mono_array_length (src);
4373         g_assert (size == mono_array_length (dest));
4374         size *= mono_array_element_size (klass);
4375 #ifdef HAVE_SGEN_GC
4376         if (klass->element_class->valuetype) {
4377                 if (klass->element_class->has_references)
4378                         mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4379                 else
4380                         memcpy (&dest->vector, &src->vector, size);
4381         } else {
4382                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4383         }
4384 #else
4385         memcpy (&dest->vector, &src->vector, size);
4386 #endif
4387 }
4388
4389 /**
4390  * mono_array_clone_in_domain:
4391  * @domain: the domain in which the array will be cloned into
4392  * @array: the array to clone
4393  *
4394  * This routine returns a copy of the array that is hosted on the
4395  * specified MonoDomain.
4396  */
4397 MonoArray*
4398 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4399 {
4400         MonoArray *o;
4401         uintptr_t size, i;
4402         uintptr_t *sizes;
4403         MonoClass *klass = array->obj.vtable->klass;
4404
4405         MONO_ARCH_SAVE_REGS;
4406
4407         if (array->bounds == NULL) {
4408                 size = mono_array_length (array);
4409                 o = mono_array_new_full (domain, klass, &size, NULL);
4410
4411                 size *= mono_array_element_size (klass);
4412 #ifdef HAVE_SGEN_GC
4413                 if (klass->element_class->valuetype) {
4414                         if (klass->element_class->has_references)
4415                                 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4416                         else
4417                                 memcpy (&o->vector, &array->vector, size);
4418                 } else {
4419                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4420                 }
4421 #else
4422                 memcpy (&o->vector, &array->vector, size);
4423 #endif
4424                 return o;
4425         }
4426         
4427         sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4428         size = mono_array_element_size (klass);
4429         for (i = 0; i < klass->rank; ++i) {
4430                 sizes [i] = array->bounds [i].length;
4431                 size *= array->bounds [i].length;
4432                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4433         }
4434         o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4435 #ifdef HAVE_SGEN_GC
4436         if (klass->element_class->valuetype) {
4437                 if (klass->element_class->has_references)
4438                         mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4439                 else
4440                         memcpy (&o->vector, &array->vector, size);
4441         } else {
4442                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4443         }
4444 #else
4445         memcpy (&o->vector, &array->vector, size);
4446 #endif
4447
4448         return o;
4449 }
4450
4451 /**
4452  * mono_array_clone:
4453  * @array: the array to clone
4454  *
4455  * Returns: A newly created array who is a shallow copy of @array
4456  */
4457 MonoArray*
4458 mono_array_clone (MonoArray *array)
4459 {
4460         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4461 }
4462
4463 /* helper macros to check for overflow when calculating the size of arrays */
4464 #ifdef MONO_BIG_ARRAYS
4465 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4466 #define MYGUINT_MAX MYGUINT64_MAX
4467 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4468             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4469 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4470             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
4471                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4472 #else
4473 #define MYGUINT32_MAX 4294967295U
4474 #define MYGUINT_MAX MYGUINT32_MAX
4475 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4476             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4477 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4478             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
4479                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4480 #endif
4481
4482 gboolean
4483 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4484 {
4485         uintptr_t byte_len;
4486
4487         byte_len = mono_array_element_size (class);
4488         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4489                 return FALSE;
4490         byte_len *= len;
4491         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4492                 return FALSE;
4493         byte_len += sizeof (MonoArray);
4494
4495         *res = byte_len;
4496
4497         return TRUE;
4498 }
4499
4500 /**
4501  * mono_array_new_full:
4502  * @domain: domain where the object is created
4503  * @array_class: array class
4504  * @lengths: lengths for each dimension in the array
4505  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4506  *
4507  * This routine creates a new array objects with the given dimensions,
4508  * lower bounds and type.
4509  */
4510 MonoArray*
4511 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4512 {
4513         uintptr_t byte_len, len, bounds_size;
4514         MonoObject *o;
4515         MonoArray *array;
4516         MonoArrayBounds *bounds;
4517         MonoVTable *vtable;
4518         int i;
4519
4520         if (!array_class->inited)
4521                 mono_class_init (array_class);
4522
4523         len = 1;
4524
4525         /* A single dimensional array with a 0 lower bound is the same as an szarray */
4526         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4527                 len = lengths [0];
4528                 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4529                         arith_overflow ();
4530                 bounds_size = 0;
4531         } else {
4532                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4533
4534                 for (i = 0; i < array_class->rank; ++i) {
4535                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4536                                 arith_overflow ();
4537                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4538                                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4539                         len *= lengths [i];
4540                 }
4541         }
4542
4543         if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4544                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4545
4546         if (bounds_size) {
4547                 /* align */
4548                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4549                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4550                 byte_len = (byte_len + 3) & ~3;
4551                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4552                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4553                 byte_len += bounds_size;
4554         }
4555         /* 
4556          * Following three lines almost taken from mono_object_new ():
4557          * they need to be kept in sync.
4558          */
4559         vtable = mono_class_vtable_full (domain, array_class, TRUE);
4560 #ifndef HAVE_SGEN_GC
4561         if (!array_class->has_references) {
4562                 o = mono_object_allocate_ptrfree (byte_len, vtable);
4563 #if NEED_TO_ZERO_PTRFREE
4564                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4565 #endif
4566         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4567                 o = mono_object_allocate_spec (byte_len, vtable);
4568         }else {
4569                 o = mono_object_allocate (byte_len, vtable);
4570         }
4571
4572         array = (MonoArray*)o;
4573         array->max_length = len;
4574
4575         if (bounds_size) {
4576                 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4577                 array->bounds = bounds;
4578         }
4579 #else
4580         if (bounds_size)
4581                 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4582         else
4583                 o = mono_gc_alloc_vector (vtable, byte_len, len);
4584         array = (MonoArray*)o;
4585         mono_stats.new_object_count++;
4586
4587         bounds = array->bounds;
4588 #endif
4589
4590         if (bounds_size) {
4591                 for (i = 0; i < array_class->rank; ++i) {
4592                         bounds [i].length = lengths [i];
4593                         if (lower_bounds)
4594                                 bounds [i].lower_bound = lower_bounds [i];
4595                 }
4596         }
4597
4598         if (G_UNLIKELY (profile_allocs))
4599                 mono_profiler_allocation (o, array_class);
4600
4601         return array;
4602 }
4603
4604 /**
4605  * mono_array_new:
4606  * @domain: domain where the object is created
4607  * @eclass: element class
4608  * @n: number of array elements
4609  *
4610  * This routine creates a new szarray with @n elements of type @eclass.
4611  */
4612 MonoArray *
4613 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4614 {
4615         MonoClass *ac;
4616
4617         MONO_ARCH_SAVE_REGS;
4618
4619         ac = mono_array_class_get (eclass, 1);
4620         g_assert (ac);
4621
4622         return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4623 }
4624
4625 /**
4626  * mono_array_new_specific:
4627  * @vtable: a vtable in the appropriate domain for an initialized class
4628  * @n: number of array elements
4629  *
4630  * This routine is a fast alternative to mono_array_new() for code which
4631  * can be sure about the domain it operates in.
4632  */
4633 MonoArray *
4634 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4635 {
4636         MonoObject *o;
4637         MonoArray *ao;
4638         uintptr_t byte_len;
4639
4640         MONO_ARCH_SAVE_REGS;
4641
4642         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4643                 arith_overflow ();
4644                 return NULL;
4645         }
4646
4647         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4648                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4649                 return NULL;
4650         }
4651 #ifndef HAVE_SGEN_GC
4652         if (!vtable->klass->has_references) {
4653                 o = mono_object_allocate_ptrfree (byte_len, vtable);
4654 #if NEED_TO_ZERO_PTRFREE
4655                 ((MonoArray*)o)->bounds = NULL;
4656                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4657 #endif
4658         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4659                 o = mono_object_allocate_spec (byte_len, vtable);
4660         } else {
4661 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4662                 o = mono_object_allocate (byte_len, vtable);
4663         }
4664
4665         ao = (MonoArray *)o;
4666         ao->max_length = n;
4667 #else
4668         o = mono_gc_alloc_vector (vtable, byte_len, n);
4669         ao = (MonoArray*)o;
4670         mono_stats.new_object_count++;
4671 #endif
4672
4673         if (G_UNLIKELY (profile_allocs))
4674                 mono_profiler_allocation (o, vtable->klass);
4675
4676         return ao;
4677 }
4678
4679 /**
4680  * mono_string_new_utf16:
4681  * @text: a pointer to an utf16 string
4682  * @len: the length of the string
4683  *
4684  * Returns: A newly created string object which contains @text.
4685  */
4686 MonoString *
4687 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4688 {
4689         MonoString *s;
4690         
4691         s = mono_string_new_size (domain, len);
4692         g_assert (s != NULL);
4693
4694         memcpy (mono_string_chars (s), text, len * 2);
4695
4696         return s;
4697 }
4698
4699 /**
4700  * mono_string_new_size:
4701  * @text: a pointer to an utf16 string
4702  * @len: the length of the string
4703  *
4704  * Returns: A newly created string object of @len
4705  */
4706 MonoString *
4707 mono_string_new_size (MonoDomain *domain, gint32 len)
4708 {
4709         MonoString *s;
4710         MonoVTable *vtable;
4711         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4712
4713         /* overflow ? can't fit it, can't allocate it! */
4714         if (len > size)
4715                 mono_gc_out_of_memory (-1);
4716
4717         vtable = mono_class_vtable (domain, mono_defaults.string_class);
4718         g_assert (vtable);
4719
4720 #ifndef HAVE_SGEN_GC
4721         s = mono_object_allocate_ptrfree (size, vtable);
4722
4723         s->length = len;
4724 #else
4725         s = mono_gc_alloc_string (vtable, size, len);
4726 #endif
4727 #if NEED_TO_ZERO_PTRFREE
4728         s->chars [len] = 0;
4729 #endif
4730         if (G_UNLIKELY (profile_allocs))
4731                 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4732
4733         return s;
4734 }
4735
4736 /**
4737  * mono_string_new_len:
4738  * @text: a pointer to an utf8 string
4739  * @length: number of bytes in @text to consider
4740  *
4741  * Returns: A newly created string object which contains @text.
4742  */
4743 MonoString*
4744 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4745 {
4746         GError *error = NULL;
4747         MonoString *o = NULL;
4748         guint16 *ut;
4749         glong items_written;
4750
4751         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4752
4753         if (!error)
4754                 o = mono_string_new_utf16 (domain, ut, items_written);
4755         else 
4756                 g_error_free (error);
4757
4758         g_free (ut);
4759
4760         return o;
4761 }
4762
4763 /**
4764  * mono_string_new:
4765  * @text: a pointer to an utf8 string
4766  *
4767  * Returns: A newly created string object which contains @text.
4768  */
4769 MonoString*
4770 mono_string_new (MonoDomain *domain, const char *text)
4771 {
4772     GError *error = NULL;
4773     MonoString *o = NULL;
4774     guint16 *ut;
4775     glong items_written;
4776     int l;
4777
4778     l = strlen (text);
4779    
4780     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4781
4782     if (!error)
4783         o = mono_string_new_utf16 (domain, ut, items_written);
4784     else
4785         g_error_free (error);
4786
4787     g_free (ut);
4788 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4789 #if 0
4790         gunichar2 *str;
4791         const gchar *end;
4792         int len;
4793         MonoString *o = NULL;
4794
4795         if (!g_utf8_validate (text, -1, &end))
4796                 return NULL;
4797
4798         len = g_utf8_strlen (text, -1);
4799         o = mono_string_new_size (domain, len);
4800         str = mono_string_chars (o);
4801
4802         while (text < end) {
4803                 *str++ = g_utf8_get_char (text);
4804                 text = g_utf8_next_char (text);
4805         }
4806 #endif
4807         return o;
4808 }
4809
4810 /**
4811  * mono_string_new_wrapper:
4812  * @text: pointer to utf8 characters.
4813  *
4814  * Helper function to create a string object from @text in the current domain.
4815  */
4816 MonoString*
4817 mono_string_new_wrapper (const char *text)
4818 {
4819         MonoDomain *domain = mono_domain_get ();
4820
4821         MONO_ARCH_SAVE_REGS;
4822
4823         if (text)
4824                 return mono_string_new (domain, text);
4825
4826         return NULL;
4827 }
4828
4829 /**
4830  * mono_value_box:
4831  * @class: the class of the value
4832  * @value: a pointer to the unboxed data
4833  *
4834  * Returns: A newly created object which contains @value.
4835  */
4836 MonoObject *
4837 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4838 {
4839         MonoObject *res;
4840         int size;
4841         MonoVTable *vtable;
4842
4843         g_assert (class->valuetype);
4844         if (mono_class_is_nullable (class))
4845                 return mono_nullable_box (value, class);
4846
4847         vtable = mono_class_vtable (domain, class);
4848         if (!vtable)
4849                 return NULL;
4850         size = mono_class_instance_size (class);
4851         res = mono_object_new_alloc_specific (vtable);
4852         if (G_UNLIKELY (profile_allocs))
4853                 mono_profiler_allocation (res, class);
4854
4855         size = size - sizeof (MonoObject);
4856
4857 #ifdef HAVE_SGEN_GC
4858         g_assert (size == mono_class_value_size (class, NULL));
4859         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4860 #else
4861 #if NO_UNALIGNED_ACCESS
4862         memcpy ((char *)res + sizeof (MonoObject), value, size);
4863 #else
4864         switch (size) {
4865         case 1:
4866                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4867                 break;
4868         case 2:
4869                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4870                 break;
4871         case 4:
4872                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4873                 break;
4874         case 8:
4875                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4876                 break;
4877         default:
4878                 memcpy ((char *)res + sizeof (MonoObject), value, size);
4879         }
4880 #endif
4881 #endif
4882         if (class->has_finalize)
4883                 mono_object_register_finalizer (res);
4884         return res;
4885 }
4886
4887 /*
4888  * mono_value_copy:
4889  * @dest: destination pointer
4890  * @src: source pointer
4891  * @klass: a valuetype class
4892  *
4893  * Copy a valuetype from @src to @dest. This function must be used
4894  * when @klass contains references fields.
4895  */
4896 void
4897 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4898 {
4899         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4900 }
4901
4902 /*
4903  * mono_value_copy_array:
4904  * @dest: destination array
4905  * @dest_idx: index in the @dest array
4906  * @src: source pointer
4907  * @count: number of items
4908  *
4909  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
4910  * This function must be used when @klass contains references fields.
4911  * Overlap is handled.
4912  */
4913 void
4914 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4915 {
4916         int size = mono_array_element_size (dest->obj.vtable->klass);
4917         char *d = mono_array_addr_with_size (dest, size, dest_idx);
4918         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4919         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4920 }
4921
4922 /**
4923  * mono_object_get_domain:
4924  * @obj: object to query
4925  * 
4926  * Returns: the MonoDomain where the object is hosted
4927  */
4928 MonoDomain*
4929 mono_object_get_domain (MonoObject *obj)
4930 {
4931         return mono_object_domain (obj);
4932 }
4933
4934 /**
4935  * mono_object_get_class:
4936  * @obj: object to query
4937  * 
4938  * Returns: the MonOClass of the object.
4939  */
4940 MonoClass*
4941 mono_object_get_class (MonoObject *obj)
4942 {
4943         return mono_object_class (obj);
4944 }
4945 /**
4946  * mono_object_get_size:
4947  * @o: object to query
4948  * 
4949  * Returns: the size, in bytes, of @o
4950  */
4951 guint
4952 mono_object_get_size (MonoObject* o)
4953 {
4954         MonoClass* klass = mono_object_class (o);
4955         if (klass == mono_defaults.string_class) {
4956                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4957         } else if (o->vtable->rank) {
4958                 MonoArray *array = (MonoArray*)o;
4959                 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4960                 if (array->bounds) {
4961                         size += 3;
4962                         size &= ~3;
4963                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
4964                 }
4965                 return size;
4966         } else {
4967                 return mono_class_instance_size (klass);
4968         }
4969 }
4970
4971 /**
4972  * mono_object_unbox:
4973  * @obj: object to unbox
4974  * 
4975  * Returns: a pointer to the start of the valuetype boxed in this
4976  * object.
4977  *
4978  * This method will assert if the object passed is not a valuetype.
4979  */
4980 gpointer
4981 mono_object_unbox (MonoObject *obj)
4982 {
4983         /* add assert for valuetypes? */
4984         g_assert (obj->vtable->klass->valuetype);
4985         return ((char*)obj) + sizeof (MonoObject);
4986 }
4987
4988 /**
4989  * mono_object_isinst:
4990  * @obj: an object
4991  * @klass: a pointer to a class 
4992  *
4993  * Returns: @obj if @obj is derived from @klass
4994  */
4995 MonoObject *
4996 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4997 {
4998         if (!klass->inited)
4999                 mono_class_init (klass);
5000
5001         if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5002                 return mono_object_isinst_mbyref (obj, klass);
5003
5004         if (!obj)
5005                 return NULL;
5006
5007         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5008 }
5009
5010 MonoObject *
5011 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5012 {
5013         MonoVTable *vt;
5014
5015         if (!obj)
5016                 return NULL;
5017
5018         vt = obj->vtable;
5019         
5020         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5021                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5022                         return obj;
5023                 }
5024
5025                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5026                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5027                         return obj;
5028         } else {
5029                 MonoClass *oklass = vt->klass;
5030                 if ((oklass == mono_defaults.transparent_proxy_class))
5031                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5032         
5033                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5034                         return obj;
5035         }
5036
5037         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5038         {
5039                 MonoDomain *domain = mono_domain_get ();
5040                 MonoObject *res;
5041                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5042                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5043                 MonoMethod *im = NULL;
5044                 gpointer pa [2];
5045
5046                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5047                 im = mono_object_get_virtual_method (rp, im);
5048                 g_assert (im);
5049         
5050                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5051                 pa [1] = obj;
5052
5053                 res = mono_runtime_invoke (im, rp, pa, NULL);
5054         
5055                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5056                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5057                         mono_upgrade_remote_class (domain, obj, klass);
5058                         return obj;
5059                 }
5060         }
5061
5062         return NULL;
5063 }
5064
5065 /**
5066  * mono_object_castclass_mbyref:
5067  * @obj: an object
5068  * @klass: a pointer to a class 
5069  *
5070  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5071  */
5072 MonoObject *
5073 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5074 {
5075         if (!obj) return NULL;
5076         if (mono_object_isinst_mbyref (obj, klass)) return obj;
5077                 
5078         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5079                                                         "System",
5080                                                         "InvalidCastException"));
5081         return NULL;
5082 }
5083
5084 typedef struct {
5085         MonoDomain *orig_domain;
5086         MonoString *ins;
5087         MonoString *res;
5088 } LDStrInfo;
5089
5090 static void
5091 str_lookup (MonoDomain *domain, gpointer user_data)
5092 {
5093         LDStrInfo *info = user_data;
5094         if (info->res || domain == info->orig_domain)
5095                 return;
5096         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5097 }
5098
5099 #ifdef HAVE_SGEN_GC
5100
5101 static MonoString*
5102 mono_string_get_pinned (MonoString *str)
5103 {
5104         int size;
5105         MonoString *news;
5106         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5107         news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5108         memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5109         news->length = mono_string_length (str);
5110         return news;
5111 }
5112
5113 #else
5114 #define mono_string_get_pinned(str) (str)
5115 #endif
5116
5117 static MonoString*
5118 mono_string_is_interned_lookup (MonoString *str, int insert)
5119 {
5120         MonoGHashTable *ldstr_table;
5121         MonoString *res;
5122         MonoDomain *domain;
5123         
5124         domain = ((MonoObject *)str)->vtable->domain;
5125         ldstr_table = domain->ldstr_table;
5126         ldstr_lock ();
5127         if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5128                 ldstr_unlock ();
5129                 return res;
5130         }
5131         if (insert) {
5132                 str = mono_string_get_pinned (str);
5133                 mono_g_hash_table_insert (ldstr_table, str, str);
5134                 ldstr_unlock ();
5135                 return str;
5136         } else {
5137                 LDStrInfo ldstr_info;
5138                 ldstr_info.orig_domain = domain;
5139                 ldstr_info.ins = str;
5140                 ldstr_info.res = NULL;
5141
5142                 mono_domain_foreach (str_lookup, &ldstr_info);
5143                 if (ldstr_info.res) {
5144                         /* 
5145                          * the string was already interned in some other domain:
5146                          * intern it in the current one as well.
5147                          */
5148                         mono_g_hash_table_insert (ldstr_table, str, str);
5149                         ldstr_unlock ();
5150                         return str;
5151                 }
5152         }
5153         ldstr_unlock ();
5154         return NULL;
5155 }
5156
5157 /**
5158  * mono_string_is_interned:
5159  * @o: String to probe
5160  *
5161  * Returns whether the string has been interned.
5162  */
5163 MonoString*
5164 mono_string_is_interned (MonoString *o)
5165 {
5166         return mono_string_is_interned_lookup (o, FALSE);
5167 }
5168
5169 /**
5170  * mono_string_intern:
5171  * @o: String to intern
5172  *
5173  * Interns the string passed.  
5174  * Returns: The interned string.
5175  */
5176 MonoString*
5177 mono_string_intern (MonoString *str)
5178 {
5179         return mono_string_is_interned_lookup (str, TRUE);
5180 }
5181
5182 /**
5183  * mono_ldstr:
5184  * @domain: the domain where the string will be used.
5185  * @image: a metadata context
5186  * @idx: index into the user string table.
5187  * 
5188  * Implementation for the ldstr opcode.
5189  * Returns: a loaded string from the @image/@idx combination.
5190  */
5191 MonoString*
5192 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5193 {
5194         MONO_ARCH_SAVE_REGS;
5195
5196         if (image->dynamic) {
5197                 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5198                 return str;
5199         } else {
5200                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5201                         return NULL; /*FIXME we should probably be raising an exception here*/
5202                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5203         }
5204 }
5205
5206 /**
5207  * mono_ldstr_metadata_sig
5208  * @domain: the domain for the string
5209  * @sig: the signature of a metadata string
5210  *
5211  * Returns: a MonoString for a string stored in the metadata
5212  */
5213 static MonoString*
5214 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5215 {
5216         const char *str = sig;
5217         MonoString *o, *interned;
5218         size_t len2;
5219
5220         len2 = mono_metadata_decode_blob_size (str, &str);
5221         len2 >>= 1;
5222
5223         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5224 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5225         {
5226                 int i;
5227                 guint16 *p2 = (guint16*)mono_string_chars (o);
5228                 for (i = 0; i < len2; ++i) {
5229                         *p2 = GUINT16_FROM_LE (*p2);
5230                         ++p2;
5231                 }
5232         }
5233 #endif
5234         ldstr_lock ();
5235         if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5236                 ldstr_unlock ();
5237                 /* o will get garbage collected */
5238                 return interned;
5239         }
5240
5241         o = mono_string_get_pinned (o);
5242         mono_g_hash_table_insert (domain->ldstr_table, o, o);
5243         ldstr_unlock ();
5244
5245         return o;
5246 }
5247
5248 /**
5249  * mono_string_to_utf8:
5250  * @s: a System.String
5251  *
5252  * Return the UTF8 representation for @s.
5253  * the resulting buffer nedds to be freed with g_free().
5254  *
5255  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5256  */
5257 char *
5258 mono_string_to_utf8 (MonoString *s)
5259 {
5260         MonoError error;
5261         char *result = mono_string_to_utf8_checked (s, &error);
5262         
5263         if (!mono_error_ok (&error))
5264                 mono_error_raise_exception (&error);
5265         return result;
5266 }
5267
5268 char *
5269 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5270 {
5271         long written = 0;
5272         char *as;
5273         GError *gerror = NULL;
5274
5275         mono_error_init (error);
5276
5277         if (s == NULL)
5278                 return NULL;
5279
5280         if (!s->length)
5281                 return g_strdup ("");
5282
5283         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5284         if (gerror) {
5285                 mono_error_set_argument (error, "string", "%s", gerror->message);
5286                 g_error_free (gerror);
5287                 return NULL;
5288         }
5289         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5290         if (s->length > written) {
5291                 /* allocate the total length and copy the part of the string that has been converted */
5292                 char *as2 = g_malloc0 (s->length);
5293                 memcpy (as2, as, written);
5294                 g_free (as);
5295                 as = as2;
5296         }
5297
5298         return as;
5299 }
5300
5301 /**
5302  * mono_string_to_utf16:
5303  * @s: a MonoString
5304  *
5305  * Return an null-terminated array of the utf-16 chars
5306  * contained in @s. The result must be freed with g_free().
5307  * This is a temporary helper until our string implementation
5308  * is reworked to always include the null terminating char.
5309  */
5310 mono_unichar2*
5311 mono_string_to_utf16 (MonoString *s)
5312 {
5313         char *as;
5314
5315         if (s == NULL)
5316                 return NULL;
5317
5318         as = g_malloc ((s->length * 2) + 2);
5319         as [(s->length * 2)] = '\0';
5320         as [(s->length * 2) + 1] = '\0';
5321
5322         if (!s->length) {
5323                 return (gunichar2 *)(as);
5324         }
5325         
5326         memcpy (as, mono_string_chars(s), s->length * 2);
5327         return (gunichar2 *)(as);
5328 }
5329
5330 /**
5331  * mono_string_from_utf16:
5332  * @data: the UTF16 string (LPWSTR) to convert
5333  *
5334  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5335  *
5336  * Returns: a MonoString.
5337  */
5338 MonoString *
5339 mono_string_from_utf16 (gunichar2 *data)
5340 {
5341         MonoDomain *domain = mono_domain_get ();
5342         int len = 0;
5343
5344         if (!data)
5345                 return NULL;
5346
5347         while (data [len]) len++;
5348
5349         return mono_string_new_utf16 (domain, data, len);
5350 }
5351
5352
5353 static char *
5354 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5355 {
5356         char *r;
5357         char *mp_s;
5358         int len;
5359
5360         r = mono_string_to_utf8_checked (s, error);
5361         if (!mono_error_ok (error))
5362                 return NULL;
5363
5364         if (!mp && !image)
5365                 return r;
5366
5367         len = strlen (r) + 1;
5368         if (mp)
5369                 mp_s = mono_mempool_alloc (mp, len);
5370         else
5371                 mp_s = mono_image_alloc (image, len);
5372
5373         memcpy (mp_s, r, len);
5374
5375         g_free (r);
5376
5377         return mp_s;
5378 }
5379
5380 /**
5381  * mono_string_to_utf8_image:
5382  * @s: a System.String
5383  *
5384  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5385  */
5386 char *
5387 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5388 {
5389         return mono_string_to_utf8_internal (NULL, image, s, error);
5390 }
5391
5392 /**
5393  * mono_string_to_utf8_mp:
5394  * @s: a System.String
5395  *
5396  * Same as mono_string_to_utf8, but allocate the string from a mempool.
5397  */
5398 char *
5399 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5400 {
5401         return mono_string_to_utf8_internal (mp, NULL, s, error);
5402 }
5403
5404 static void
5405 default_ex_handler (MonoException *ex)
5406 {
5407         MonoObject *o = (MonoObject*)ex;
5408         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5409         exit (1);
5410 }
5411
5412 static MonoExceptionFunc ex_handler = default_ex_handler;
5413
5414 /**
5415  * mono_install_handler:
5416  * @func: exception handler
5417  *
5418  * This is an internal JIT routine used to install the handler for exceptions
5419  * being throwh.
5420  */
5421 void
5422 mono_install_handler (MonoExceptionFunc func)
5423 {
5424         ex_handler = func? func: default_ex_handler;
5425 }
5426
5427 /**
5428  * mono_raise_exception:
5429  * @ex: exception object
5430  *
5431  * Signal the runtime that the exception @ex has been raised in unmanaged code.
5432  */
5433 void
5434 mono_raise_exception (MonoException *ex) 
5435 {
5436         /*
5437          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5438          * that will cause gcc to omit the function epilog, causing problems when
5439          * the JIT tries to walk the stack, since the return address on the stack
5440          * will point into the next function in the executable, not this one.
5441          */
5442
5443         if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5444                 MonoInternalThread *thread = mono_thread_internal_current ();
5445                 g_assert (ex->object.vtable->domain == mono_domain_get ());
5446                 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5447         }
5448         
5449         ex_handler (ex);
5450 }
5451
5452 /**
5453  * mono_wait_handle_new:
5454  * @domain: Domain where the object will be created
5455  * @handle: Handle for the wait handle
5456  *
5457  * Returns: A new MonoWaitHandle created in the given domain for the given handle
5458  */
5459 MonoWaitHandle *
5460 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5461 {
5462         MonoWaitHandle *res;
5463         gpointer params [1];
5464         static MonoMethod *handle_set;
5465
5466         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5467
5468         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
5469         if (!handle_set)
5470                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5471
5472         params [0] = &handle;
5473         mono_runtime_invoke (handle_set, res, params, NULL);
5474
5475         return res;
5476 }
5477
5478 HANDLE
5479 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5480 {
5481         static MonoClassField *f_os_handle;
5482         static MonoClassField *f_safe_handle;
5483
5484         if (!f_os_handle && !f_safe_handle) {
5485                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5486                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5487         }
5488
5489         if (f_os_handle) {
5490                 HANDLE retval;
5491                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5492                 return retval;
5493         } else {
5494                 MonoSafeHandle *sh;
5495                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5496                 return sh->handle;
5497         }
5498 }
5499
5500
5501 static MonoObject*
5502 mono_runtime_capture_context (MonoDomain *domain)
5503 {
5504         RuntimeInvokeFunction runtime_invoke;
5505
5506         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5507                 MonoMethod *method = mono_get_context_capture_method ();
5508                 MonoMethod *wrapper;
5509                 if (!method)
5510                         return NULL;
5511                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5512                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5513                 domain->capture_context_method = mono_compile_method (method);
5514         }
5515
5516         runtime_invoke = domain->capture_context_runtime_invoke;
5517
5518         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5519 }
5520 /**
5521  * mono_async_result_new:
5522  * @domain:domain where the object will be created.
5523  * @handle: wait handle.
5524  * @state: state to pass to AsyncResult
5525  * @data: C closure data.
5526  *
5527  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5528  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5529  *
5530  */
5531 MonoAsyncResult *
5532 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5533 {
5534         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5535         MonoObject *context = mono_runtime_capture_context (domain);
5536         /* we must capture the execution context from the original thread */
5537         if (context) {
5538                 MONO_OBJECT_SETREF (res, execution_context, context);
5539                 /* note: result may be null if the flow is suppressed */
5540         }
5541
5542         res->data = data;
5543         MONO_OBJECT_SETREF (res, object_data, object_data);
5544         MONO_OBJECT_SETREF (res, async_state, state);
5545         if (handle != NULL)
5546                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5547
5548         res->sync_completed = FALSE;
5549         res->completed = FALSE;
5550
5551         return res;
5552 }
5553
5554 void
5555 mono_message_init (MonoDomain *domain,
5556                    MonoMethodMessage *this, 
5557                    MonoReflectionMethod *method,
5558                    MonoArray *out_args)
5559 {
5560         static MonoClass *object_array_klass;
5561         static MonoClass *byte_array_klass;
5562         static MonoClass *string_array_klass;
5563         MonoMethodSignature *sig = mono_method_signature (method->method);
5564         MonoString *name;
5565         int i, j;
5566         char **names;
5567         guint8 arg_type;
5568
5569         if (!object_array_klass) {
5570                 MonoClass *klass;
5571
5572                 klass = mono_array_class_get (mono_defaults.object_class, 1);
5573                 g_assert (klass);
5574
5575                 mono_memory_barrier ();
5576                 object_array_klass = klass;
5577
5578                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5579                 g_assert (klass);
5580
5581                 mono_memory_barrier ();
5582                 byte_array_klass = klass;
5583
5584                 klass = mono_array_class_get (mono_defaults.string_class, 1);
5585                 g_assert (klass);
5586
5587                 mono_memory_barrier ();
5588                 string_array_klass = klass;
5589         }
5590
5591         MONO_OBJECT_SETREF (this, method, method);
5592
5593         MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5594         MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5595         this->async_result = NULL;
5596         this->call_type = CallType_Sync;
5597
5598         names = g_new (char *, sig->param_count);
5599         mono_method_get_param_names (method->method, (const char **) names);
5600         MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5601         
5602         for (i = 0; i < sig->param_count; i++) {
5603                 name = mono_string_new (domain, names [i]);
5604                 mono_array_setref (this->names, i, name);       
5605         }
5606
5607         g_free (names);
5608         for (i = 0, j = 0; i < sig->param_count; i++) {
5609                 if (sig->params [i]->byref) {
5610                         if (out_args) {
5611                                 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5612                                 mono_array_setref (this->args, i, arg);
5613                                 j++;
5614                         }
5615                         arg_type = 2;
5616                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5617                                 arg_type |= 1;
5618                 } else {
5619                         arg_type = 1;
5620                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5621                                 arg_type |= 4;
5622                 }
5623                 mono_array_set (this->arg_types, guint8, i, arg_type);
5624         }
5625 }
5626
5627 /**
5628  * mono_remoting_invoke:
5629  * @real_proxy: pointer to a RealProxy object
5630  * @msg: The MonoMethodMessage to execute
5631  * @exc: used to store exceptions
5632  * @out_args: used to store output arguments
5633  *
5634  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5635  * IMessage interface and it is not trivial to extract results from there. So
5636  * we call an helper method PrivateInvoke instead of calling
5637  * RealProxy::Invoke() directly.
5638  *
5639  * Returns: the result object.
5640  */
5641 MonoObject *
5642 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
5643                       MonoObject **exc, MonoArray **out_args)
5644 {
5645         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5646         gpointer pa [4];
5647
5648         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5649
5650         if (!im) {
5651                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5652                 g_assert (im);
5653                 real_proxy->vtable->domain->private_invoke_method = im;
5654         }
5655
5656         pa [0] = real_proxy;
5657         pa [1] = msg;
5658         pa [2] = exc;
5659         pa [3] = out_args;
5660
5661         return mono_runtime_invoke (im, NULL, pa, exc);
5662 }
5663
5664 MonoObject *
5665 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
5666                      MonoObject **exc, MonoArray **out_args) 
5667 {
5668         static MonoClass *object_array_klass;
5669         MonoDomain *domain; 
5670         MonoMethod *method;
5671         MonoMethodSignature *sig;
5672         MonoObject *ret;
5673         int i, j, outarg_count = 0;
5674
5675         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5676
5677                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5678                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5679                         target = tp->rp->unwrapped_server;
5680                 } else {
5681                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5682                 }
5683         }
5684
5685         domain = mono_domain_get (); 
5686         method = msg->method->method;
5687         sig = mono_method_signature (method);
5688
5689         for (i = 0; i < sig->param_count; i++) {
5690                 if (sig->params [i]->byref) 
5691                         outarg_count++;
5692         }
5693
5694         if (!object_array_klass) {
5695                 MonoClass *klass;
5696
5697                 klass = mono_array_class_get (mono_defaults.object_class, 1);
5698                 g_assert (klass);
5699
5700                 mono_memory_barrier ();
5701                 object_array_klass = klass;
5702         }
5703
5704         /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5705         *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5706         *exc = NULL;
5707
5708         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5709
5710         for (i = 0, j = 0; i < sig->param_count; i++) {
5711                 if (sig->params [i]->byref) {
5712                         MonoObject* arg;
5713                         arg = mono_array_get (msg->args, gpointer, i);
5714                         mono_array_setref (*out_args, j, arg);
5715                         j++;
5716                 }
5717         }
5718
5719         return ret;
5720 }
5721
5722 /**
5723  * mono_print_unhandled_exception:
5724  * @exc: The exception
5725  *
5726  * Prints the unhandled exception.
5727  */
5728 void
5729 mono_print_unhandled_exception (MonoObject *exc)
5730 {
5731         MonoError error;
5732         char *message = (char *) "";
5733         MonoString *str; 
5734         MonoMethod *method;
5735         MonoClass *klass;
5736         gboolean free_message = FALSE;
5737
5738         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5739                 klass = exc->vtable->klass;
5740                 method = NULL;
5741                 while (klass && method == NULL) {
5742                         method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5743                         if (method == NULL)
5744                                 klass = klass->parent;
5745                 }
5746
5747                 g_assert (method);
5748
5749                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5750                 if (str) {
5751                         message = mono_string_to_utf8_checked (str, &error);
5752                         if (!mono_error_ok (&error)) {
5753                                 mono_error_cleanup (&error);
5754                                 message = (char *)"";
5755                         } else {
5756                                 free_message = TRUE;
5757                         }
5758                 }
5759         }                               
5760
5761         /*
5762          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
5763          *         exc->vtable->klass->name, message);
5764          */
5765         g_printerr ("\nUnhandled Exception: %s\n", message);
5766         
5767         if (free_message)
5768                 g_free (message);
5769 }
5770
5771 /**
5772  * mono_delegate_ctor:
5773  * @this: pointer to an uninitialized delegate object
5774  * @target: target object
5775  * @addr: pointer to native code
5776  * @method: method
5777  *
5778  * Initialize a delegate and sets a specific method, not the one
5779  * associated with addr.  This is useful when sharing generic code.
5780  * In that case addr will most probably not be associated with the
5781  * correct instantiation of the method.
5782  */
5783 void
5784 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5785 {
5786         MonoDelegate *delegate = (MonoDelegate *)this;
5787         MonoClass *class;
5788
5789         g_assert (this);
5790         g_assert (addr);
5791
5792         if (method)
5793                 delegate->method = method;
5794
5795         class = this->vtable->klass;
5796         mono_stats.delegate_creations++;
5797
5798         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5799                 g_assert (method);
5800                 method = mono_marshal_get_remoting_invoke (method);
5801                 delegate->method_ptr = mono_compile_method (method);
5802                 MONO_OBJECT_SETREF (delegate, target, target);
5803         } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5804                 method = mono_marshal_get_unbox_wrapper (method);
5805                 delegate->method_ptr = mono_compile_method (method);
5806                 MONO_OBJECT_SETREF (delegate, target, target);
5807         } else {
5808                 delegate->method_ptr = addr;
5809                 MONO_OBJECT_SETREF (delegate, target, target);
5810         }
5811
5812         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5813 }
5814
5815 /**
5816  * mono_delegate_ctor:
5817  * @this: pointer to an uninitialized delegate object
5818  * @target: target object
5819  * @addr: pointer to native code
5820  *
5821  * This is used to initialize a delegate.
5822  */
5823 void
5824 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5825 {
5826         MonoDomain *domain = mono_domain_get ();
5827         MonoJitInfo *ji;
5828         MonoMethod *method = NULL;
5829
5830         g_assert (addr);
5831
5832         if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5833                 method = ji->method;
5834                 g_assert (!method->klass->generic_container);
5835         }
5836
5837         mono_delegate_ctor_with_method (this, target, addr, method);
5838 }
5839
5840 /**
5841  * mono_method_call_message_new:
5842  * @method: method to encapsulate
5843  * @params: parameters to the method
5844  * @invoke: optional, delegate invoke.
5845  * @cb: async callback delegate.
5846  * @state: state passed to the async callback.
5847  *
5848  * Translates arguments pointers into a MonoMethodMessage.
5849  */
5850 MonoMethodMessage *
5851 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
5852                               MonoDelegate **cb, MonoObject **state)
5853 {
5854         MonoDomain *domain = mono_domain_get ();
5855         MonoMethodSignature *sig = mono_method_signature (method);
5856         MonoMethodMessage *msg;
5857         int i, count, type;
5858
5859         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
5860         
5861         if (invoke) {
5862                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5863                 count =  sig->param_count - 2;
5864         } else {
5865                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5866                 count =  sig->param_count;
5867         }
5868
5869         for (i = 0; i < count; i++) {
5870                 gpointer vpos;
5871                 MonoClass *class;
5872                 MonoObject *arg;
5873
5874                 if (sig->params [i]->byref)
5875                         vpos = *((gpointer *)params [i]);
5876                 else 
5877                         vpos = params [i];
5878
5879                 type = sig->params [i]->type;
5880                 class = mono_class_from_mono_type (sig->params [i]);
5881
5882                 if (class->valuetype)
5883                         arg = mono_value_box (domain, class, vpos);
5884                 else 
5885                         arg = *((MonoObject **)vpos);
5886                       
5887                 mono_array_setref (msg->args, i, arg);
5888         }
5889
5890         if (cb != NULL && state != NULL) {
5891                 *cb = *((MonoDelegate **)params [i]);
5892                 i++;
5893                 *state = *((MonoObject **)params [i]);
5894         }
5895
5896         return msg;
5897 }
5898
5899 /**
5900  * mono_method_return_message_restore:
5901  *
5902  * Restore results from message based processing back to arguments pointers
5903  */
5904 void
5905 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5906 {
5907         MonoMethodSignature *sig = mono_method_signature (method);
5908         int i, j, type, size, out_len;
5909         
5910         if (out_args == NULL)
5911                 return;
5912         out_len = mono_array_length (out_args);
5913         if (out_len == 0)
5914                 return;
5915
5916         for (i = 0, j = 0; i < sig->param_count; i++) {
5917                 MonoType *pt = sig->params [i];
5918
5919                 if (pt->byref) {
5920                         char *arg;
5921                         if (j >= out_len)
5922                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5923
5924                         arg = mono_array_get (out_args, gpointer, j);
5925                         type = pt->type;
5926
5927                         g_assert (type != MONO_TYPE_VOID);
5928
5929                         if (MONO_TYPE_IS_REFERENCE (pt)) {
5930                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5931                         } else {
5932                                 if (arg) {
5933                                         MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5934                                         size = mono_class_value_size (class, NULL);
5935                                         if (class->has_references)
5936                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5937                                         else
5938                                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5939                                 } else {
5940                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5941                                         memset (*((gpointer *)params [i]), 0, size);
5942                                 }
5943                         }
5944
5945                         j++;
5946                 }
5947         }
5948 }
5949
5950 /**
5951  * mono_load_remote_field:
5952  * @this: pointer to an object
5953  * @klass: klass of the object containing @field
5954  * @field: the field to load
5955  * @res: a storage to store the result
5956  *
5957  * This method is called by the runtime on attempts to load fields of
5958  * transparent proxy objects. @this points to such TP, @klass is the class of
5959  * the object containing @field. @res is a storage location which can be
5960  * used to store the result.
5961  *
5962  * Returns: an address pointing to the value of field.
5963  */
5964 gpointer
5965 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5966 {
5967         static MonoMethod *getter = NULL;
5968         MonoDomain *domain = mono_domain_get ();
5969         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5970         MonoClass *field_class;
5971         MonoMethodMessage *msg;
5972         MonoArray *out_args;
5973         MonoObject *exc;
5974         char* full_name;
5975
5976         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5977         g_assert (res != NULL);
5978
5979         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5980                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5981                 return res;
5982         }
5983         
5984         if (!getter) {
5985                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5986                 g_assert (getter);
5987         }
5988         
5989         field_class = mono_class_from_mono_type (field->type);
5990
5991         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5992         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5993         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5994
5995         full_name = mono_type_get_full_name (klass);
5996         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5997         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5998         g_free (full_name);
5999
6000         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6001
6002         if (exc) mono_raise_exception ((MonoException *)exc);
6003
6004         if (mono_array_length (out_args) == 0)
6005                 return NULL;
6006
6007         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6008
6009         if (field_class->valuetype) {
6010                 return ((char *)*res) + sizeof (MonoObject);
6011         } else
6012                 return res;
6013 }
6014
6015 /**
6016  * mono_load_remote_field_new:
6017  * @this: 
6018  * @klass: 
6019  * @field:
6020  *
6021  * Missing documentation.
6022  */
6023 MonoObject *
6024 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6025 {
6026         static MonoMethod *getter = NULL;
6027         MonoDomain *domain = mono_domain_get ();
6028         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6029         MonoClass *field_class;
6030         MonoMethodMessage *msg;
6031         MonoArray *out_args;
6032         MonoObject *exc, *res;
6033         char* full_name;
6034
6035         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6036
6037         field_class = mono_class_from_mono_type (field->type);
6038
6039         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6040                 gpointer val;
6041                 if (field_class->valuetype) {
6042                         res = mono_object_new (domain, field_class);
6043                         val = ((gchar *) res) + sizeof (MonoObject);
6044                 } else {
6045                         val = &res;
6046                 }
6047                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6048                 return res;
6049         }
6050
6051         if (!getter) {
6052                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6053                 g_assert (getter);
6054         }
6055         
6056         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6057         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6058
6059         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6060
6061         full_name = mono_type_get_full_name (klass);
6062         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6063         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6064         g_free (full_name);
6065
6066         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6067
6068         if (exc) mono_raise_exception ((MonoException *)exc);
6069
6070         if (mono_array_length (out_args) == 0)
6071                 res = NULL;
6072         else
6073                 res = mono_array_get (out_args, MonoObject *, 0);
6074
6075         return res;
6076 }
6077
6078 /**
6079  * mono_store_remote_field:
6080  * @this: pointer to an object
6081  * @klass: klass of the object containing @field
6082  * @field: the field to load
6083  * @val: the value/object to store
6084  *
6085  * This method is called by the runtime on attempts to store fields of
6086  * transparent proxy objects. @this points to such TP, @klass is the class of
6087  * the object containing @field. @val is the new value to store in @field.
6088  */
6089 void
6090 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6091 {
6092         static MonoMethod *setter = NULL;
6093         MonoDomain *domain = mono_domain_get ();
6094         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6095         MonoClass *field_class;
6096         MonoMethodMessage *msg;
6097         MonoArray *out_args;
6098         MonoObject *exc;
6099         MonoObject *arg;
6100         char* full_name;
6101
6102         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6103
6104         field_class = mono_class_from_mono_type (field->type);
6105
6106         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6107                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6108                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6109                 return;
6110         }
6111
6112         if (!setter) {
6113                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6114                 g_assert (setter);
6115         }
6116
6117         if (field_class->valuetype)
6118                 arg = mono_value_box (domain, field_class, val);
6119         else 
6120                 arg = *((MonoObject **)val);
6121                 
6122
6123         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6124         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6125
6126         full_name = mono_type_get_full_name (klass);
6127         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6128         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6129         mono_array_setref (msg->args, 2, arg);
6130         g_free (full_name);
6131
6132         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6133
6134         if (exc) mono_raise_exception ((MonoException *)exc);
6135 }
6136
6137 /**
6138  * mono_store_remote_field_new:
6139  * @this:
6140  * @klass:
6141  * @field:
6142  * @arg:
6143  *
6144  * Missing documentation
6145  */
6146 void
6147 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6148 {
6149         static MonoMethod *setter = NULL;
6150         MonoDomain *domain = mono_domain_get ();
6151         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6152         MonoClass *field_class;
6153         MonoMethodMessage *msg;
6154         MonoArray *out_args;
6155         MonoObject *exc;
6156         char* full_name;
6157
6158         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6159
6160         field_class = mono_class_from_mono_type (field->type);
6161
6162         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6163                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6164                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6165                 return;
6166         }
6167
6168         if (!setter) {
6169                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6170                 g_assert (setter);
6171         }
6172
6173         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6174         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6175
6176         full_name = mono_type_get_full_name (klass);
6177         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6178         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6179         mono_array_setref (msg->args, 2, arg);
6180         g_free (full_name);
6181
6182         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6183
6184         if (exc) mono_raise_exception ((MonoException *)exc);
6185 }
6186
6187 /*
6188  * mono_create_ftnptr:
6189  *
6190  *   Given a function address, create a function descriptor for it.
6191  * This is only needed on some platforms.
6192  */
6193 gpointer
6194 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6195 {
6196         return callbacks.create_ftnptr (domain, addr);
6197 }
6198
6199 /*
6200  * mono_get_addr_from_ftnptr:
6201  *
6202  *   Given a pointer to a function descriptor, return the function address.
6203  * This is only needed on some platforms.
6204  */
6205 gpointer
6206 mono_get_addr_from_ftnptr (gpointer descr)
6207 {
6208         return callbacks.get_addr_from_ftnptr (descr);
6209 }       
6210
6211 /**
6212  * mono_string_chars:
6213  * @s: a MonoString
6214  *
6215  * Returns a pointer to the UCS16 characters stored in the MonoString
6216  */
6217 gunichar2 *
6218 mono_string_chars (MonoString *s)
6219 {
6220         return s->chars;
6221 }
6222
6223 /**
6224  * mono_string_length:
6225  * @s: MonoString
6226  *
6227  * Returns the lenght in characters of the string
6228  */
6229 int
6230 mono_string_length (MonoString *s)
6231 {
6232         return s->length;
6233 }
6234
6235 /**
6236  * mono_array_length:
6237  * @array: a MonoArray*
6238  *
6239  * Returns the total number of elements in the array. This works for
6240  * both vectors and multidimensional arrays.
6241  */
6242 uintptr_t
6243 mono_array_length (MonoArray *array)
6244 {
6245         return array->max_length;
6246 }
6247
6248 /**
6249  * mono_array_addr_with_size:
6250  * @array: a MonoArray*
6251  * @size: size of the array elements
6252  * @idx: index into the array
6253  *
6254  * Returns the address of the @idx element in the array.
6255  */
6256 char*
6257 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6258 {
6259         return ((char*)(array)->vector) + size * idx;
6260 }
6261