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