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