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