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