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