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