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