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