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