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