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