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