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