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