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