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