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