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