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