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