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