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