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