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