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