Update a comment.
[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 (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2081                 /* This is unregistered in
2082                    unregister_vtable_reflection_type() in
2083                    domain.c. */
2084                 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2085         if (class->contextbound)
2086                 vt->remote = 1;
2087         else
2088                 vt->remote = 0;
2089
2090         return vt;
2091 }
2092
2093 /**
2094  * mono_class_proxy_vtable:
2095  * @domain: the application domain
2096  * @remove_class: the remote class
2097  *
2098  * Creates a vtable for transparent proxies. It is basically
2099  * a copy of the real vtable of the class wrapped in @remote_class,
2100  * but all function pointers invoke the remoting functions, and
2101  * vtable->klass points to the transparent proxy class, and not to @class.
2102  */
2103 static MonoVTable *
2104 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2105 {
2106         MonoError error;
2107         MonoVTable *vt, *pvt;
2108         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2109         MonoClass *k;
2110         GSList *extra_interfaces = NULL;
2111         MonoClass *class = remote_class->proxy_class;
2112         gpointer *interface_offsets;
2113         uint8_t *bitmap;
2114         int bsize;
2115         
2116 #ifdef COMPRESSED_INTERFACE_BITMAP
2117         int bcsize;
2118 #endif
2119
2120         vt = mono_class_vtable (domain, class);
2121         g_assert (vt); /*FIXME property handle failure*/
2122         max_interface_id = vt->max_interface_id;
2123         
2124         /* Calculate vtable space for extra interfaces */
2125         for (j = 0; j < remote_class->interface_count; j++) {
2126                 MonoClass* iclass = remote_class->interfaces[j];
2127                 GPtrArray *ifaces;
2128                 int method_count;
2129
2130                 /*FIXME test for interfaces with variant generic arguments*/
2131                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2132                         continue;       /* interface implemented by the class */
2133                 if (g_slist_find (extra_interfaces, iclass))
2134                         continue;
2135                         
2136                 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2137                 
2138                 method_count = mono_class_num_methods (iclass);
2139         
2140                 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2141                 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2142                 if (ifaces) {
2143                         for (i = 0; i < ifaces->len; ++i) {
2144                                 MonoClass *ic = g_ptr_array_index (ifaces, i);
2145                                 /*FIXME test for interfaces with variant generic arguments*/
2146                                 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2147                                         continue;       /* interface implemented by the class */
2148                                 if (g_slist_find (extra_interfaces, ic))
2149                                         continue;
2150                                 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2151                                 method_count += mono_class_num_methods (ic);
2152                         }
2153                         g_ptr_array_free (ifaces, TRUE);
2154                 }
2155
2156                 extra_interface_vtsize += method_count * sizeof (gpointer);
2157                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2158         }
2159
2160         if (ARCH_USE_IMT) {
2161                 mono_stats.imt_number_of_tables++;
2162                 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2163                 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2164                         MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2165         } else {
2166                 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2167                         MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2168         }
2169
2170         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2171
2172         interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2173         if (ARCH_USE_IMT)
2174                 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2175         else
2176                 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2177         memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2178
2179         pvt->klass = mono_defaults.transparent_proxy_class;
2180         /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2181         pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2182
2183         /* initialize vtable */
2184         mono_class_setup_vtable (class);
2185         for (i = 0; i < class->vtable_size; ++i) {
2186                 MonoMethod *cm;
2187                     
2188                 if ((cm = class->vtable [i]))
2189                         pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2190                 else
2191                         pvt->vtable [i] = NULL;
2192         }
2193
2194         if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2195                 /* create trampolines for abstract methods */
2196                 for (k = class; k; k = k->parent) {
2197                         MonoMethod* m;
2198                         gpointer iter = NULL;
2199                         while ((m = mono_class_get_methods (k, &iter)))
2200                                 if (!pvt->vtable [m->slot])
2201                                         pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2202                 }
2203         }
2204
2205         pvt->max_interface_id = max_interface_id;
2206         bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2207 #ifdef COMPRESSED_INTERFACE_BITMAP
2208         bitmap = g_malloc0 (bsize);
2209 #else
2210         bitmap = mono_domain_alloc0 (domain, bsize);
2211 #endif
2212
2213         if (! ARCH_USE_IMT) {
2214                 /* initialize interface offsets */
2215                 for (i = 0; i < class->interface_offsets_count; ++i) {
2216                         int interface_id = class->interfaces_packed [i]->interface_id;
2217                         int slot = class->interface_offsets_packed [i];
2218                         interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2219                 }
2220         }
2221         for (i = 0; i < class->interface_offsets_count; ++i) {
2222                 int interface_id = class->interfaces_packed [i]->interface_id;
2223                 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2224         }
2225
2226         if (extra_interfaces) {
2227                 int slot = class->vtable_size;
2228                 MonoClass* interf;
2229                 gpointer iter;
2230                 MonoMethod* cm;
2231                 GSList *list_item;
2232
2233                 /* Create trampolines for the methods of the interfaces */
2234                 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2235                         interf = list_item->data;
2236                         
2237                         if (! ARCH_USE_IMT) {
2238                                 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2239                         }
2240                         bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2241
2242                         iter = NULL;
2243                         j = 0;
2244                         while ((cm = mono_class_get_methods (interf, &iter)))
2245                                 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2246                         
2247                         slot += mono_class_num_methods (interf);
2248                 }
2249                 if (! ARCH_USE_IMT) {
2250                         g_slist_free (extra_interfaces);
2251                 }
2252         }
2253
2254         if (ARCH_USE_IMT) {
2255                 /* Now that the vtable is full, we can actually fill up the IMT */
2256                 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2257                 if (extra_interfaces) {
2258                         g_slist_free (extra_interfaces);
2259                 }
2260         }
2261
2262 #ifdef COMPRESSED_INTERFACE_BITMAP
2263         bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2264         pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2265         mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2266         g_free (bitmap);
2267 #else
2268         pvt->interface_bitmap = bitmap;
2269 #endif
2270         return pvt;
2271 }
2272
2273 /**
2274  * mono_class_field_is_special_static:
2275  *
2276  *   Returns whether @field is a thread/context static field.
2277  */
2278 gboolean
2279 mono_class_field_is_special_static (MonoClassField *field)
2280 {
2281         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2282                 return FALSE;
2283         if (mono_field_is_deleted (field))
2284                 return FALSE;
2285         if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2286                 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2287                         return TRUE;
2288         }
2289         return FALSE;
2290 }
2291
2292 /**
2293  * mono_class_has_special_static_fields:
2294  * 
2295  *   Returns whenever @klass has any thread/context static fields.
2296  */
2297 gboolean
2298 mono_class_has_special_static_fields (MonoClass *klass)
2299 {
2300         MonoClassField *field;
2301         gpointer iter;
2302
2303         iter = NULL;
2304         while ((field = mono_class_get_fields (klass, &iter))) {
2305                 g_assert (field->parent == klass);
2306                 if (mono_class_field_is_special_static (field))
2307                         return TRUE;
2308         }
2309
2310         return FALSE;
2311 }
2312
2313 /**
2314  * create_remote_class_key:
2315  * Creates an array of pointers that can be used as a hash key for a remote class.
2316  * The first element of the array is the number of pointers.
2317  */
2318 static gpointer*
2319 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2320 {
2321         gpointer *key;
2322         int i, j;
2323         
2324         if (remote_class == NULL) {
2325                 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2326                         key = g_malloc (sizeof(gpointer) * 3);
2327                         key [0] = GINT_TO_POINTER (2);
2328                         key [1] = mono_defaults.marshalbyrefobject_class;
2329                         key [2] = extra_class;
2330                 } else {
2331                         key = g_malloc (sizeof(gpointer) * 2);
2332                         key [0] = GINT_TO_POINTER (1);
2333                         key [1] = extra_class;
2334                 }
2335         } else {
2336                 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2337                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2338                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2339                         key [1] = remote_class->proxy_class;
2340
2341                         // Keep the list of interfaces sorted
2342                         for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2343                                 if (extra_class && remote_class->interfaces [i] > extra_class) {
2344                                         key [j++] = extra_class;
2345                                         extra_class = NULL;
2346                                 }
2347                                 key [j] = remote_class->interfaces [i];
2348                         }
2349                         if (extra_class)
2350                                 key [j] = extra_class;
2351                 } else {
2352                         // Replace the old class. The interface list is the same
2353                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2354                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2355                         key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2356                         for (i = 0; i < remote_class->interface_count; i++)
2357                                 key [2 + i] = remote_class->interfaces [i];
2358                 }
2359         }
2360         
2361         return key;
2362 }
2363
2364 /**
2365  * copy_remote_class_key:
2366  *
2367  *   Make a copy of KEY in the domain and return the copy.
2368  */
2369 static gpointer*
2370 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2371 {
2372         int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2373         gpointer *mp_key = mono_domain_alloc (domain, key_size);
2374
2375         memcpy (mp_key, key, key_size);
2376
2377         return mp_key;
2378 }
2379
2380 /**
2381  * mono_remote_class:
2382  * @domain: the application domain
2383  * @class_name: name of the remote class
2384  *
2385  * Creates and initializes a MonoRemoteClass object for a remote type. 
2386  *
2387  * Can raise an exception on failure. 
2388  */
2389 MonoRemoteClass*
2390 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2391 {
2392         MonoError error;
2393         MonoRemoteClass *rc;
2394         gpointer* key, *mp_key;
2395         char *name;
2396         
2397         key = create_remote_class_key (NULL, proxy_class);
2398         
2399         mono_domain_lock (domain);
2400         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2401
2402         if (rc) {
2403                 g_free (key);
2404                 mono_domain_unlock (domain);
2405                 return rc;
2406         }
2407
2408         name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2409         if (!mono_error_ok (&error)) {
2410                 g_free (key);
2411                 mono_domain_unlock (domain);
2412                 mono_error_raise_exception (&error);
2413         }
2414
2415         mp_key = copy_remote_class_key (domain, key);
2416         g_free (key);
2417         key = mp_key;
2418
2419         if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2420                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2421                 rc->interface_count = 1;
2422                 rc->interfaces [0] = proxy_class;
2423                 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2424         } else {
2425                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2426                 rc->interface_count = 0;
2427                 rc->proxy_class = proxy_class;
2428         }
2429         
2430         rc->default_vtable = NULL;
2431         rc->xdomain_vtable = NULL;
2432         rc->proxy_class_name = name;
2433         mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2434
2435         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2436
2437         mono_domain_unlock (domain);
2438         return rc;
2439 }
2440
2441 /**
2442  * clone_remote_class:
2443  * Creates a copy of the remote_class, adding the provided class or interface
2444  */
2445 static MonoRemoteClass*
2446 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2447 {
2448         MonoRemoteClass *rc;
2449         gpointer* key, *mp_key;
2450         
2451         key = create_remote_class_key (remote_class, extra_class);
2452         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2453         if (rc != NULL) {
2454                 g_free (key);
2455                 return rc;
2456         }
2457
2458         mp_key = copy_remote_class_key (domain, key);
2459         g_free (key);
2460         key = mp_key;
2461
2462         if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2463                 int i,j;
2464                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2465                 rc->proxy_class = remote_class->proxy_class;
2466                 rc->interface_count = remote_class->interface_count + 1;
2467                 
2468                 // Keep the list of interfaces sorted, since the hash key of
2469                 // the remote class depends on this
2470                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2471                         if (remote_class->interfaces [i] > extra_class && i == j)
2472                                 rc->interfaces [j++] = extra_class;
2473                         rc->interfaces [j] = remote_class->interfaces [i];
2474                 }
2475                 if (i == j)
2476                         rc->interfaces [j] = extra_class;
2477         } else {
2478                 // Replace the old class. The interface array is the same
2479                 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2480                 rc->proxy_class = extra_class;
2481                 rc->interface_count = remote_class->interface_count;
2482                 if (rc->interface_count > 0)
2483                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2484         }
2485         
2486         rc->default_vtable = NULL;
2487         rc->xdomain_vtable = NULL;
2488         rc->proxy_class_name = remote_class->proxy_class_name;
2489
2490         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2491
2492         return rc;
2493 }
2494
2495 gpointer
2496 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2497 {
2498         mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2499         mono_domain_lock (domain);
2500         if (rp->target_domain_id != -1) {
2501                 if (remote_class->xdomain_vtable == NULL)
2502                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2503                 mono_domain_unlock (domain);
2504                 mono_loader_unlock ();
2505                 return remote_class->xdomain_vtable;
2506         }
2507         if (remote_class->default_vtable == NULL) {
2508                 MonoType *type;
2509                 MonoClass *klass;
2510                 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2511                 klass = mono_class_from_mono_type (type);
2512                 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2513                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2514                 else
2515                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2516         }
2517         
2518         mono_domain_unlock (domain);
2519         mono_loader_unlock ();
2520         return remote_class->default_vtable;
2521 }
2522
2523 /**
2524  * mono_upgrade_remote_class:
2525  * @domain: the application domain
2526  * @tproxy: the proxy whose remote class has to be upgraded.
2527  * @klass: class to which the remote class can be casted.
2528  *
2529  * Updates the vtable of the remote class by adding the necessary method slots
2530  * and interface offsets so it can be safely casted to klass. klass can be a
2531  * class or an interface.
2532  */
2533 void
2534 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2535 {
2536         MonoTransparentProxy *tproxy;
2537         MonoRemoteClass *remote_class;
2538         gboolean redo_vtable;
2539
2540         mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2541         mono_domain_lock (domain);
2542
2543         tproxy = (MonoTransparentProxy*) proxy_object;
2544         remote_class = tproxy->remote_class;
2545         
2546         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2547                 int i;
2548                 redo_vtable = TRUE;
2549                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2550                         if (remote_class->interfaces [i] == klass)
2551                                 redo_vtable = FALSE;
2552         }
2553         else {
2554                 redo_vtable = (remote_class->proxy_class != klass);
2555         }
2556
2557         if (redo_vtable) {
2558                 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2559                 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2560         }
2561         
2562         mono_domain_unlock (domain);
2563         mono_loader_unlock ();
2564 }
2565
2566
2567 /**
2568  * mono_object_get_virtual_method:
2569  * @obj: object to operate on.
2570  * @method: method 
2571  *
2572  * Retrieves the MonoMethod that would be called on obj if obj is passed as
2573  * the instance of a callvirt of method.
2574  */
2575 MonoMethod*
2576 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2577 {
2578         MonoClass *klass;
2579         MonoMethod **vtable;
2580         gboolean is_proxy;
2581         MonoMethod *res = NULL;
2582
2583         klass = mono_object_class (obj);
2584         if (klass == mono_defaults.transparent_proxy_class) {
2585                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2586                 is_proxy = TRUE;
2587         } else {
2588                 is_proxy = FALSE;
2589         }
2590
2591         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2592                         return method;
2593
2594         mono_class_setup_vtable (klass);
2595         vtable = klass->vtable;
2596
2597         if (method->slot == -1) {
2598                 /* method->slot might not be set for instances of generic methods */
2599                 if (method->is_inflated) {
2600                         g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2601                         method->slot = ((MonoMethodInflated*)method)->declaring->slot; 
2602                 } else {
2603                         if (!is_proxy)
2604                                 g_assert_not_reached ();
2605                 }
2606         }
2607
2608         /* check method->slot is a valid index: perform isinstance? */
2609         if (method->slot != -1) {
2610                 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2611                         if (!is_proxy) {
2612                                 gboolean variance_used = FALSE;
2613                                 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2614                                 g_assert (iface_offset > 0);
2615                                 res = vtable [iface_offset + method->slot];
2616                         }
2617                 } else {
2618                         res = vtable [method->slot];
2619                 }
2620     }
2621
2622         if (is_proxy) {
2623                 /* It may be an interface, abstract class method or generic method */
2624                 if (!res || mono_method_signature (res)->generic_param_count)
2625                         res = method;
2626
2627                 /* generic methods demand invoke_with_check */
2628                 if (mono_method_signature (res)->generic_param_count)
2629                         res = mono_marshal_get_remoting_invoke_with_check (res);
2630                 else {
2631 #ifndef DISABLE_COM
2632                         if (klass == mono_defaults.com_object_class || klass->is_com_object)
2633                                 res = mono_cominterop_get_invoke (res);
2634                         else
2635 #endif
2636                                 res = mono_marshal_get_remoting_invoke (res);
2637                 }
2638         } else {
2639                 if (method->is_inflated) {
2640                         /* Have to inflate the result */
2641                         res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2642                 }
2643         }
2644
2645         g_assert (res);
2646         
2647         return res;
2648 }
2649
2650 static MonoObject*
2651 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2652 {
2653         g_error ("runtime invoke called on uninitialized runtime");
2654         return NULL;
2655 }
2656
2657 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2658
2659 /**
2660  * mono_runtime_invoke:
2661  * @method: method to invoke
2662  * @obJ: object instance
2663  * @params: arguments to the method
2664  * @exc: exception information.
2665  *
2666  * Invokes the method represented by @method on the object @obj.
2667  *
2668  * obj is the 'this' pointer, it should be NULL for static
2669  * methods, a MonoObject* for object instances and a pointer to
2670  * the value type for value types.
2671  *
2672  * The params array contains the arguments to the method with the
2673  * same convention: MonoObject* pointers for object instances and
2674  * pointers to the value type otherwise. 
2675  * 
2676  * From unmanaged code you'll usually use the
2677  * mono_runtime_invoke() variant.
2678  *
2679  * Note that this function doesn't handle virtual methods for
2680  * you, it will exec the exact method you pass: we still need to
2681  * expose a function to lookup the derived class implementation
2682  * of a virtual method (there are examples of this in the code,
2683  * though).
2684  * 
2685  * You can pass NULL as the exc argument if you don't want to
2686  * catch exceptions, otherwise, *exc will be set to the exception
2687  * thrown, if any.  if an exception is thrown, you can't use the
2688  * MonoObject* result from the function.
2689  * 
2690  * If the method returns a value type, it is boxed in an object
2691  * reference.
2692  */
2693 MonoObject*
2694 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2695 {
2696         MonoObject *result;
2697
2698         if (mono_runtime_get_no_exec ())
2699                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2700
2701         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2702                 mono_profiler_method_start_invoke (method);
2703
2704         result = default_mono_runtime_invoke (method, obj, params, exc);
2705
2706         if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2707                 mono_profiler_method_end_invoke (method);
2708
2709         return result;
2710 }
2711
2712 /**
2713  * mono_method_get_unmanaged_thunk:
2714  * @method: method to generate a thunk for.
2715  *
2716  * Returns an unmanaged->managed thunk that can be used to call
2717  * a managed method directly from C.
2718  *
2719  * The thunk's C signature closely matches the managed signature:
2720  *
2721  * C#: public bool Equals (object obj);
2722  * C:  typedef MonoBoolean (*Equals)(MonoObject*,
2723  *             MonoObject*, MonoException**);
2724  *
2725  * The 1st ("this") parameter must not be used with static methods:
2726  *
2727  * C#: public static bool ReferenceEquals (object a, object b);
2728  * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2729  *             MonoException**);
2730  *
2731  * The last argument must be a non-null pointer of a MonoException* pointer.
2732  * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2733  * exception has been thrown in managed code. Otherwise it will point
2734  * to the MonoException* caught by the thunk. In this case, the result of
2735  * the thunk is undefined:
2736  *
2737  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2738  * MonoException *ex = NULL;
2739  * Equals func = mono_method_get_unmanaged_thunk (method);
2740  * MonoBoolean res = func (thisObj, objToCompare, &ex);
2741  * if (ex) {
2742  *    // handle exception
2743  * }
2744  *
2745  * The calling convention of the thunk matches the platform's default
2746  * convention. This means that under Windows, C declarations must
2747  * contain the __stdcall attribute:
2748  *
2749  * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2750  *             MonoObject*, MonoException**);
2751  *
2752  * LIMITATIONS
2753  *
2754  * Value type arguments and return values are treated as they were objects:
2755  *
2756  * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2757  * C:  typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2758  *
2759  * Arguments must be properly boxed upon trunk's invocation, while return
2760  * values must be unboxed.
2761  */
2762 gpointer
2763 mono_method_get_unmanaged_thunk (MonoMethod *method)
2764 {
2765         method = mono_marshal_get_thunk_invoke_wrapper (method);
2766         return mono_compile_method (method);
2767 }
2768
2769 static void
2770 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2771 {
2772         int t;
2773         if (type->byref) {
2774                 /* object fields cannot be byref, so we don't need a
2775                    wbarrier here */
2776                 gpointer *p = (gpointer*)dest;
2777                 *p = value;
2778                 return;
2779         }
2780         t = type->type;
2781 handle_enum:
2782         switch (t) {
2783         case MONO_TYPE_BOOLEAN:
2784         case MONO_TYPE_I1:
2785         case MONO_TYPE_U1: {
2786                 guint8 *p = (guint8*)dest;
2787                 *p = value ? *(guint8*)value : 0;
2788                 return;
2789         }
2790         case MONO_TYPE_I2:
2791         case MONO_TYPE_U2:
2792         case MONO_TYPE_CHAR: {
2793                 guint16 *p = (guint16*)dest;
2794                 *p = value ? *(guint16*)value : 0;
2795                 return;
2796         }
2797 #if SIZEOF_VOID_P == 4
2798         case MONO_TYPE_I:
2799         case MONO_TYPE_U:
2800 #endif
2801         case MONO_TYPE_I4:
2802         case MONO_TYPE_U4: {
2803                 gint32 *p = (gint32*)dest;
2804                 *p = value ? *(gint32*)value : 0;
2805                 return;
2806         }
2807 #if SIZEOF_VOID_P == 8
2808         case MONO_TYPE_I:
2809         case MONO_TYPE_U:
2810 #endif
2811         case MONO_TYPE_I8:
2812         case MONO_TYPE_U8: {
2813                 gint64 *p = (gint64*)dest;
2814                 *p = value ? *(gint64*)value : 0;
2815                 return;
2816         }
2817         case MONO_TYPE_R4: {
2818                 float *p = (float*)dest;
2819                 *p = value ? *(float*)value : 0;
2820                 return;
2821         }
2822         case MONO_TYPE_R8: {
2823                 double *p = (double*)dest;
2824                 *p = value ? *(double*)value : 0;
2825                 return;
2826         }
2827         case MONO_TYPE_STRING:
2828         case MONO_TYPE_SZARRAY:
2829         case MONO_TYPE_CLASS:
2830         case MONO_TYPE_OBJECT:
2831         case MONO_TYPE_ARRAY:
2832                 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2833                 return;
2834         case MONO_TYPE_FNPTR:
2835         case MONO_TYPE_PTR: {
2836                 gpointer *p = (gpointer*)dest;
2837                 *p = deref_pointer? *(gpointer*)value: value;
2838                 return;
2839         }
2840         case MONO_TYPE_VALUETYPE:
2841                 /* note that 't' and 'type->type' can be different */
2842                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2843                         t = mono_class_enum_basetype (type->data.klass)->type;
2844                         goto handle_enum;
2845                 } else {
2846                         MonoClass *class = mono_class_from_mono_type (type);
2847                         int size = mono_class_value_size (class, NULL);
2848                         if (value == NULL)
2849                                 memset (dest, 0, size);
2850                         else
2851                                 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2852                 }
2853                 return;
2854         case MONO_TYPE_GENERICINST:
2855                 t = type->data.generic_class->container_class->byval_arg.type;
2856                 goto handle_enum;
2857         default:
2858                 g_warning ("got type %x", type->type);
2859                 g_assert_not_reached ();
2860         }
2861 }
2862
2863 /**
2864  * mono_field_set_value:
2865  * @obj: Instance object
2866  * @field: MonoClassField describing the field to set
2867  * @value: The value to be set
2868  *
2869  * Sets the value of the field described by @field in the object instance @obj
2870  * to the value passed in @value.   This method should only be used for instance
2871  * fields.   For static fields, use mono_field_static_set_value.
2872  *
2873  * The value must be on the native format of the field type. 
2874  */
2875 void
2876 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2877 {
2878         void *dest;
2879
2880         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2881
2882         dest = (char*)obj + field->offset;
2883         set_value (field->type, dest, value, FALSE);
2884 }
2885
2886 /**
2887  * mono_field_static_set_value:
2888  * @field: MonoClassField describing the field to set
2889  * @value: The value to be set
2890  *
2891  * Sets the value of the static field described by @field
2892  * to the value passed in @value.
2893  *
2894  * The value must be on the native format of the field type. 
2895  */
2896 void
2897 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2898 {
2899         void *dest;
2900
2901         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2902         /* you cant set a constant! */
2903         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2904
2905         if (field->offset == -1) {
2906                 /* Special static */
2907                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2908                 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2909         } else {
2910                 dest = (char*)vt->data + field->offset;
2911         }
2912         set_value (field->type, dest, value, FALSE);
2913 }
2914
2915 /* Used by the debugger */
2916 void *
2917 mono_vtable_get_static_field_data (MonoVTable *vt)
2918 {
2919         return vt->data;
2920 }
2921
2922 static guint8*
2923 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2924 {
2925         guint8 *src;
2926
2927         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2928                 if (field->offset == -1) {
2929                         /* Special static */
2930                         gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2931                         src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2932                 } else {
2933                         src = (guint8*)vt->data + field->offset;
2934                 }
2935         } else {
2936                 src = (guint8*)obj + field->offset;
2937         }
2938
2939         return src;
2940 }
2941
2942 /**
2943  * mono_field_get_value:
2944  * @obj: Object instance
2945  * @field: MonoClassField describing the field to fetch information from
2946  * @value: pointer to the location where the value will be stored
2947  *
2948  * Use this routine to get the value of the field @field in the object
2949  * passed.
2950  *
2951  * The pointer provided by value must be of the field type, for reference
2952  * types this is a MonoObject*, for value types its the actual pointer to
2953  * the value type.
2954  *
2955  * For example:
2956  *     int i;
2957  *     mono_field_get_value (obj, int_field, &i);
2958  */
2959 void
2960 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2961 {
2962         void *src;
2963
2964         g_assert (obj);
2965
2966         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2967
2968         src = (char*)obj + field->offset;
2969         set_value (field->type, value, src, TRUE);
2970 }
2971
2972 /**
2973  * mono_field_get_value_object:
2974  * @domain: domain where the object will be created (if boxing)
2975  * @field: MonoClassField describing the field to fetch information from
2976  * @obj: The object instance for the field.
2977  *
2978  * Returns: a new MonoObject with the value from the given field.  If the
2979  * field represents a value type, the value is boxed.
2980  *
2981  */
2982 MonoObject *
2983 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2984 {       
2985         MonoObject *o;
2986         MonoClass *klass;
2987         MonoVTable *vtable = NULL;
2988         gchar *v;
2989         gboolean is_static = FALSE;
2990         gboolean is_ref = FALSE;
2991         gboolean is_literal = FALSE;
2992         gboolean is_ptr = FALSE;
2993         MonoError error;
2994         MonoType *type = mono_field_get_type_checked (field, &error);
2995
2996         if (!mono_error_ok (&error))
2997                 mono_error_raise_exception (&error);
2998
2999         switch (type->type) {
3000         case MONO_TYPE_STRING:
3001         case MONO_TYPE_OBJECT:
3002         case MONO_TYPE_CLASS:
3003         case MONO_TYPE_ARRAY:
3004         case MONO_TYPE_SZARRAY:
3005                 is_ref = TRUE;
3006                 break;
3007         case MONO_TYPE_U1:
3008         case MONO_TYPE_I1:
3009         case MONO_TYPE_BOOLEAN:
3010         case MONO_TYPE_U2:
3011         case MONO_TYPE_I2:
3012         case MONO_TYPE_CHAR:
3013         case MONO_TYPE_U:
3014         case MONO_TYPE_I:
3015         case MONO_TYPE_U4:
3016         case MONO_TYPE_I4:
3017         case MONO_TYPE_R4:
3018         case MONO_TYPE_U8:
3019         case MONO_TYPE_I8:
3020         case MONO_TYPE_R8:
3021         case MONO_TYPE_VALUETYPE:
3022                 is_ref = type->byref;
3023                 break;
3024         case MONO_TYPE_GENERICINST:
3025                 is_ref = !mono_type_generic_inst_is_valuetype (type);
3026                 break;
3027         case MONO_TYPE_PTR:
3028                 is_ptr = TRUE;
3029                 break;
3030         default:
3031                 g_error ("type 0x%x not handled in "
3032                          "mono_field_get_value_object", type->type);
3033                 return NULL;
3034         }
3035
3036         if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3037                 is_literal = TRUE;
3038
3039         if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3040                 is_static = TRUE;
3041
3042                 if (!is_literal) {
3043                         vtable = mono_class_vtable (domain, field->parent);
3044                         if (!vtable) {
3045                                 char *name = mono_type_get_full_name (field->parent);
3046                                 /*FIXME extend this to use the MonoError api*/
3047                                 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3048                                 g_free (name);
3049                                 return NULL;
3050                         }
3051                         if (!vtable->initialized)
3052                                 mono_runtime_class_init (vtable);
3053                 }
3054         } else {
3055                 g_assert (obj);
3056         }
3057         
3058         if (is_ref) {
3059                 if (is_literal) {
3060                         get_default_field_value (domain, field, &o);
3061                 } else if (is_static) {
3062                         mono_field_static_get_value (vtable, field, &o);
3063                 } else {
3064                         mono_field_get_value (obj, field, &o);
3065                 }
3066                 return o;
3067         }
3068
3069         if (is_ptr) {
3070                 static MonoMethod *m;
3071                 gpointer args [2];
3072                 gpointer *ptr;
3073                 gpointer v;
3074
3075                 if (!m) {
3076                         MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3077                         m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3078                         g_assert (m);
3079                 }
3080
3081                 v = &ptr;
3082                 if (is_literal) {
3083                         get_default_field_value (domain, field, v);
3084                 } else if (is_static) {
3085                         mono_field_static_get_value (vtable, field, v);
3086                 } else {
3087                         mono_field_get_value (obj, field, v);
3088                 }
3089
3090                 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3091                 args [0] = *ptr;
3092                 args [1] = mono_type_get_object (mono_domain_get (), type);
3093
3094                 return mono_runtime_invoke (m, NULL, args, NULL);
3095         }
3096
3097         /* boxed value type */
3098         klass = mono_class_from_mono_type (type);
3099
3100         if (mono_class_is_nullable (klass))
3101                 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3102
3103         o = mono_object_new (domain, klass);
3104         v = ((gchar *) o) + sizeof (MonoObject);
3105
3106         if (is_literal) {
3107                 get_default_field_value (domain, field, v);
3108         } else if (is_static) {
3109                 mono_field_static_get_value (vtable, field, v);
3110         } else {
3111                 mono_field_get_value (obj, field, v);
3112         }
3113
3114         return o;
3115 }
3116
3117 int
3118 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3119 {
3120         int retval = 0;
3121         const char *p = blob;
3122         mono_metadata_decode_blob_size (p, &p);
3123
3124         switch (type) {
3125         case MONO_TYPE_BOOLEAN:
3126         case MONO_TYPE_U1:
3127         case MONO_TYPE_I1:
3128                 *(guint8 *) value = *p;
3129                 break;
3130         case MONO_TYPE_CHAR:
3131         case MONO_TYPE_U2:
3132         case MONO_TYPE_I2:
3133                 *(guint16*) value = read16 (p);
3134                 break;
3135         case MONO_TYPE_U4:
3136         case MONO_TYPE_I4:
3137                 *(guint32*) value = read32 (p);
3138                 break;
3139         case MONO_TYPE_U8:
3140         case MONO_TYPE_I8:
3141                 *(guint64*) value = read64 (p);
3142                 break;
3143         case MONO_TYPE_R4:
3144                 readr4 (p, (float*) value);
3145                 break;
3146         case MONO_TYPE_R8:
3147                 readr8 (p, (double*) value);
3148                 break;
3149         case MONO_TYPE_STRING:
3150                 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3151                 break;
3152         case MONO_TYPE_CLASS:
3153                 *(gpointer*) value = NULL;
3154                 break;
3155         default:
3156                 retval = -1;
3157                 g_warning ("type 0x%02x should not be in constant table", type);
3158         }
3159         return retval;
3160 }
3161
3162 static void
3163 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3164 {
3165         MonoTypeEnum def_type;
3166         const char* data;
3167         
3168         data = mono_class_get_field_default_value (field, &def_type);
3169         mono_get_constant_value_from_blob (domain, def_type, data, value);
3170 }
3171
3172 /**
3173  * mono_field_static_get_value:
3174  * @vt: vtable to the object
3175  * @field: MonoClassField describing the field to fetch information from
3176  * @value: where the value is returned
3177  *
3178  * Use this routine to get the value of the static field @field value.
3179  *
3180  * The pointer provided by value must be of the field type, for reference
3181  * types this is a MonoObject*, for value types its the actual pointer to
3182  * the value type.
3183  *
3184  * For example:
3185  *     int i;
3186  *     mono_field_static_get_value (vt, int_field, &i);
3187  */
3188 void
3189 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3190 {
3191         void *src;
3192
3193         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3194         
3195         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3196                 get_default_field_value (vt->domain, field, value);
3197                 return;
3198         }
3199
3200         if (field->offset == -1) {
3201                 /* Special static */
3202                 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3203                 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3204         } else {
3205                 src = (char*)vt->data + field->offset;
3206         }
3207         set_value (field->type, value, src, TRUE);
3208 }
3209
3210 /**
3211  * mono_property_set_value:
3212  * @prop: MonoProperty to set
3213  * @obj: instance object on which to act
3214  * @params: parameters to pass to the propery
3215  * @exc: optional exception
3216  *
3217  * Invokes the property's set method with the given arguments on the
3218  * object instance obj (or NULL for static properties). 
3219  * 
3220  * You can pass NULL as the exc argument if you don't want to
3221  * catch exceptions, otherwise, *exc will be set to the exception
3222  * thrown, if any.  if an exception is thrown, you can't use the
3223  * MonoObject* result from the function.
3224  */
3225 void
3226 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3227 {
3228         default_mono_runtime_invoke (prop->set, obj, params, exc);
3229 }
3230
3231 /**
3232  * mono_property_get_value:
3233  * @prop: MonoProperty to fetch
3234  * @obj: instance object on which to act
3235  * @params: parameters to pass to the propery
3236  * @exc: optional exception
3237  *
3238  * Invokes the property's get method with the given arguments on the
3239  * object instance obj (or NULL for static properties). 
3240  * 
3241  * You can pass NULL as the exc argument if you don't want to
3242  * catch exceptions, otherwise, *exc will be set to the exception
3243  * thrown, if any.  if an exception is thrown, you can't use the
3244  * MonoObject* result from the function.
3245  *
3246  * Returns: the value from invoking the get method on the property.
3247  */
3248 MonoObject*
3249 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3250 {
3251         return default_mono_runtime_invoke (prop->get, obj, params, exc);
3252 }
3253
3254 /*
3255  * mono_nullable_init:
3256  * @buf: The nullable structure to initialize.
3257  * @value: the value to initialize from
3258  * @klass: the type for the object
3259  *
3260  * Initialize the nullable structure pointed to by @buf from @value which
3261  * should be a boxed value type.   The size of @buf should be able to hold
3262  * as much data as the @klass->instance_size (which is the number of bytes
3263  * that will be copies).
3264  *
3265  * Since Nullables have variable structure, we can not define a C
3266  * structure for them.
3267  */
3268 void
3269 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3270 {
3271         MonoClass *param_class = klass->cast_class;
3272                                 
3273         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3274         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3275
3276         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3277         if (value) {
3278                 if (param_class->has_references)
3279                         mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3280                 else
3281                         memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3282         } else {
3283                 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3284         }
3285 }
3286
3287 /**
3288  * mono_nullable_box:
3289  * @buf: The buffer representing the data to be boxed
3290  * @klass: the type to box it as.
3291  *
3292  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3293  * @buf.
3294  */
3295 MonoObject*
3296 mono_nullable_box (guint8 *buf, MonoClass *klass)
3297 {
3298         MonoClass *param_class = klass->cast_class;
3299
3300         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3301         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3302
3303         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3304                 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3305                 if (param_class->has_references)
3306                         mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3307                 else
3308                         memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3309                 return o;
3310         }
3311         else
3312                 return NULL;
3313 }
3314
3315 /**
3316  * mono_get_delegate_invoke:
3317  * @klass: The delegate class
3318  *
3319  * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3320  */
3321 MonoMethod *
3322 mono_get_delegate_invoke (MonoClass *klass)
3323 {
3324         MonoMethod *im;
3325
3326         /* This is called at runtime, so avoid the slower search in metadata */
3327         mono_class_setup_methods (klass);
3328         if (klass->exception_type)
3329                 return NULL;
3330         im = mono_class_get_method_from_name (klass, "Invoke", -1);
3331         return im;
3332 }
3333
3334 /**
3335  * mono_runtime_delegate_invoke:
3336  * @delegate: pointer to a delegate object.
3337  * @params: parameters for the delegate.
3338  * @exc: Pointer to the exception result.
3339  *
3340  * Invokes the delegate method @delegate with the parameters provided.
3341  *
3342  * You can pass NULL as the exc argument if you don't want to
3343  * catch exceptions, otherwise, *exc will be set to the exception
3344  * thrown, if any.  if an exception is thrown, you can't use the
3345  * MonoObject* result from the function.
3346  */
3347 MonoObject*
3348 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3349 {
3350         MonoMethod *im;
3351
3352         im = mono_get_delegate_invoke (delegate->vtable->klass);
3353         g_assert (im);
3354
3355         return mono_runtime_invoke (im, delegate, params, exc);
3356 }
3357
3358 static char **main_args = NULL;
3359 static int num_main_args;
3360
3361 /**
3362  * mono_runtime_get_main_args:
3363  *
3364  * Returns: a MonoArray with the arguments passed to the main program
3365  */
3366 MonoArray*
3367 mono_runtime_get_main_args (void)
3368 {
3369         MonoArray *res;
3370         int i;
3371         MonoDomain *domain = mono_domain_get ();
3372
3373         if (!main_args)
3374                 return NULL;
3375
3376         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3377
3378         for (i = 0; i < num_main_args; ++i)
3379                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3380
3381         return res;
3382 }
3383
3384 static void
3385 free_main_args (void)
3386 {
3387         int i;
3388
3389         for (i = 0; i < num_main_args; ++i)
3390                 g_free (main_args [i]);
3391         g_free (main_args);
3392 }
3393
3394 /**
3395  * mono_runtime_run_main:
3396  * @method: the method to start the application with (usually Main)
3397  * @argc: number of arguments from the command line
3398  * @argv: array of strings from the command line
3399  * @exc: excetption results
3400  *
3401  * Execute a standard Main() method (argc/argv contains the
3402  * executable name). This method also sets the command line argument value
3403  * needed by System.Environment.
3404  *
3405  * 
3406  */
3407 int
3408 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3409                        MonoObject **exc)
3410 {
3411         int i;
3412         MonoArray *args = NULL;
3413         MonoDomain *domain = mono_domain_get ();
3414         gchar *utf8_fullpath;
3415         MonoMethodSignature *sig;
3416
3417         g_assert (method != NULL);
3418         
3419         mono_thread_set_main (mono_thread_current ());
3420
3421         main_args = g_new0 (char*, argc);
3422         num_main_args = argc;
3423
3424         if (!g_path_is_absolute (argv [0])) {
3425                 gchar *basename = g_path_get_basename (argv [0]);
3426                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3427                                                     basename,
3428                                                     NULL);
3429
3430                 utf8_fullpath = mono_utf8_from_external (fullpath);
3431                 if(utf8_fullpath == NULL) {
3432                         /* Printing the arg text will cause glib to
3433                          * whinge about "Invalid UTF-8", but at least
3434                          * its relevant, and shows the problem text
3435                          * string.
3436                          */
3437                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3438                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3439                         exit (-1);
3440                 }
3441
3442                 g_free (fullpath);
3443                 g_free (basename);
3444         } else {
3445                 utf8_fullpath = mono_utf8_from_external (argv[0]);
3446                 if(utf8_fullpath == NULL) {
3447                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3448                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3449                         exit (-1);
3450                 }
3451         }
3452
3453         main_args [0] = utf8_fullpath;
3454
3455         for (i = 1; i < argc; ++i) {
3456                 gchar *utf8_arg;
3457
3458                 utf8_arg=mono_utf8_from_external (argv[i]);
3459                 if(utf8_arg==NULL) {
3460                         /* Ditto the comment about Invalid UTF-8 here */
3461                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3462                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3463                         exit (-1);
3464                 }
3465
3466                 main_args [i] = utf8_arg;
3467         }
3468         argc--;
3469         argv++;
3470
3471         sig = mono_method_signature (method);
3472         if (!sig) {
3473                 g_print ("Unable to load Main method.\n");
3474                 exit (-1);
3475         }
3476
3477         if (sig->param_count) {
3478                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3479                 for (i = 0; i < argc; ++i) {
3480                         /* The encodings should all work, given that
3481                          * we've checked all these args for the
3482                          * main_args array.
3483                          */
3484                         gchar *str = mono_utf8_from_external (argv [i]);
3485                         MonoString *arg = mono_string_new (domain, str);
3486                         mono_array_setref (args, i, arg);
3487                         g_free (str);
3488                 }
3489         } else {
3490                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3491         }
3492         
3493         mono_assembly_set_main (method->klass->image->assembly);
3494
3495         return mono_runtime_exec_main (method, args, exc);
3496 }
3497
3498 static MonoObject*
3499 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3500 {
3501         static MonoMethod *serialize_method;
3502
3503         void *params [1];
3504         MonoObject *array;
3505
3506         if (!serialize_method) {
3507                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3508                 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3509         }
3510
3511         if (!serialize_method) {
3512                 *failure = TRUE;
3513                 return NULL;
3514         }
3515
3516         g_assert (!mono_object_class (obj)->marshalbyref);
3517
3518         params [0] = obj;
3519         *exc = NULL;
3520         array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3521         if (*exc)
3522                 *failure = TRUE;
3523
3524         return array;
3525 }
3526
3527 static MonoObject*
3528 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3529 {
3530         static MonoMethod *deserialize_method;
3531
3532         void *params [1];
3533         MonoObject *result;
3534
3535         if (!deserialize_method) {
3536                 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3537                 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3538         }
3539         if (!deserialize_method) {
3540                 *failure = TRUE;
3541                 return NULL;
3542         }
3543
3544         params [0] = obj;
3545         *exc = NULL;
3546         result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3547         if (*exc)
3548                 *failure = TRUE;
3549
3550         return result;
3551 }
3552
3553 static MonoObject*
3554 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3555 {
3556         static MonoMethod *get_proxy_method;
3557
3558         MonoDomain *domain = mono_domain_get ();
3559         MonoRealProxy *real_proxy;
3560         MonoReflectionType *reflection_type;
3561         MonoTransparentProxy *transparent_proxy;
3562
3563         if (!get_proxy_method)
3564                 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3565
3566         g_assert (obj->vtable->klass->marshalbyref);
3567
3568         real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3569         reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3570
3571         MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3572         MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3573
3574         *exc = NULL;
3575         transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3576         if (*exc)
3577                 *failure = TRUE;
3578
3579         return (MonoObject*) transparent_proxy;
3580 }
3581
3582 /**
3583  * mono_object_xdomain_representation
3584  * @obj: an object
3585  * @target_domain: a domain
3586  * @exc: pointer to a MonoObject*
3587  *
3588  * Creates a representation of obj in the domain target_domain.  This
3589  * is either a copy of obj arrived through via serialization and
3590  * deserialization or a proxy, depending on whether the object is
3591  * serializable or marshal by ref.  obj must not be in target_domain.
3592  *
3593  * If the object cannot be represented in target_domain, NULL is
3594  * returned and *exc is set to an appropriate exception.
3595  */
3596 MonoObject*
3597 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3598 {
3599         MonoObject *deserialized = NULL;
3600         gboolean failure = FALSE;
3601
3602         *exc = NULL;
3603
3604         if (mono_object_class (obj)->marshalbyref) {
3605                 deserialized = make_transparent_proxy (obj, &failure, exc);
3606         } else {
3607                 MonoDomain *domain = mono_domain_get ();
3608                 MonoObject *serialized;
3609
3610                 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3611                 serialized = serialize_object (obj, &failure, exc);
3612                 mono_domain_set_internal_with_options (target_domain, FALSE);
3613                 if (!failure)
3614                         deserialized = deserialize_object (serialized, &failure, exc);
3615                 if (domain != target_domain)
3616                         mono_domain_set_internal_with_options (domain, FALSE);
3617         }
3618
3619         return deserialized;
3620 }
3621
3622 /* Used in call_unhandled_exception_delegate */
3623 static MonoObject *
3624 create_unhandled_exception_eventargs (MonoObject *exc)
3625 {
3626         MonoClass *klass;
3627         gpointer args [2];
3628         MonoMethod *method = NULL;
3629         MonoBoolean is_terminating = TRUE;
3630         MonoObject *obj;
3631
3632         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3633         g_assert (klass);
3634
3635         mono_class_init (klass);
3636
3637         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3638         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3639         g_assert (method);
3640
3641         args [0] = exc;
3642         args [1] = &is_terminating;
3643
3644         obj = mono_object_new (mono_domain_get (), klass);
3645         mono_runtime_invoke (method, obj, args, NULL);
3646
3647         return obj;
3648 }
3649
3650 /* Used in mono_unhandled_exception */
3651 static void
3652 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3653         MonoObject *e = NULL;
3654         gpointer pa [2];
3655         MonoDomain *current_domain = mono_domain_get ();
3656
3657         if (domain != current_domain)
3658                 mono_domain_set_internal_with_options (domain, FALSE);
3659
3660         g_assert (domain == mono_object_domain (domain->domain));
3661
3662         if (mono_object_domain (exc) != domain) {
3663                 MonoObject *serialization_exc;
3664
3665                 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3666                 if (!exc) {
3667                         if (serialization_exc) {
3668                                 MonoObject *dummy;
3669                                 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3670                                 g_assert (exc);
3671                         } else {
3672                                 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3673                                                 "System.Runtime.Serialization", "SerializationException",
3674                                                 "Could not serialize unhandled exception.");
3675                         }
3676                 }
3677         }
3678         g_assert (mono_object_domain (exc) == domain);
3679
3680         pa [0] = domain->domain;
3681         pa [1] = create_unhandled_exception_eventargs (exc);
3682         mono_runtime_delegate_invoke (delegate, pa, &e);
3683
3684         if (domain != current_domain)
3685                 mono_domain_set_internal_with_options (current_domain, FALSE);
3686
3687         if (e) {
3688                 MonoError error;
3689                 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3690                 if (!mono_error_ok (&error)) {
3691                         g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3692                         mono_error_cleanup (&error);
3693                 } else {
3694                         g_warning ("exception inside UnhandledException handler: %s\n", msg);
3695                         g_free (msg);
3696                 }
3697         }
3698 }
3699
3700 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3701
3702 /**
3703  * mono_runtime_unhandled_exception_policy_set:
3704  * @policy: the new policy
3705  * 
3706  * This is a VM internal routine.
3707  *
3708  * Sets the runtime policy for handling unhandled exceptions.
3709  */
3710 void
3711 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3712         runtime_unhandled_exception_policy = policy;
3713 }
3714
3715 /**
3716  * mono_runtime_unhandled_exception_policy_get:
3717  *
3718  * This is a VM internal routine.
3719  *
3720  * Gets the runtime policy for handling unhandled exceptions.
3721  */
3722 MonoRuntimeUnhandledExceptionPolicy
3723 mono_runtime_unhandled_exception_policy_get (void) {
3724         return runtime_unhandled_exception_policy;
3725 }
3726
3727 /**
3728  * mono_unhandled_exception:
3729  * @exc: exception thrown
3730  *
3731  * This is a VM internal routine.
3732  *
3733  * We call this function when we detect an unhandled exception
3734  * in the default domain.
3735  *
3736  * It invokes the * UnhandledException event in AppDomain or prints
3737  * a warning to the console 
3738  */
3739 void
3740 mono_unhandled_exception (MonoObject *exc)
3741 {
3742         MonoDomain *current_domain = mono_domain_get ();
3743         MonoDomain *root_domain = mono_get_root_domain ();
3744         MonoClassField *field;
3745         MonoObject *current_appdomain_delegate;
3746         MonoObject *root_appdomain_delegate;
3747
3748         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
3749                                              "UnhandledException");
3750         g_assert (field);
3751
3752         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3753                 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3754                                 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3755                 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3756                 if (current_domain != root_domain) {
3757                         current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3758                 } else {
3759                         current_appdomain_delegate = NULL;
3760                 }
3761
3762                 /* set exitcode only if we will abort the process */
3763                 if (abort_process)
3764                         mono_environment_exitcode_set (1);
3765                 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3766                         mono_print_unhandled_exception (exc);
3767                 } else {
3768                         if (root_appdomain_delegate) {
3769                                 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3770                         }
3771                         if (current_appdomain_delegate) {
3772                                 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3773                         }
3774                 }
3775         }
3776 }
3777
3778 /**
3779  * mono_runtime_exec_managed_code:
3780  * @domain: Application domain
3781  * @main_func: function to invoke from the execution thread
3782  * @main_args: parameter to the main_func
3783  *
3784  * Launch a new thread to execute a function
3785  *
3786  * main_func is called back from the thread with main_args as the
3787  * parameter.  The callback function is expected to start Main()
3788  * eventually.  This function then waits for all managed threads to
3789  * finish.
3790  * It is not necesseray anymore to execute managed code in a subthread,
3791  * so this function should not be used anymore by default: just
3792  * execute the code and then call mono_thread_manage ().
3793  */
3794 void
3795 mono_runtime_exec_managed_code (MonoDomain *domain,
3796                                 MonoMainThreadFunc main_func,
3797                                 gpointer main_args)
3798 {
3799         mono_thread_create (domain, main_func, main_args);
3800
3801         mono_thread_manage ();
3802 }
3803
3804 /*
3805  * Execute a standard Main() method (args doesn't contain the
3806  * executable name).
3807  */
3808 int
3809 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3810 {
3811         MonoDomain *domain;
3812         gpointer pa [1];
3813         int rval;
3814         MonoCustomAttrInfo* cinfo;
3815         gboolean has_stathread_attribute;
3816         MonoInternalThread* thread = mono_thread_internal_current ();
3817
3818         g_assert (args);
3819
3820         pa [0] = args;
3821
3822         domain = mono_object_domain (args);
3823         if (!domain->entry_assembly) {
3824                 gchar *str;
3825                 MonoAssembly *assembly;
3826
3827                 assembly = method->klass->image->assembly;
3828                 domain->entry_assembly = assembly;
3829                 /* Domains created from another domain already have application_base and configuration_file set */
3830                 if (domain->setup->application_base == NULL) {
3831                         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3832                 }
3833
3834                 if (domain->setup->configuration_file == NULL) {
3835                         str = g_strconcat (assembly->image->name, ".config", NULL);
3836                         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3837                         g_free (str);
3838                         mono_set_private_bin_path_from_config (domain);
3839                 }
3840         }
3841
3842         cinfo = mono_custom_attrs_from_method (method);
3843         if (cinfo) {
3844                 static MonoClass *stathread_attribute = NULL;
3845                 if (!stathread_attribute)
3846                         stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3847                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3848                 if (!cinfo->cached)
3849                         mono_custom_attrs_free (cinfo);
3850         } else {
3851                 has_stathread_attribute = FALSE;
3852         }
3853         if (has_stathread_attribute) {
3854                 thread->apartment_state = ThreadApartmentState_STA;
3855         } else {
3856                 thread->apartment_state = ThreadApartmentState_MTA;
3857         }
3858         mono_thread_init_apartment_state ();
3859
3860         mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3861
3862         /* FIXME: check signature of method */
3863         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3864                 MonoObject *res;
3865                 res = mono_runtime_invoke (method, NULL, pa, exc);
3866                 if (!exc || !*exc)
3867                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3868                 else
3869                         rval = -1;
3870
3871                 mono_environment_exitcode_set (rval);
3872         } else {
3873                 mono_runtime_invoke (method, NULL, pa, exc);
3874                 if (!exc || !*exc)
3875                         rval = 0;
3876                 else {
3877                         /* If the return type of Main is void, only
3878                          * set the exitcode if an exception was thrown
3879                          * (we don't want to blow away an
3880                          * explicitly-set exit code)
3881                          */
3882                         rval = -1;
3883                         mono_environment_exitcode_set (rval);
3884                 }
3885         }
3886
3887         mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3888
3889         return rval;
3890 }
3891
3892 /**
3893  * mono_install_runtime_invoke:
3894  * @func: Function to install
3895  *
3896  * This is a VM internal routine
3897  */
3898 void
3899 mono_install_runtime_invoke (MonoInvokeFunc func)
3900 {
3901         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3902 }
3903
3904
3905 /**
3906  * mono_runtime_invoke_array:
3907  * @method: method to invoke
3908  * @obJ: object instance
3909  * @params: arguments to the method
3910  * @exc: exception information.
3911  *
3912  * Invokes the method represented by @method on the object @obj.
3913  *
3914  * obj is the 'this' pointer, it should be NULL for static
3915  * methods, a MonoObject* for object instances and a pointer to
3916  * the value type for value types.
3917  *
3918  * The params array contains the arguments to the method with the
3919  * same convention: MonoObject* pointers for object instances and
3920  * pointers to the value type otherwise. The _invoke_array
3921  * variant takes a C# object[] as the params argument (MonoArray
3922  * *params): in this case the value types are boxed inside the
3923  * respective reference representation.
3924  * 
3925  * From unmanaged code you'll usually use the
3926  * mono_runtime_invoke() variant.
3927  *
3928  * Note that this function doesn't handle virtual methods for
3929  * you, it will exec the exact method you pass: we still need to
3930  * expose a function to lookup the derived class implementation
3931  * of a virtual method (there are examples of this in the code,
3932  * though).
3933  * 
3934  * You can pass NULL as the exc argument if you don't want to
3935  * catch exceptions, otherwise, *exc will be set to the exception
3936  * thrown, if any.  if an exception is thrown, you can't use the
3937  * MonoObject* result from the function.
3938  * 
3939  * If the method returns a value type, it is boxed in an object
3940  * reference.
3941  */
3942 MonoObject*
3943 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3944                            MonoObject **exc)
3945 {
3946         MonoMethodSignature *sig = mono_method_signature (method);
3947         gpointer *pa = NULL;
3948         MonoObject *res;
3949         int i;
3950         gboolean has_byref_nullables = FALSE;
3951
3952         if (NULL != params) {
3953                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3954                 for (i = 0; i < mono_array_length (params); i++) {
3955                         MonoType *t = sig->params [i];
3956
3957                 again:
3958                         switch (t->type) {
3959                         case MONO_TYPE_U1:
3960                         case MONO_TYPE_I1:
3961                         case MONO_TYPE_BOOLEAN:
3962                         case MONO_TYPE_U2:
3963                         case MONO_TYPE_I2:
3964                         case MONO_TYPE_CHAR:
3965                         case MONO_TYPE_U:
3966                         case MONO_TYPE_I:
3967                         case MONO_TYPE_U4:
3968                         case MONO_TYPE_I4:
3969                         case MONO_TYPE_U8:
3970                         case MONO_TYPE_I8:
3971                         case MONO_TYPE_R4:
3972                         case MONO_TYPE_R8:
3973                         case MONO_TYPE_VALUETYPE:
3974                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3975                                         /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3976                                         pa [i] = mono_array_get (params, MonoObject*, i);
3977                                         if (t->byref)
3978                                                 has_byref_nullables = TRUE;
3979                                 } else {
3980                                         /* MS seems to create the objects if a null is passed in */
3981                                         if (!mono_array_get (params, MonoObject*, i))
3982                                                 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
3983
3984                                         if (t->byref) {
3985                                                 /*
3986                                                  * We can't pass the unboxed vtype byref to the callee, since
3987                                                  * that would mean the callee would be able to modify boxed
3988                                                  * primitive types. So we (and MS) make a copy of the boxed
3989                                                  * object, pass that to the callee, and replace the original
3990                                                  * boxed object in the arg array with the copy.
3991                                                  */
3992                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3993                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3994                                                 mono_array_setref (params, i, copy);
3995                                         }
3996                                                 
3997                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3998                                 }
3999                                 break;
4000                         case MONO_TYPE_STRING:
4001                         case MONO_TYPE_OBJECT:
4002                         case MONO_TYPE_CLASS:
4003                         case MONO_TYPE_ARRAY:
4004                         case MONO_TYPE_SZARRAY:
4005                                 if (t->byref)
4006                                         pa [i] = mono_array_addr (params, MonoObject*, i);
4007                                         // FIXME: I need to check this code path
4008                                 else
4009                                         pa [i] = mono_array_get (params, MonoObject*, i);
4010                                 break;
4011                         case MONO_TYPE_GENERICINST:
4012                                 if (t->byref)
4013                                         t = &t->data.generic_class->container_class->this_arg;
4014                                 else
4015                                         t = &t->data.generic_class->container_class->byval_arg;
4016                                 goto again;
4017                         case MONO_TYPE_PTR: {
4018                                 MonoObject *arg;
4019
4020                                 /* The argument should be an IntPtr */
4021                                 arg = mono_array_get (params, MonoObject*, i);
4022                                 if (arg == NULL) {
4023                                         pa [i] = NULL;
4024                                 } else {
4025                                         g_assert (arg->vtable->klass == mono_defaults.int_class);
4026                                         pa [i] = ((MonoIntPtr*)arg)->m_value;
4027                                 }
4028                                 break;
4029                         }
4030                         default:
4031                                 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4032                         }
4033                 }
4034         }
4035
4036         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4037                 void *o = obj;
4038
4039                 if (mono_class_is_nullable (method->klass)) {
4040                         /* Need to create a boxed vtype instead */
4041                         g_assert (!obj);
4042
4043                         if (!params)
4044                                 return NULL;
4045                         else
4046                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4047                 }
4048
4049                 if (!obj) {
4050                         obj = mono_object_new (mono_domain_get (), method->klass);
4051                         g_assert (obj); /*maybe we should raise a TLE instead?*/
4052                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4053                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4054                         }
4055                         if (method->klass->valuetype)
4056                                 o = mono_object_unbox (obj);
4057                         else
4058                                 o = obj;
4059                 } else if (method->klass->valuetype) {
4060                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
4061                 }
4062
4063                 mono_runtime_invoke (method, o, pa, exc);
4064                 return obj;
4065         } else {
4066                 if (mono_class_is_nullable (method->klass)) {
4067                         MonoObject *nullable;
4068
4069                         /* Convert the unboxed vtype into a Nullable structure */
4070                         nullable = mono_object_new (mono_domain_get (), method->klass);
4071
4072                         mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4073                         obj = mono_object_unbox (nullable);
4074                 }
4075
4076                 /* obj must be already unboxed if needed */
4077                 res = mono_runtime_invoke (method, obj, pa, exc);
4078
4079                 if (sig->ret->type == MONO_TYPE_PTR) {
4080                         MonoClass *pointer_class;
4081                         static MonoMethod *box_method;
4082                         void *box_args [2];
4083                         MonoObject *box_exc;
4084
4085                         /* 
4086                          * The runtime-invoke wrapper returns a boxed IntPtr, need to 
4087                          * convert it to a Pointer object.
4088                          */
4089                         pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4090                         if (!box_method)
4091                                 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4092
4093                         g_assert (res->vtable->klass == mono_defaults.int_class);
4094                         box_args [0] = ((MonoIntPtr*)res)->m_value;
4095                         box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4096                         res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4097                         g_assert (!box_exc);
4098                 }
4099
4100                 if (has_byref_nullables) {
4101                         /* 
4102                          * The runtime invoke wrapper already converted byref nullables back,
4103                          * and stored them in pa, we just need to copy them back to the
4104                          * managed array.
4105                          */
4106                         for (i = 0; i < mono_array_length (params); i++) {
4107                                 MonoType *t = sig->params [i];
4108
4109                                 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4110                                         mono_array_setref (params, i, pa [i]);
4111                         }
4112                 }
4113
4114                 return res;
4115         }
4116 }
4117
4118 static void
4119 arith_overflow (void)
4120 {
4121         mono_raise_exception (mono_get_exception_overflow ());
4122 }
4123
4124 /**
4125  * mono_object_allocate:
4126  * @size: number of bytes to allocate
4127  *
4128  * This is a very simplistic routine until we have our GC-aware
4129  * memory allocator. 
4130  *
4131  * Returns: an allocated object of size @size, or NULL on failure.
4132  */
4133 static inline void *
4134 mono_object_allocate (size_t size, MonoVTable *vtable)
4135 {
4136         MonoObject *o;
4137         mono_stats.new_object_count++;
4138         ALLOC_OBJECT (o, vtable, size);
4139
4140         return o;
4141 }
4142
4143 /**
4144  * mono_object_allocate_ptrfree:
4145  * @size: number of bytes to allocate
4146  *
4147  * Note that the memory allocated is not zeroed.
4148  * Returns: an allocated object of size @size, or NULL on failure.
4149  */
4150 static inline void *
4151 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4152 {
4153         MonoObject *o;
4154         mono_stats.new_object_count++;
4155         ALLOC_PTRFREE (o, vtable, size);
4156         return o;
4157 }
4158
4159 static inline void *
4160 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4161 {
4162         void *o;
4163         ALLOC_TYPED (o, size, vtable);
4164         mono_stats.new_object_count++;
4165
4166         return o;
4167 }
4168
4169 /**
4170  * mono_object_new:
4171  * @klass: the class of the object that we want to create
4172  *
4173  * Returns: a newly created object whose definition is
4174  * looked up using @klass.   This will not invoke any constructors, 
4175  * so the consumer of this routine has to invoke any constructors on
4176  * its own to initialize the object.
4177  * 
4178  * It returns NULL on failure.
4179  */
4180 MonoObject *
4181 mono_object_new (MonoDomain *domain, MonoClass *klass)
4182 {
4183         MonoVTable *vtable;
4184
4185         MONO_ARCH_SAVE_REGS;
4186         vtable = mono_class_vtable (domain, klass);
4187         if (!vtable)
4188                 return NULL;
4189         return mono_object_new_specific (vtable);
4190 }
4191
4192 /**
4193  * mono_object_new_pinned:
4194  *
4195  *   Same as mono_object_new, but the returned object will be pinned.
4196  * For SGEN, these objects will only be freed at appdomain unload.
4197  */
4198 MonoObject *
4199 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4200 {
4201         MonoVTable *vtable;
4202
4203         MONO_ARCH_SAVE_REGS;
4204         vtable = mono_class_vtable (domain, klass);
4205         if (!vtable)
4206                 return NULL;
4207
4208 #ifdef HAVE_SGEN_GC
4209         return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4210 #else
4211         return mono_object_new_specific (vtable);
4212 #endif
4213 }
4214
4215 /**
4216  * mono_object_new_specific:
4217  * @vtable: the vtable of the object that we want to create
4218  *
4219  * Returns: A newly created object with class and domain specified
4220  * by @vtable
4221  */
4222 MonoObject *
4223 mono_object_new_specific (MonoVTable *vtable)
4224 {
4225         MonoObject *o;
4226
4227         MONO_ARCH_SAVE_REGS;
4228         
4229         /* check for is_com_object for COM Interop */
4230         if (vtable->remote || vtable->klass->is_com_object)
4231         {
4232                 gpointer pa [1];
4233                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4234
4235                 if (im == NULL) {
4236                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4237
4238                         if (!klass->inited)
4239                                 mono_class_init (klass);
4240
4241                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4242                         g_assert (im);
4243                         vtable->domain->create_proxy_for_type_method = im;
4244                 }
4245         
4246                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4247
4248                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
4249                 if (o != NULL) return o;
4250         }
4251
4252         return mono_object_new_alloc_specific (vtable);
4253 }
4254
4255 MonoObject *
4256 mono_object_new_alloc_specific (MonoVTable *vtable)
4257 {
4258         MonoObject *o;
4259
4260         if (!vtable->klass->has_references) {
4261                 o = mono_object_new_ptrfree (vtable);
4262         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4263                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4264         } else {
4265 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4266                 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4267         }
4268         if (G_UNLIKELY (vtable->klass->has_finalize))
4269                 mono_object_register_finalizer (o);
4270         
4271         if (G_UNLIKELY (profile_allocs))
4272                 mono_profiler_allocation (o, vtable->klass);
4273         return o;
4274 }
4275
4276 MonoObject*
4277 mono_object_new_fast (MonoVTable *vtable)
4278 {
4279         MonoObject *o;
4280         ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4281         return o;
4282 }
4283
4284 static MonoObject*
4285 mono_object_new_ptrfree (MonoVTable *vtable)
4286 {
4287         MonoObject *obj;
4288         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4289 #if NEED_TO_ZERO_PTRFREE
4290         /* an inline memset is much faster for the common vcase of small objects
4291          * note we assume the allocated size is a multiple of sizeof (void*).
4292          */
4293         if (vtable->klass->instance_size < 128) {
4294                 gpointer *p, *end;
4295                 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4296                 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4297                 while (p < end) {
4298                         *p = NULL;
4299                         ++p;
4300                 }
4301         } else {
4302                 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4303         }
4304 #endif
4305         return obj;
4306 }
4307
4308 static MonoObject*
4309 mono_object_new_ptrfree_box (MonoVTable *vtable)
4310 {
4311         MonoObject *obj;
4312         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4313         /* the object will be boxed right away, no need to memzero it */
4314         return obj;
4315 }
4316
4317 /**
4318  * mono_class_get_allocation_ftn:
4319  * @vtable: vtable
4320  * @for_box: the object will be used for boxing
4321  * @pass_size_in_words: 
4322  *
4323  * Return the allocation function appropriate for the given class.
4324  */
4325
4326 void*
4327 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4328 {
4329         *pass_size_in_words = FALSE;
4330
4331         if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4332                 profile_allocs = FALSE;
4333
4334         if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4335                 return mono_object_new_specific;
4336
4337         if (!vtable->klass->has_references) {
4338                 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4339                 if (for_box)
4340                         return mono_object_new_ptrfree_box;
4341                 return mono_object_new_ptrfree;
4342         }
4343
4344         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4345
4346                 return mono_object_new_fast;
4347
4348                 /* 
4349                  * FIXME: This is actually slower than mono_object_new_fast, because
4350                  * of the overhead of parameter passing.
4351                  */
4352                 /*
4353                 *pass_size_in_words = TRUE;
4354 #ifdef GC_REDIRECT_TO_LOCAL
4355                 return GC_local_gcj_fast_malloc;
4356 #else
4357                 return GC_gcj_fast_malloc;
4358 #endif
4359                 */
4360         }
4361
4362         return mono_object_new_specific;
4363 }
4364
4365 /**
4366  * mono_object_new_from_token:
4367  * @image: Context where the type_token is hosted
4368  * @token: a token of the type that we want to create
4369  *
4370  * Returns: A newly created object whose definition is
4371  * looked up using @token in the @image image
4372  */
4373 MonoObject *
4374 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
4375 {
4376         MonoClass *class;
4377
4378         class = mono_class_get (image, token);
4379
4380         return mono_object_new (domain, class);
4381 }
4382
4383
4384 /**
4385  * mono_object_clone:
4386  * @obj: the object to clone
4387  *
4388  * Returns: A newly created object who is a shallow copy of @obj
4389  */
4390 MonoObject *
4391 mono_object_clone (MonoObject *obj)
4392 {
4393         MonoObject *o;
4394         int size = obj->vtable->klass->instance_size;
4395
4396         o = mono_object_allocate (size, obj->vtable);
4397
4398         if (obj->vtable->klass->has_references) {
4399                 mono_gc_wbarrier_object_copy (o, obj);
4400         } else {
4401                 int size = obj->vtable->klass->instance_size;
4402                 /* do not copy the sync state */
4403                 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4404         }
4405         if (G_UNLIKELY (profile_allocs))
4406                 mono_profiler_allocation (o, obj->vtable->klass);
4407
4408         if (obj->vtable->klass->has_finalize)
4409                 mono_object_register_finalizer (o);
4410         return o;
4411 }
4412
4413 /**
4414  * mono_array_full_copy:
4415  * @src: source array to copy
4416  * @dest: destination array
4417  *
4418  * Copies the content of one array to another with exactly the same type and size.
4419  */
4420 void
4421 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4422 {
4423         uintptr_t size;
4424         MonoClass *klass = src->obj.vtable->klass;
4425
4426         MONO_ARCH_SAVE_REGS;
4427
4428         g_assert (klass == dest->obj.vtable->klass);
4429
4430         size = mono_array_length (src);
4431         g_assert (size == mono_array_length (dest));
4432         size *= mono_array_element_size (klass);
4433 #ifdef HAVE_SGEN_GC
4434         if (klass->element_class->valuetype) {
4435                 if (klass->element_class->has_references)
4436                         mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4437                 else
4438                         memcpy (&dest->vector, &src->vector, size);
4439         } else {
4440                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4441         }
4442 #else
4443         memcpy (&dest->vector, &src->vector, size);
4444 #endif
4445 }
4446
4447 /**
4448  * mono_array_clone_in_domain:
4449  * @domain: the domain in which the array will be cloned into
4450  * @array: the array to clone
4451  *
4452  * This routine returns a copy of the array that is hosted on the
4453  * specified MonoDomain.
4454  */
4455 MonoArray*
4456 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4457 {
4458         MonoArray *o;
4459         uintptr_t size, i;
4460         uintptr_t *sizes;
4461         MonoClass *klass = array->obj.vtable->klass;
4462
4463         MONO_ARCH_SAVE_REGS;
4464
4465         if (array->bounds == NULL) {
4466                 size = mono_array_length (array);
4467                 o = mono_array_new_full (domain, klass, &size, NULL);
4468
4469                 size *= mono_array_element_size (klass);
4470 #ifdef HAVE_SGEN_GC
4471                 if (klass->element_class->valuetype) {
4472                         if (klass->element_class->has_references)
4473                                 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4474                         else
4475                                 memcpy (&o->vector, &array->vector, size);
4476                 } else {
4477                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4478                 }
4479 #else
4480                 memcpy (&o->vector, &array->vector, size);
4481 #endif
4482                 return o;
4483         }
4484         
4485         sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4486         size = mono_array_element_size (klass);
4487         for (i = 0; i < klass->rank; ++i) {
4488                 sizes [i] = array->bounds [i].length;
4489                 size *= array->bounds [i].length;
4490                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4491         }
4492         o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4493 #ifdef HAVE_SGEN_GC
4494         if (klass->element_class->valuetype) {
4495                 if (klass->element_class->has_references)
4496                         mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4497                 else
4498                         memcpy (&o->vector, &array->vector, size);
4499         } else {
4500                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4501         }
4502 #else
4503         memcpy (&o->vector, &array->vector, size);
4504 #endif
4505
4506         return o;
4507 }
4508
4509 /**
4510  * mono_array_clone:
4511  * @array: the array to clone
4512  *
4513  * Returns: A newly created array who is a shallow copy of @array
4514  */
4515 MonoArray*
4516 mono_array_clone (MonoArray *array)
4517 {
4518         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4519 }
4520
4521 /* helper macros to check for overflow when calculating the size of arrays */
4522 #ifdef MONO_BIG_ARRAYS
4523 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4524 #define MYGUINT_MAX MYGUINT64_MAX
4525 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4526             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4527 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4528             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
4529                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4530 #else
4531 #define MYGUINT32_MAX 4294967295U
4532 #define MYGUINT_MAX MYGUINT32_MAX
4533 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4534             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4535 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4536             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
4537                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4538 #endif
4539
4540 gboolean
4541 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4542 {
4543         uintptr_t byte_len;
4544
4545         byte_len = mono_array_element_size (class);
4546         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4547                 return FALSE;
4548         byte_len *= len;
4549         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4550                 return FALSE;
4551         byte_len += sizeof (MonoArray);
4552
4553         *res = byte_len;
4554
4555         return TRUE;
4556 }
4557
4558 /**
4559  * mono_array_new_full:
4560  * @domain: domain where the object is created
4561  * @array_class: array class
4562  * @lengths: lengths for each dimension in the array
4563  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4564  *
4565  * This routine creates a new array objects with the given dimensions,
4566  * lower bounds and type.
4567  */
4568 MonoArray*
4569 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4570 {
4571         uintptr_t byte_len, len, bounds_size;
4572         MonoObject *o;
4573         MonoArray *array;
4574         MonoArrayBounds *bounds;
4575         MonoVTable *vtable;
4576         int i;
4577
4578         if (!array_class->inited)
4579                 mono_class_init (array_class);
4580
4581         len = 1;
4582
4583         /* A single dimensional array with a 0 lower bound is the same as an szarray */
4584         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4585                 len = lengths [0];
4586                 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4587                         arith_overflow ();
4588                 bounds_size = 0;
4589         } else {
4590                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4591
4592                 for (i = 0; i < array_class->rank; ++i) {
4593                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4594                                 arith_overflow ();
4595                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4596                                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4597                         len *= lengths [i];
4598                 }
4599         }
4600
4601         if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4602                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4603
4604         if (bounds_size) {
4605                 /* align */
4606                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4607                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4608                 byte_len = (byte_len + 3) & ~3;
4609                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4610                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4611                 byte_len += bounds_size;
4612         }
4613         /* 
4614          * Following three lines almost taken from mono_object_new ():
4615          * they need to be kept in sync.
4616          */
4617         vtable = mono_class_vtable_full (domain, array_class, TRUE);
4618 #ifndef HAVE_SGEN_GC
4619         if (!array_class->has_references) {
4620                 o = mono_object_allocate_ptrfree (byte_len, vtable);
4621 #if NEED_TO_ZERO_PTRFREE
4622                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4623 #endif
4624         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4625                 o = mono_object_allocate_spec (byte_len, vtable);
4626         }else {
4627                 o = mono_object_allocate (byte_len, vtable);
4628         }
4629
4630         array = (MonoArray*)o;
4631         array->max_length = len;
4632
4633         if (bounds_size) {
4634                 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4635                 array->bounds = bounds;
4636         }
4637 #else
4638         if (bounds_size)
4639                 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4640         else
4641                 o = mono_gc_alloc_vector (vtable, byte_len, len);
4642         array = (MonoArray*)o;
4643         mono_stats.new_object_count++;
4644
4645         bounds = array->bounds;
4646 #endif
4647
4648         if (bounds_size) {
4649                 for (i = 0; i < array_class->rank; ++i) {
4650                         bounds [i].length = lengths [i];
4651                         if (lower_bounds)
4652                                 bounds [i].lower_bound = lower_bounds [i];
4653                 }
4654         }
4655
4656         if (G_UNLIKELY (profile_allocs))
4657                 mono_profiler_allocation (o, array_class);
4658
4659         return array;
4660 }
4661
4662 /**
4663  * mono_array_new:
4664  * @domain: domain where the object is created
4665  * @eclass: element class
4666  * @n: number of array elements
4667  *
4668  * This routine creates a new szarray with @n elements of type @eclass.
4669  */
4670 MonoArray *
4671 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4672 {
4673         MonoClass *ac;
4674
4675         MONO_ARCH_SAVE_REGS;
4676
4677         ac = mono_array_class_get (eclass, 1);
4678         g_assert (ac);
4679
4680         return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4681 }
4682
4683 /**
4684  * mono_array_new_specific:
4685  * @vtable: a vtable in the appropriate domain for an initialized class
4686  * @n: number of array elements
4687  *
4688  * This routine is a fast alternative to mono_array_new() for code which
4689  * can be sure about the domain it operates in.
4690  */
4691 MonoArray *
4692 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4693 {
4694         MonoObject *o;
4695         MonoArray *ao;
4696         uintptr_t byte_len;
4697
4698         MONO_ARCH_SAVE_REGS;
4699
4700         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4701                 arith_overflow ();
4702                 return NULL;
4703         }
4704
4705         if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4706                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4707                 return NULL;
4708         }
4709 #ifndef HAVE_SGEN_GC
4710         if (!vtable->klass->has_references) {
4711                 o = mono_object_allocate_ptrfree (byte_len, vtable);
4712 #if NEED_TO_ZERO_PTRFREE
4713                 ((MonoArray*)o)->bounds = NULL;
4714                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4715 #endif
4716         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4717                 o = mono_object_allocate_spec (byte_len, vtable);
4718         } else {
4719 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4720                 o = mono_object_allocate (byte_len, vtable);
4721         }
4722
4723         ao = (MonoArray *)o;
4724         ao->max_length = n;
4725 #else
4726         o = mono_gc_alloc_vector (vtable, byte_len, n);
4727         ao = (MonoArray*)o;
4728         mono_stats.new_object_count++;
4729 #endif
4730
4731         if (G_UNLIKELY (profile_allocs))
4732                 mono_profiler_allocation (o, vtable->klass);
4733
4734         return ao;
4735 }
4736
4737 /**
4738  * mono_string_new_utf16:
4739  * @text: a pointer to an utf16 string
4740  * @len: the length of the string
4741  *
4742  * Returns: A newly created string object which contains @text.
4743  */
4744 MonoString *
4745 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4746 {
4747         MonoString *s;
4748         
4749         s = mono_string_new_size (domain, len);
4750         g_assert (s != NULL);
4751
4752         memcpy (mono_string_chars (s), text, len * 2);
4753
4754         return s;
4755 }
4756
4757 /**
4758  * mono_string_new_size:
4759  * @text: a pointer to an utf16 string
4760  * @len: the length of the string
4761  *
4762  * Returns: A newly created string object of @len
4763  */
4764 MonoString *
4765 mono_string_new_size (MonoDomain *domain, gint32 len)
4766 {
4767         MonoString *s;
4768         MonoVTable *vtable;
4769         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4770
4771         /* overflow ? can't fit it, can't allocate it! */
4772         if (len > size)
4773                 mono_gc_out_of_memory (-1);
4774
4775         vtable = mono_class_vtable (domain, mono_defaults.string_class);
4776         g_assert (vtable);
4777
4778 #ifndef HAVE_SGEN_GC
4779         s = mono_object_allocate_ptrfree (size, vtable);
4780
4781         s->length = len;
4782 #else
4783         s = mono_gc_alloc_string (vtable, size, len);
4784 #endif
4785 #if NEED_TO_ZERO_PTRFREE
4786         s->chars [len] = 0;
4787 #endif
4788         if (G_UNLIKELY (profile_allocs))
4789                 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4790
4791         return s;
4792 }
4793
4794 /**
4795  * mono_string_new_len:
4796  * @text: a pointer to an utf8 string
4797  * @length: number of bytes in @text to consider
4798  *
4799  * Returns: A newly created string object which contains @text.
4800  */
4801 MonoString*
4802 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4803 {
4804         GError *error = NULL;
4805         MonoString *o = NULL;
4806         guint16 *ut;
4807         glong items_written;
4808
4809         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4810
4811         if (!error)
4812                 o = mono_string_new_utf16 (domain, ut, items_written);
4813         else 
4814                 g_error_free (error);
4815
4816         g_free (ut);
4817
4818         return o;
4819 }
4820
4821 /**
4822  * mono_string_new:
4823  * @text: a pointer to an utf8 string
4824  *
4825  * Returns: A newly created string object which contains @text.
4826  */
4827 MonoString*
4828 mono_string_new (MonoDomain *domain, const char *text)
4829 {
4830     GError *error = NULL;
4831     MonoString *o = NULL;
4832     guint16 *ut;
4833     glong items_written;
4834     int l;
4835
4836     l = strlen (text);
4837    
4838     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4839
4840     if (!error)
4841         o = mono_string_new_utf16 (domain, ut, items_written);
4842     else
4843         g_error_free (error);
4844
4845     g_free (ut);
4846 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4847 #if 0
4848         gunichar2 *str;
4849         const gchar *end;
4850         int len;
4851         MonoString *o = NULL;
4852
4853         if (!g_utf8_validate (text, -1, &end))
4854                 return NULL;
4855
4856         len = g_utf8_strlen (text, -1);
4857         o = mono_string_new_size (domain, len);
4858         str = mono_string_chars (o);
4859
4860         while (text < end) {
4861                 *str++ = g_utf8_get_char (text);
4862                 text = g_utf8_next_char (text);
4863         }
4864 #endif
4865         return o;
4866 }
4867
4868 /**
4869  * mono_string_new_wrapper:
4870  * @text: pointer to utf8 characters.
4871  *
4872  * Helper function to create a string object from @text in the current domain.
4873  */
4874 MonoString*
4875 mono_string_new_wrapper (const char *text)
4876 {
4877         MonoDomain *domain = mono_domain_get ();
4878
4879         MONO_ARCH_SAVE_REGS;
4880
4881         if (text)
4882                 return mono_string_new (domain, text);
4883
4884         return NULL;
4885 }
4886
4887 /**
4888  * mono_value_box:
4889  * @class: the class of the value
4890  * @value: a pointer to the unboxed data
4891  *
4892  * Returns: A newly created object which contains @value.
4893  */
4894 MonoObject *
4895 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4896 {
4897         MonoObject *res;
4898         int size;
4899         MonoVTable *vtable;
4900
4901         g_assert (class->valuetype);
4902         if (mono_class_is_nullable (class))
4903                 return mono_nullable_box (value, class);
4904
4905         vtable = mono_class_vtable (domain, class);
4906         if (!vtable)
4907                 return NULL;
4908         size = mono_class_instance_size (class);
4909         res = mono_object_new_alloc_specific (vtable);
4910         if (G_UNLIKELY (profile_allocs))
4911                 mono_profiler_allocation (res, class);
4912
4913         size = size - sizeof (MonoObject);
4914
4915 #ifdef HAVE_SGEN_GC
4916         g_assert (size == mono_class_value_size (class, NULL));
4917         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4918 #else
4919 #if NO_UNALIGNED_ACCESS
4920         memcpy ((char *)res + sizeof (MonoObject), value, size);
4921 #else
4922         switch (size) {
4923         case 1:
4924                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4925                 break;
4926         case 2:
4927                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4928                 break;
4929         case 4:
4930                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4931                 break;
4932         case 8:
4933                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4934                 break;
4935         default:
4936                 memcpy ((char *)res + sizeof (MonoObject), value, size);
4937         }
4938 #endif
4939 #endif
4940         if (class->has_finalize)
4941                 mono_object_register_finalizer (res);
4942         return res;
4943 }
4944
4945 /*
4946  * mono_value_copy:
4947  * @dest: destination pointer
4948  * @src: source pointer
4949  * @klass: a valuetype class
4950  *
4951  * Copy a valuetype from @src to @dest. This function must be used
4952  * when @klass contains references fields.
4953  */
4954 void
4955 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4956 {
4957         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4958 }
4959
4960 /*
4961  * mono_value_copy_array:
4962  * @dest: destination array
4963  * @dest_idx: index in the @dest array
4964  * @src: source pointer
4965  * @count: number of items
4966  *
4967  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
4968  * This function must be used when @klass contains references fields.
4969  * Overlap is handled.
4970  */
4971 void
4972 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4973 {
4974         int size = mono_array_element_size (dest->obj.vtable->klass);
4975         char *d = mono_array_addr_with_size (dest, size, dest_idx);
4976         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4977         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4978 }
4979
4980 /**
4981  * mono_object_get_domain:
4982  * @obj: object to query
4983  * 
4984  * Returns: the MonoDomain where the object is hosted
4985  */
4986 MonoDomain*
4987 mono_object_get_domain (MonoObject *obj)
4988 {
4989         return mono_object_domain (obj);
4990 }
4991
4992 /**
4993  * mono_object_get_class:
4994  * @obj: object to query
4995  * 
4996  * Returns: the MonOClass of the object.
4997  */
4998 MonoClass*
4999 mono_object_get_class (MonoObject *obj)
5000 {
5001         return mono_object_class (obj);
5002 }
5003 /**
5004  * mono_object_get_size:
5005  * @o: object to query
5006  * 
5007  * Returns: the size, in bytes, of @o
5008  */
5009 guint
5010 mono_object_get_size (MonoObject* o)
5011 {
5012         MonoClass* klass = mono_object_class (o);
5013         if (klass == mono_defaults.string_class) {
5014                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5015         } else if (o->vtable->rank) {
5016                 MonoArray *array = (MonoArray*)o;
5017                 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5018                 if (array->bounds) {
5019                         size += 3;
5020                         size &= ~3;
5021                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
5022                 }
5023                 return size;
5024         } else {
5025                 return mono_class_instance_size (klass);
5026         }
5027 }
5028
5029 /**
5030  * mono_object_unbox:
5031  * @obj: object to unbox
5032  * 
5033  * Returns: a pointer to the start of the valuetype boxed in this
5034  * object.
5035  *
5036  * This method will assert if the object passed is not a valuetype.
5037  */
5038 gpointer
5039 mono_object_unbox (MonoObject *obj)
5040 {
5041         /* add assert for valuetypes? */
5042         g_assert (obj->vtable->klass->valuetype);
5043         return ((char*)obj) + sizeof (MonoObject);
5044 }
5045
5046 /**
5047  * mono_object_isinst:
5048  * @obj: an object
5049  * @klass: a pointer to a class 
5050  *
5051  * Returns: @obj if @obj is derived from @klass
5052  */
5053 MonoObject *
5054 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5055 {
5056         if (!klass->inited)
5057                 mono_class_init (klass);
5058
5059         if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5060                 return mono_object_isinst_mbyref (obj, klass);
5061
5062         if (!obj)
5063                 return NULL;
5064
5065         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5066 }
5067
5068 MonoObject *
5069 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5070 {
5071         MonoVTable *vt;
5072
5073         if (!obj)
5074                 return NULL;
5075
5076         vt = obj->vtable;
5077         
5078         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5079                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5080                         return obj;
5081                 }
5082
5083                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5084                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5085                         return obj;
5086         } else {
5087                 MonoClass *oklass = vt->klass;
5088                 if ((oklass == mono_defaults.transparent_proxy_class))
5089                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5090         
5091                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5092                         return obj;
5093         }
5094
5095         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5096         {
5097                 MonoDomain *domain = mono_domain_get ();
5098                 MonoObject *res;
5099                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5100                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5101                 MonoMethod *im = NULL;
5102                 gpointer pa [2];
5103
5104                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5105                 im = mono_object_get_virtual_method (rp, im);
5106                 g_assert (im);
5107         
5108                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5109                 pa [1] = obj;
5110
5111                 res = mono_runtime_invoke (im, rp, pa, NULL);
5112         
5113                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5114                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5115                         mono_upgrade_remote_class (domain, obj, klass);
5116                         return obj;
5117                 }
5118         }
5119
5120         return NULL;
5121 }
5122
5123 /**
5124  * mono_object_castclass_mbyref:
5125  * @obj: an object
5126  * @klass: a pointer to a class 
5127  *
5128  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5129  */
5130 MonoObject *
5131 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5132 {
5133         if (!obj) return NULL;
5134         if (mono_object_isinst_mbyref (obj, klass)) return obj;
5135                 
5136         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5137                                                         "System",
5138                                                         "InvalidCastException"));
5139         return NULL;
5140 }
5141
5142 typedef struct {
5143         MonoDomain *orig_domain;
5144         MonoString *ins;
5145         MonoString *res;
5146 } LDStrInfo;
5147
5148 static void
5149 str_lookup (MonoDomain *domain, gpointer user_data)
5150 {
5151         LDStrInfo *info = user_data;
5152         if (info->res || domain == info->orig_domain)
5153                 return;
5154         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5155 }
5156
5157 #ifdef HAVE_SGEN_GC
5158
5159 static MonoString*
5160 mono_string_get_pinned (MonoString *str)
5161 {
5162         int size;
5163         MonoString *news;
5164         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5165         news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5166         if (news) {
5167                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5168                 news->length = mono_string_length (str);
5169         }
5170         return news;
5171 }
5172
5173 #else
5174 #define mono_string_get_pinned(str) (str)
5175 #endif
5176
5177 static MonoString*
5178 mono_string_is_interned_lookup (MonoString *str, int insert)
5179 {
5180         MonoGHashTable *ldstr_table;
5181         MonoString *res;
5182         MonoDomain *domain;
5183         
5184         domain = ((MonoObject *)str)->vtable->domain;
5185         ldstr_table = domain->ldstr_table;
5186         ldstr_lock ();
5187         if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5188                 ldstr_unlock ();
5189                 return res;
5190         }
5191         if (insert) {
5192                 str = mono_string_get_pinned (str);
5193                 if (str)
5194                         mono_g_hash_table_insert (ldstr_table, str, str);
5195                 ldstr_unlock ();
5196                 return str;
5197         } else {
5198                 LDStrInfo ldstr_info;
5199                 ldstr_info.orig_domain = domain;
5200                 ldstr_info.ins = str;
5201                 ldstr_info.res = NULL;
5202
5203                 mono_domain_foreach (str_lookup, &ldstr_info);
5204                 if (ldstr_info.res) {
5205                         /* 
5206                          * the string was already interned in some other domain:
5207                          * intern it in the current one as well.
5208                          */
5209                         mono_g_hash_table_insert (ldstr_table, str, str);
5210                         ldstr_unlock ();
5211                         return str;
5212                 }
5213         }
5214         ldstr_unlock ();
5215         return NULL;
5216 }
5217
5218 /**
5219  * mono_string_is_interned:
5220  * @o: String to probe
5221  *
5222  * Returns whether the string has been interned.
5223  */
5224 MonoString*
5225 mono_string_is_interned (MonoString *o)
5226 {
5227         return mono_string_is_interned_lookup (o, FALSE);
5228 }
5229
5230 /**
5231  * mono_string_intern:
5232  * @o: String to intern
5233  *
5234  * Interns the string passed.  
5235  * Returns: The interned string.
5236  */
5237 MonoString*
5238 mono_string_intern (MonoString *str)
5239 {
5240         return mono_string_is_interned_lookup (str, TRUE);
5241 }
5242
5243 /**
5244  * mono_ldstr:
5245  * @domain: the domain where the string will be used.
5246  * @image: a metadata context
5247  * @idx: index into the user string table.
5248  * 
5249  * Implementation for the ldstr opcode.
5250  * Returns: a loaded string from the @image/@idx combination.
5251  */
5252 MonoString*
5253 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5254 {
5255         MONO_ARCH_SAVE_REGS;
5256
5257         if (image->dynamic) {
5258                 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5259                 return str;
5260         } else {
5261                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5262                         return NULL; /*FIXME we should probably be raising an exception here*/
5263                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5264         }
5265 }
5266
5267 /**
5268  * mono_ldstr_metadata_sig
5269  * @domain: the domain for the string
5270  * @sig: the signature of a metadata string
5271  *
5272  * Returns: a MonoString for a string stored in the metadata
5273  */
5274 static MonoString*
5275 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5276 {
5277         const char *str = sig;
5278         MonoString *o, *interned;
5279         size_t len2;
5280
5281         len2 = mono_metadata_decode_blob_size (str, &str);
5282         len2 >>= 1;
5283
5284         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5285 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5286         {
5287                 int i;
5288                 guint16 *p2 = (guint16*)mono_string_chars (o);
5289                 for (i = 0; i < len2; ++i) {
5290                         *p2 = GUINT16_FROM_LE (*p2);
5291                         ++p2;
5292                 }
5293         }
5294 #endif
5295         ldstr_lock ();
5296         if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5297                 ldstr_unlock ();
5298                 /* o will get garbage collected */
5299                 return interned;
5300         }
5301
5302         o = mono_string_get_pinned (o);
5303         if (o)
5304                 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5305         ldstr_unlock ();
5306
5307         return o;
5308 }
5309
5310 /**
5311  * mono_string_to_utf8:
5312  * @s: a System.String
5313  *
5314  * Returns the UTF8 representation for @s.
5315  * The resulting buffer needs to be freed with mono_free().
5316  *
5317  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5318  */
5319 char *
5320 mono_string_to_utf8 (MonoString *s)
5321 {
5322         MonoError error;
5323         char *result = mono_string_to_utf8_checked (s, &error);
5324         
5325         if (!mono_error_ok (&error))
5326                 mono_error_raise_exception (&error);
5327         return result;
5328 }
5329
5330 /**
5331  * mono_string_to_utf8_checked:
5332  * @s: a System.String
5333  * @error: a MonoError.
5334  * 
5335  * Converts a MonoString to its UTF8 representation. May fail; check 
5336  * @error to determine whether the conversion was successful.
5337  * The resulting buffer should be freed with mono_free().
5338  */
5339 char *
5340 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5341 {
5342         long written = 0;
5343         char *as;
5344         GError *gerror = NULL;
5345
5346         mono_error_init (error);
5347
5348         if (s == NULL)
5349                 return NULL;
5350
5351         if (!s->length)
5352                 return g_strdup ("");
5353
5354         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5355         if (gerror) {
5356                 mono_error_set_argument (error, "string", "%s", gerror->message);
5357                 g_error_free (gerror);
5358                 return NULL;
5359         }
5360         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5361         if (s->length > written) {
5362                 /* allocate the total length and copy the part of the string that has been converted */
5363                 char *as2 = g_malloc0 (s->length);
5364                 memcpy (as2, as, written);
5365                 g_free (as);
5366                 as = as2;
5367         }
5368
5369         return as;
5370 }
5371
5372 /**
5373  * mono_string_to_utf16:
5374  * @s: a MonoString
5375  *
5376  * Return an null-terminated array of the utf-16 chars
5377  * contained in @s. The result must be freed with g_free().
5378  * This is a temporary helper until our string implementation
5379  * is reworked to always include the null terminating char.
5380  */
5381 mono_unichar2*
5382 mono_string_to_utf16 (MonoString *s)
5383 {
5384         char *as;
5385
5386         if (s == NULL)
5387                 return NULL;
5388
5389         as = g_malloc ((s->length * 2) + 2);
5390         as [(s->length * 2)] = '\0';
5391         as [(s->length * 2) + 1] = '\0';
5392
5393         if (!s->length) {
5394                 return (gunichar2 *)(as);
5395         }
5396         
5397         memcpy (as, mono_string_chars(s), s->length * 2);
5398         return (gunichar2 *)(as);
5399 }
5400
5401 /**
5402  * mono_string_from_utf16:
5403  * @data: the UTF16 string (LPWSTR) to convert
5404  *
5405  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5406  *
5407  * Returns: a MonoString.
5408  */
5409 MonoString *
5410 mono_string_from_utf16 (gunichar2 *data)
5411 {
5412         MonoDomain *domain = mono_domain_get ();
5413         int len = 0;
5414
5415         if (!data)
5416                 return NULL;
5417
5418         while (data [len]) len++;
5419
5420         return mono_string_new_utf16 (domain, data, len);
5421 }
5422
5423
5424 static char *
5425 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5426 {
5427         char *r;
5428         char *mp_s;
5429         int len;
5430
5431         r = mono_string_to_utf8_checked (s, error);
5432         if (!mono_error_ok (error))
5433                 return NULL;
5434
5435         if (!mp && !image)
5436                 return r;
5437
5438         len = strlen (r) + 1;
5439         if (mp)
5440                 mp_s = mono_mempool_alloc (mp, len);
5441         else
5442                 mp_s = mono_image_alloc (image, len);
5443
5444         memcpy (mp_s, r, len);
5445
5446         g_free (r);
5447
5448         return mp_s;
5449 }
5450
5451 /**
5452  * mono_string_to_utf8_image:
5453  * @s: a System.String
5454  *
5455  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5456  */
5457 char *
5458 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5459 {
5460         return mono_string_to_utf8_internal (NULL, image, s, error);
5461 }
5462
5463 /**
5464  * mono_string_to_utf8_mp:
5465  * @s: a System.String
5466  *
5467  * Same as mono_string_to_utf8, but allocate the string from a mempool.
5468  */
5469 char *
5470 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5471 {
5472         return mono_string_to_utf8_internal (mp, NULL, s, error);
5473 }
5474
5475 static void
5476 default_ex_handler (MonoException *ex)
5477 {
5478         MonoObject *o = (MonoObject*)ex;
5479         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5480         exit (1);
5481 }
5482
5483 static MonoExceptionFunc ex_handler = default_ex_handler;
5484
5485 /**
5486  * mono_install_handler:
5487  * @func: exception handler
5488  *
5489  * This is an internal JIT routine used to install the handler for exceptions
5490  * being throwh.
5491  */
5492 void
5493 mono_install_handler (MonoExceptionFunc func)
5494 {
5495         ex_handler = func? func: default_ex_handler;
5496 }
5497
5498 /**
5499  * mono_raise_exception:
5500  * @ex: exception object
5501  *
5502  * Signal the runtime that the exception @ex has been raised in unmanaged code.
5503  */
5504 void
5505 mono_raise_exception (MonoException *ex) 
5506 {
5507         /*
5508          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5509          * that will cause gcc to omit the function epilog, causing problems when
5510          * the JIT tries to walk the stack, since the return address on the stack
5511          * will point into the next function in the executable, not this one.
5512          */
5513
5514         if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5515                 MonoInternalThread *thread = mono_thread_internal_current ();
5516                 g_assert (ex->object.vtable->domain == mono_domain_get ());
5517                 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5518         }
5519         
5520         ex_handler (ex);
5521 }
5522
5523 /**
5524  * mono_wait_handle_new:
5525  * @domain: Domain where the object will be created
5526  * @handle: Handle for the wait handle
5527  *
5528  * Returns: A new MonoWaitHandle created in the given domain for the given handle
5529  */
5530 MonoWaitHandle *
5531 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5532 {
5533         MonoWaitHandle *res;
5534         gpointer params [1];
5535         static MonoMethod *handle_set;
5536
5537         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5538
5539         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
5540         if (!handle_set)
5541                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5542
5543         params [0] = &handle;
5544         mono_runtime_invoke (handle_set, res, params, NULL);
5545
5546         return res;
5547 }
5548
5549 HANDLE
5550 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5551 {
5552         static MonoClassField *f_os_handle;
5553         static MonoClassField *f_safe_handle;
5554
5555         if (!f_os_handle && !f_safe_handle) {
5556                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5557                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5558         }
5559
5560         if (f_os_handle) {
5561                 HANDLE retval;
5562                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5563                 return retval;
5564         } else {
5565                 MonoSafeHandle *sh;
5566                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5567                 return sh->handle;
5568         }
5569 }
5570
5571
5572 static MonoObject*
5573 mono_runtime_capture_context (MonoDomain *domain)
5574 {
5575         RuntimeInvokeFunction runtime_invoke;
5576
5577         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5578                 MonoMethod *method = mono_get_context_capture_method ();
5579                 MonoMethod *wrapper;
5580                 if (!method)
5581                         return NULL;
5582                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5583                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5584                 domain->capture_context_method = mono_compile_method (method);
5585         }
5586
5587         runtime_invoke = domain->capture_context_runtime_invoke;
5588
5589         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5590 }
5591 /**
5592  * mono_async_result_new:
5593  * @domain:domain where the object will be created.
5594  * @handle: wait handle.
5595  * @state: state to pass to AsyncResult
5596  * @data: C closure data.
5597  *
5598  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5599  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5600  *
5601  */
5602 MonoAsyncResult *
5603 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5604 {
5605         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5606         MonoObject *context = mono_runtime_capture_context (domain);
5607         /* we must capture the execution context from the original thread */
5608         if (context) {
5609                 MONO_OBJECT_SETREF (res, execution_context, context);
5610                 /* note: result may be null if the flow is suppressed */
5611         }
5612
5613         res->data = data;
5614         MONO_OBJECT_SETREF (res, object_data, object_data);
5615         MONO_OBJECT_SETREF (res, async_state, state);
5616         if (handle != NULL)
5617                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5618
5619         res->sync_completed = FALSE;
5620         res->completed = FALSE;
5621
5622         return res;
5623 }
5624
5625 void
5626 mono_message_init (MonoDomain *domain,
5627                    MonoMethodMessage *this, 
5628                    MonoReflectionMethod *method,
5629                    MonoArray *out_args)
5630 {
5631         static MonoClass *object_array_klass;
5632         static MonoClass *byte_array_klass;
5633         static MonoClass *string_array_klass;
5634         MonoMethodSignature *sig = mono_method_signature (method->method);
5635         MonoString *name;
5636         int i, j;
5637         char **names;
5638         guint8 arg_type;
5639
5640         if (!object_array_klass) {
5641                 MonoClass *klass;
5642
5643                 klass = mono_array_class_get (mono_defaults.object_class, 1);
5644                 g_assert (klass);
5645
5646                 mono_memory_barrier ();
5647                 object_array_klass = klass;
5648
5649                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5650                 g_assert (klass);
5651
5652                 mono_memory_barrier ();
5653                 byte_array_klass = klass;
5654
5655                 klass = mono_array_class_get (mono_defaults.string_class, 1);
5656                 g_assert (klass);
5657
5658                 mono_memory_barrier ();
5659                 string_array_klass = klass;
5660         }
5661
5662         MONO_OBJECT_SETREF (this, method, method);
5663
5664         MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5665         MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5666         this->async_result = NULL;
5667         this->call_type = CallType_Sync;
5668
5669         names = g_new (char *, sig->param_count);
5670         mono_method_get_param_names (method->method, (const char **) names);
5671         MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5672         
5673         for (i = 0; i < sig->param_count; i++) {
5674                 name = mono_string_new (domain, names [i]);
5675                 mono_array_setref (this->names, i, name);       
5676         }
5677
5678         g_free (names);
5679         for (i = 0, j = 0; i < sig->param_count; i++) {
5680                 if (sig->params [i]->byref) {
5681                         if (out_args) {
5682                                 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5683                                 mono_array_setref (this->args, i, arg);
5684                                 j++;
5685                         }
5686                         arg_type = 2;
5687                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5688                                 arg_type |= 1;
5689                 } else {
5690                         arg_type = 1;
5691                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5692                                 arg_type |= 4;
5693                 }
5694                 mono_array_set (this->arg_types, guint8, i, arg_type);
5695         }
5696 }
5697
5698 /**
5699  * mono_remoting_invoke:
5700  * @real_proxy: pointer to a RealProxy object
5701  * @msg: The MonoMethodMessage to execute
5702  * @exc: used to store exceptions
5703  * @out_args: used to store output arguments
5704  *
5705  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5706  * IMessage interface and it is not trivial to extract results from there. So
5707  * we call an helper method PrivateInvoke instead of calling
5708  * RealProxy::Invoke() directly.
5709  *
5710  * Returns: the result object.
5711  */
5712 MonoObject *
5713 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
5714                       MonoObject **exc, MonoArray **out_args)
5715 {
5716         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5717         gpointer pa [4];
5718
5719         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5720
5721         if (!im) {
5722                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5723                 g_assert (im);
5724                 real_proxy->vtable->domain->private_invoke_method = im;
5725         }
5726
5727         pa [0] = real_proxy;
5728         pa [1] = msg;
5729         pa [2] = exc;
5730         pa [3] = out_args;
5731
5732         return mono_runtime_invoke (im, NULL, pa, exc);
5733 }
5734
5735 MonoObject *
5736 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
5737                      MonoObject **exc, MonoArray **out_args) 
5738 {
5739         static MonoClass *object_array_klass;
5740         MonoDomain *domain; 
5741         MonoMethod *method;
5742         MonoMethodSignature *sig;
5743         MonoObject *ret;
5744         int i, j, outarg_count = 0;
5745
5746         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5747
5748                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5749                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5750                         target = tp->rp->unwrapped_server;
5751                 } else {
5752                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5753                 }
5754         }
5755
5756         domain = mono_domain_get (); 
5757         method = msg->method->method;
5758         sig = mono_method_signature (method);
5759
5760         for (i = 0; i < sig->param_count; i++) {
5761                 if (sig->params [i]->byref) 
5762                         outarg_count++;
5763         }
5764
5765         if (!object_array_klass) {
5766                 MonoClass *klass;
5767
5768                 klass = mono_array_class_get (mono_defaults.object_class, 1);
5769                 g_assert (klass);
5770
5771                 mono_memory_barrier ();
5772                 object_array_klass = klass;
5773         }
5774
5775         /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5776         *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5777         *exc = NULL;
5778
5779         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5780
5781         for (i = 0, j = 0; i < sig->param_count; i++) {
5782                 if (sig->params [i]->byref) {
5783                         MonoObject* arg;
5784                         arg = mono_array_get (msg->args, gpointer, i);
5785                         mono_array_setref (*out_args, j, arg);
5786                         j++;
5787                 }
5788         }
5789
5790         return ret;
5791 }
5792
5793 /**
5794  * mono_object_to_string:
5795  * @obj: The object
5796  * @exc: Any exception thrown by ToString (). May be NULL.
5797  *
5798  * Returns: the result of calling ToString () on an object.
5799  */
5800 MonoString *
5801 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5802 {
5803         static MonoMethod *to_string = NULL;
5804         MonoMethod *method;
5805
5806         g_assert (obj);
5807
5808         if (!to_string)
5809                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5810
5811         method = mono_object_get_virtual_method (obj, to_string);
5812
5813         return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5814 }
5815
5816 /**
5817  * mono_print_unhandled_exception:
5818  * @exc: The exception
5819  *
5820  * Prints the unhandled exception.
5821  */
5822 void
5823 mono_print_unhandled_exception (MonoObject *exc)
5824 {
5825         MonoString * str;
5826         char *message = (char*)"";
5827         gboolean free_message = FALSE;
5828         MonoError error;
5829
5830         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5831                 message = g_strdup ("OutOfMemoryException");
5832         } else {
5833                 str = mono_object_to_string (exc, NULL);
5834                 if (str) {
5835                         message = mono_string_to_utf8_checked (str, &error);
5836                         if (!mono_error_ok (&error)) {
5837                                 mono_error_cleanup (&error);
5838                                 message = (char *) "";
5839                         } else {
5840                                 free_message = TRUE;
5841                         }
5842                 }
5843         }
5844
5845         /*
5846          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
5847          *         exc->vtable->klass->name, message);
5848          */
5849         g_printerr ("\nUnhandled Exception: %s\n", message);
5850         
5851         if (free_message)
5852                 g_free (message);
5853 }
5854
5855 /**
5856  * mono_delegate_ctor:
5857  * @this: pointer to an uninitialized delegate object
5858  * @target: target object
5859  * @addr: pointer to native code
5860  * @method: method
5861  *
5862  * Initialize a delegate and sets a specific method, not the one
5863  * associated with addr.  This is useful when sharing generic code.
5864  * In that case addr will most probably not be associated with the
5865  * correct instantiation of the method.
5866  */
5867 void
5868 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5869 {
5870         MonoDelegate *delegate = (MonoDelegate *)this;
5871         MonoClass *class;
5872
5873         g_assert (this);
5874         g_assert (addr);
5875
5876         if (method)
5877                 delegate->method = method;
5878
5879         class = this->vtable->klass;
5880         mono_stats.delegate_creations++;
5881
5882         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5883                 g_assert (method);
5884                 method = mono_marshal_get_remoting_invoke (method);
5885                 delegate->method_ptr = mono_compile_method (method);
5886                 MONO_OBJECT_SETREF (delegate, target, target);
5887         } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5888                 method = mono_marshal_get_unbox_wrapper (method);
5889                 delegate->method_ptr = mono_compile_method (method);
5890                 MONO_OBJECT_SETREF (delegate, target, target);
5891         } else {
5892                 delegate->method_ptr = addr;
5893                 MONO_OBJECT_SETREF (delegate, target, target);
5894         }
5895
5896         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5897 }
5898
5899 /**
5900  * mono_delegate_ctor:
5901  * @this: pointer to an uninitialized delegate object
5902  * @target: target object
5903  * @addr: pointer to native code
5904  *
5905  * This is used to initialize a delegate.
5906  */
5907 void
5908 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5909 {
5910         MonoDomain *domain = mono_domain_get ();
5911         MonoJitInfo *ji;
5912         MonoMethod *method = NULL;
5913
5914         g_assert (addr);
5915
5916         if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5917                 method = ji->method;
5918                 g_assert (!method->klass->generic_container);
5919         }
5920
5921         mono_delegate_ctor_with_method (this, target, addr, method);
5922 }
5923
5924 /**
5925  * mono_method_call_message_new:
5926  * @method: method to encapsulate
5927  * @params: parameters to the method
5928  * @invoke: optional, delegate invoke.
5929  * @cb: async callback delegate.
5930  * @state: state passed to the async callback.
5931  *
5932  * Translates arguments pointers into a MonoMethodMessage.
5933  */
5934 MonoMethodMessage *
5935 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
5936                               MonoDelegate **cb, MonoObject **state)
5937 {
5938         MonoDomain *domain = mono_domain_get ();
5939         MonoMethodSignature *sig = mono_method_signature (method);
5940         MonoMethodMessage *msg;
5941         int i, count, type;
5942
5943         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
5944         
5945         if (invoke) {
5946                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5947                 count =  sig->param_count - 2;
5948         } else {
5949                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5950                 count =  sig->param_count;
5951         }
5952
5953         for (i = 0; i < count; i++) {
5954                 gpointer vpos;
5955                 MonoClass *class;
5956                 MonoObject *arg;
5957
5958                 if (sig->params [i]->byref)
5959                         vpos = *((gpointer *)params [i]);
5960                 else 
5961                         vpos = params [i];
5962
5963                 type = sig->params [i]->type;
5964                 class = mono_class_from_mono_type (sig->params [i]);
5965
5966                 if (class->valuetype)
5967                         arg = mono_value_box (domain, class, vpos);
5968                 else 
5969                         arg = *((MonoObject **)vpos);
5970                       
5971                 mono_array_setref (msg->args, i, arg);
5972         }
5973
5974         if (cb != NULL && state != NULL) {
5975                 *cb = *((MonoDelegate **)params [i]);
5976                 i++;
5977                 *state = *((MonoObject **)params [i]);
5978         }
5979
5980         return msg;
5981 }
5982
5983 /**
5984  * mono_method_return_message_restore:
5985  *
5986  * Restore results from message based processing back to arguments pointers
5987  */
5988 void
5989 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5990 {
5991         MonoMethodSignature *sig = mono_method_signature (method);
5992         int i, j, type, size, out_len;
5993         
5994         if (out_args == NULL)
5995                 return;
5996         out_len = mono_array_length (out_args);
5997         if (out_len == 0)
5998                 return;
5999
6000         for (i = 0, j = 0; i < sig->param_count; i++) {
6001                 MonoType *pt = sig->params [i];
6002
6003                 if (pt->byref) {
6004                         char *arg;
6005                         if (j >= out_len)
6006                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6007
6008                         arg = mono_array_get (out_args, gpointer, j);
6009                         type = pt->type;
6010
6011                         g_assert (type != MONO_TYPE_VOID);
6012
6013                         if (MONO_TYPE_IS_REFERENCE (pt)) {
6014                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6015                         } else {
6016                                 if (arg) {
6017                                         MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6018                                         size = mono_class_value_size (class, NULL);
6019                                         if (class->has_references)
6020                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6021                                         else
6022                                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6023                                 } else {
6024                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6025                                         memset (*((gpointer *)params [i]), 0, size);
6026                                 }
6027                         }
6028
6029                         j++;
6030                 }
6031         }
6032 }
6033
6034 /**
6035  * mono_load_remote_field:
6036  * @this: pointer to an object
6037  * @klass: klass of the object containing @field
6038  * @field: the field to load
6039  * @res: a storage to store the result
6040  *
6041  * This method is called by the runtime on attempts to load fields of
6042  * transparent proxy objects. @this points to such TP, @klass is the class of
6043  * the object containing @field. @res is a storage location which can be
6044  * used to store the result.
6045  *
6046  * Returns: an address pointing to the value of field.
6047  */
6048 gpointer
6049 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6050 {
6051         static MonoMethod *getter = NULL;
6052         MonoDomain *domain = mono_domain_get ();
6053         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6054         MonoClass *field_class;
6055         MonoMethodMessage *msg;
6056         MonoArray *out_args;
6057         MonoObject *exc;
6058         char* full_name;
6059
6060         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6061         g_assert (res != NULL);
6062
6063         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6064                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6065                 return res;
6066         }
6067         
6068         if (!getter) {
6069                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6070                 g_assert (getter);
6071         }
6072         
6073         field_class = mono_class_from_mono_type (field->type);
6074
6075         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6076         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6077         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6078
6079         full_name = mono_type_get_full_name (klass);
6080         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6081         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6082         g_free (full_name);
6083
6084         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6085
6086         if (exc) mono_raise_exception ((MonoException *)exc);
6087
6088         if (mono_array_length (out_args) == 0)
6089                 return NULL;
6090
6091         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6092
6093         if (field_class->valuetype) {
6094                 return ((char *)*res) + sizeof (MonoObject);
6095         } else
6096                 return res;
6097 }
6098
6099 /**
6100  * mono_load_remote_field_new:
6101  * @this: 
6102  * @klass: 
6103  * @field:
6104  *
6105  * Missing documentation.
6106  */
6107 MonoObject *
6108 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6109 {
6110         static MonoMethod *getter = NULL;
6111         MonoDomain *domain = mono_domain_get ();
6112         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6113         MonoClass *field_class;
6114         MonoMethodMessage *msg;
6115         MonoArray *out_args;
6116         MonoObject *exc, *res;
6117         char* full_name;
6118
6119         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6120
6121         field_class = mono_class_from_mono_type (field->type);
6122
6123         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6124                 gpointer val;
6125                 if (field_class->valuetype) {
6126                         res = mono_object_new (domain, field_class);
6127                         val = ((gchar *) res) + sizeof (MonoObject);
6128                 } else {
6129                         val = &res;
6130                 }
6131                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6132                 return res;
6133         }
6134
6135         if (!getter) {
6136                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6137                 g_assert (getter);
6138         }
6139         
6140         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6141         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6142
6143         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6144
6145         full_name = mono_type_get_full_name (klass);
6146         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6147         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6148         g_free (full_name);
6149
6150         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6151
6152         if (exc) mono_raise_exception ((MonoException *)exc);
6153
6154         if (mono_array_length (out_args) == 0)
6155                 res = NULL;
6156         else
6157                 res = mono_array_get (out_args, MonoObject *, 0);
6158
6159         return res;
6160 }
6161
6162 /**
6163  * mono_store_remote_field:
6164  * @this: pointer to an object
6165  * @klass: klass of the object containing @field
6166  * @field: the field to load
6167  * @val: the value/object to store
6168  *
6169  * This method is called by the runtime on attempts to store fields of
6170  * transparent proxy objects. @this points to such TP, @klass is the class of
6171  * the object containing @field. @val is the new value to store in @field.
6172  */
6173 void
6174 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6175 {
6176         static MonoMethod *setter = NULL;
6177         MonoDomain *domain = mono_domain_get ();
6178         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6179         MonoClass *field_class;
6180         MonoMethodMessage *msg;
6181         MonoArray *out_args;
6182         MonoObject *exc;
6183         MonoObject *arg;
6184         char* full_name;
6185
6186         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6187
6188         field_class = mono_class_from_mono_type (field->type);
6189
6190         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6191                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6192                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6193                 return;
6194         }
6195
6196         if (!setter) {
6197                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6198                 g_assert (setter);
6199         }
6200
6201         if (field_class->valuetype)
6202                 arg = mono_value_box (domain, field_class, val);
6203         else 
6204                 arg = *((MonoObject **)val);
6205                 
6206
6207         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6208         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6209
6210         full_name = mono_type_get_full_name (klass);
6211         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6212         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6213         mono_array_setref (msg->args, 2, arg);
6214         g_free (full_name);
6215
6216         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6217
6218         if (exc) mono_raise_exception ((MonoException *)exc);
6219 }
6220
6221 /**
6222  * mono_store_remote_field_new:
6223  * @this:
6224  * @klass:
6225  * @field:
6226  * @arg:
6227  *
6228  * Missing documentation
6229  */
6230 void
6231 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6232 {
6233         static MonoMethod *setter = NULL;
6234         MonoDomain *domain = mono_domain_get ();
6235         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6236         MonoClass *field_class;
6237         MonoMethodMessage *msg;
6238         MonoArray *out_args;
6239         MonoObject *exc;
6240         char* full_name;
6241
6242         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6243
6244         field_class = mono_class_from_mono_type (field->type);
6245
6246         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6247                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6248                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6249                 return;
6250         }
6251
6252         if (!setter) {
6253                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6254                 g_assert (setter);
6255         }
6256
6257         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6258         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6259
6260         full_name = mono_type_get_full_name (klass);
6261         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6262         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6263         mono_array_setref (msg->args, 2, arg);
6264         g_free (full_name);
6265
6266         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6267
6268         if (exc) mono_raise_exception ((MonoException *)exc);
6269 }
6270
6271 /*
6272  * mono_create_ftnptr:
6273  *
6274  *   Given a function address, create a function descriptor for it.
6275  * This is only needed on some platforms.
6276  */
6277 gpointer
6278 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6279 {
6280         return callbacks.create_ftnptr (domain, addr);
6281 }
6282
6283 /*
6284  * mono_get_addr_from_ftnptr:
6285  *
6286  *   Given a pointer to a function descriptor, return the function address.
6287  * This is only needed on some platforms.
6288  */
6289 gpointer
6290 mono_get_addr_from_ftnptr (gpointer descr)
6291 {
6292         return callbacks.get_addr_from_ftnptr (descr);
6293 }       
6294
6295 /**
6296  * mono_string_chars:
6297  * @s: a MonoString
6298  *
6299  * Returns a pointer to the UCS16 characters stored in the MonoString
6300  */
6301 gunichar2 *
6302 mono_string_chars (MonoString *s)
6303 {
6304         return s->chars;
6305 }
6306
6307 /**
6308  * mono_string_length:
6309  * @s: MonoString
6310  *
6311  * Returns the lenght in characters of the string
6312  */
6313 int
6314 mono_string_length (MonoString *s)
6315 {
6316         return s->length;
6317 }
6318
6319 /**
6320  * mono_array_length:
6321  * @array: a MonoArray*
6322  *
6323  * Returns the total number of elements in the array. This works for
6324  * both vectors and multidimensional arrays.
6325  */
6326 uintptr_t
6327 mono_array_length (MonoArray *array)
6328 {
6329         return array->max_length;
6330 }
6331
6332 /**
6333  * mono_array_addr_with_size:
6334  * @array: a MonoArray*
6335  * @size: size of the array elements
6336  * @idx: index into the array
6337  *
6338  * Returns the address of the @idx element in the array.
6339  */
6340 char*
6341 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6342 {
6343         return ((char*)(array)->vector) + size * idx;
6344 }
6345