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