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