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