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