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