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