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