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