2007-04-06 Andreas Faerber <andreas.faerber@web.de>
[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  * (C) 2001-2004 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include "mono/metadata/security-manager.h"
35 #include "mono/metadata/mono-debug-debugger.h"
36 #include <mono/os/gc_wrapper.h>
37 #include <mono/utils/strenc.h>
38
39 #ifdef HAVE_BOEHM_GC
40 #define NEED_TO_ZERO_PTRFREE 1
41 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
42 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
43 #ifdef HAVE_GC_GCJ_MALLOC
44 #define CREATION_SPEEDUP 1
45 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
46 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
47 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
48 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
49 #else
50 #define GC_NO_DESCRIPTOR (NULL)
51 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
52 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
53 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
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 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
62 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
63 #else
64 #define NEED_TO_ZERO_PTRFREE 1
65 #define GC_NO_DESCRIPTOR (NULL)
66 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
67 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
68 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
69 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
70 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
71 #endif
72 #endif
73
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
76
77 static void
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
79
80 static MonoString*
81 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
82
83 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
84 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
85 static CRITICAL_SECTION ldstr_section;
86
87 void
88 mono_runtime_object_init (MonoObject *this)
89 {
90         MonoMethod *method = NULL;
91         MonoClass *klass = this->vtable->klass;
92
93         method = mono_class_get_method_from_name (klass, ".ctor", 0);
94         g_assert (method);
95
96         if (method->klass->valuetype)
97                 this = mono_object_unbox (this);
98         mono_runtime_invoke (method, this, NULL, NULL);
99 }
100
101 /* The pseudo algorithm for type initialization from the spec
102 Note it doesn't say anything about domains - only threads.
103
104 2. If the type is initialized you are done.
105 2.1. If the type is not yet initialized, try to take an 
106      initialization lock.  
107 2.2. If successful, record this thread as responsible for 
108      initializing the type and proceed to step 2.3.
109 2.2.1. If not, see whether this thread or any thread 
110      waiting for this thread to complete already holds the lock.
111 2.2.2. If so, return since blocking would create a deadlock.  This thread 
112      will now see an incompletely initialized state for the type, 
113      but no deadlock will arise.
114 2.2.3  If not, block until the type is initialized then return.
115 2.3 Initialize the parent type and then all interfaces implemented 
116     by this type.
117 2.4 Execute the type initialization code for this type.
118 2.5 Mark the type as initialized, release the initialization lock, 
119     awaken any threads waiting for this type to be initialized, 
120     and return.
121
122 */
123
124 typedef struct
125 {
126         guint32 initializing_tid;
127         guint32 waiting_count;
128         gboolean done;
129         CRITICAL_SECTION initialization_section;
130 } TypeInitializationLock;
131
132 /* for locking access to type_initialization_hash and blocked_thread_hash */
133 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
134 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
135 static CRITICAL_SECTION type_initialization_section;
136
137 /* from vtable to lock */
138 static GHashTable *type_initialization_hash;
139
140 /* from thread id to thread id being waited on */
141 static GHashTable *blocked_thread_hash;
142
143 /* Main thread */
144 static MonoThread *main_thread;
145
146 /**
147  * mono_thread_set_main:
148  * @thread: thread to set as the main thread
149  *
150  * This function can be used to instruct the runtime to treat @thread
151  * as the main thread, ie, the thread that would normally execute the Main()
152  * method. This basically means that at the end of @thread, the runtime will
153  * wait for the existing foreground threads to quit and other such details.
154  */
155 void
156 mono_thread_set_main (MonoThread *thread)
157 {
158         main_thread = thread;
159 }
160
161 MonoThread*
162 mono_thread_get_main (void)
163 {
164         return main_thread;
165 }
166
167 void
168 mono_type_initialization_init (void)
169 {
170         InitializeCriticalSection (&type_initialization_section);
171         type_initialization_hash = g_hash_table_new (NULL, NULL);
172         blocked_thread_hash = g_hash_table_new (NULL, NULL);
173         InitializeCriticalSection (&ldstr_section);
174 }
175
176 void
177 mono_type_initialization_cleanup (void)
178 {
179 #if 0
180         /* This is causing race conditions with
181          * mono_release_type_locks
182          */
183         DeleteCriticalSection (&type_initialization_section);
184 #endif
185         DeleteCriticalSection (&ldstr_section);
186 }
187
188 /**
189  * get_type_init_exception_for_vtable:
190  *
191  *   Return the stored type initialization exception for VTABLE.
192  */
193 static MonoException*
194 get_type_init_exception_for_vtable (MonoVTable *vtable)
195 {
196         MonoDomain *domain = vtable->domain;
197         MonoClass *klass = vtable->klass;
198         MonoException *ex;
199         gchar *full_name;
200
201         g_assert (vtable->init_failed);
202
203         /* 
204          * If the initializing thread was rudely aborted, the exception is not stored
205          * in the hash.
206          */
207         ex = NULL;
208         mono_domain_lock (domain);
209         if (domain->type_init_exception_hash)
210                 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
211         mono_domain_unlock (domain);
212
213         if (!ex) {
214                 if (klass->name_space && *klass->name_space)
215                         full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
216                 else
217                         full_name = g_strdup (klass->name);
218                 ex = mono_get_exception_type_initialization (full_name, NULL);
219                 g_free (full_name);
220         }
221
222         return ex;
223 }
224
225 /*
226  * mono_runtime_class_init:
227  * @vtable: vtable that needs to be initialized
228  *
229  * This routine calls the class constructor for @vtable.
230  */
231 void
232 mono_runtime_class_init (MonoVTable *vtable)
233 {
234         MonoException *exc;
235         MonoException *exc_to_throw;
236         MonoMethod *method = NULL;
237         MonoClass *klass;
238         gchar *full_name;
239
240         MONO_ARCH_SAVE_REGS;
241
242         if (vtable->initialized)
243                 return;
244
245         exc = NULL;
246         klass = vtable->klass;
247
248         if (!klass->image->checked_module_cctor) {
249                 mono_image_check_for_module_cctor (klass->image);
250                 if (klass->image->has_module_cctor) {
251                         MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
252                         mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
253                 }
254         }
255         method = mono_class_get_cctor (klass);
256
257         if (method) {
258                 MonoDomain *domain = vtable->domain;
259                 TypeInitializationLock *lock;
260                 guint32 tid = GetCurrentThreadId();
261                 int do_initialization = 0;
262                 MonoDomain *last_domain = NULL;
263
264                 mono_type_initialization_lock ();
265                 /* double check... */
266                 if (vtable->initialized) {
267                         mono_type_initialization_unlock ();
268                         return;
269                 }
270                 if (vtable->init_failed) {
271                         mono_type_initialization_unlock ();
272
273                         /* The type initialization already failed once, rethrow the same exception */
274                         mono_raise_exception (get_type_init_exception_for_vtable (vtable));
275                         return;
276                 }                       
277                 lock = g_hash_table_lookup (type_initialization_hash, vtable);
278                 if (lock == NULL) {
279                         /* This thread will get to do the initialization */
280                         if (mono_domain_get () != domain) {
281                                 /* Transfer into the target domain */
282                                 last_domain = mono_domain_get ();
283                                 if (!mono_domain_set (domain, FALSE)) {
284                                         vtable->initialized = 1;
285                                         mono_type_initialization_unlock ();
286                                         mono_raise_exception (mono_get_exception_appdomain_unloaded ());
287                                 }
288                         }
289                         lock = g_malloc (sizeof(TypeInitializationLock));
290                         InitializeCriticalSection (&lock->initialization_section);
291                         lock->initializing_tid = tid;
292                         lock->waiting_count = 1;
293                         lock->done = FALSE;
294                         /* grab the vtable lock while this thread still owns type_initialization_section */
295                         EnterCriticalSection (&lock->initialization_section);
296                         g_hash_table_insert (type_initialization_hash, vtable, lock);
297                         do_initialization = 1;
298                 } else {
299                         gpointer blocked;
300                         TypeInitializationLock *pending_lock;
301
302                         if (lock->initializing_tid == tid || lock->done) {
303                                 mono_type_initialization_unlock ();
304                                 return;
305                         }
306                         /* see if the thread doing the initialization is already blocked on this thread */
307                         blocked = GUINT_TO_POINTER (lock->initializing_tid);
308                         while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
309                                 if (pending_lock->initializing_tid == tid) {
310                                         if (!pending_lock->done) {
311                                                 mono_type_initialization_unlock ();
312                                                 return;
313                                         } else {
314                                                 /* the thread doing the initialization is blocked on this thread,
315                                                    but on a lock that has already been freed. It just hasn't got
316                                                    time to awake */
317                                                 break;
318                                         }
319                                 }
320                                 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
321                         }
322                         ++lock->waiting_count;
323                         /* record the fact that we are waiting on the initializing thread */
324                         g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
325                 }
326                 mono_type_initialization_unlock ();
327
328                 if (do_initialization) {
329                         mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
330
331                         /* If the initialization failed, mark the class as unusable. */
332                         /* Avoid infinite loops */
333                         if (!(exc == NULL ||
334                                   (klass->image == mono_defaults.corlib &&              
335                                    !strcmp (klass->name_space, "System") &&
336                                    !strcmp (klass->name, "TypeInitializationException")))) {
337                                 vtable->init_failed = 1;
338
339                                 if (klass->name_space && *klass->name_space)
340                                         full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
341                                 else
342                                         full_name = g_strdup (klass->name);
343                                 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
344                                 g_free (full_name);
345
346                                 /* 
347                                  * Store the exception object so it could be thrown on subsequent 
348                                  * accesses.
349                                  */
350                                 mono_domain_lock (domain);
351                                 if (!domain->type_init_exception_hash)
352                                         domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
353                                 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
354                                 mono_domain_unlock (domain);
355                         }
356
357                         if (last_domain)
358                                 mono_domain_set (last_domain, TRUE);
359                         lock->done = TRUE;
360                         LeaveCriticalSection (&lock->initialization_section);
361                 } else {
362                         /* this just blocks until the initializing thread is done */
363                         EnterCriticalSection (&lock->initialization_section);
364                         LeaveCriticalSection (&lock->initialization_section);
365                 }
366
367                 mono_type_initialization_lock ();
368                 if (lock->initializing_tid != tid)
369                         g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
370                 --lock->waiting_count;
371                 if (lock->waiting_count == 0) {
372                         DeleteCriticalSection (&lock->initialization_section);
373                         g_hash_table_remove (type_initialization_hash, vtable);
374                         g_free (lock);
375                 }
376                 if (!vtable->init_failed)
377                         vtable->initialized = 1;
378                 mono_type_initialization_unlock ();
379
380                 if (vtable->init_failed) {
381                         /* Either we were the initializing thread or we waited for the initialization */
382                         mono_raise_exception (get_type_init_exception_for_vtable (vtable));
383                 }
384         } else {
385                 vtable->initialized = 1;
386                 return;
387         }
388 }
389
390 static
391 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
392 {
393         MonoVTable *vtable = (MonoVTable*)key;
394
395         TypeInitializationLock *lock = (TypeInitializationLock*) value;
396         if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
397                 lock->done = TRUE;
398                 /* 
399                  * Have to set this since it cannot be set by the normal code in 
400                  * mono_runtime_class_init (). In this case, the exception object is not stored,
401                  * and get_type_init_exception_for_class () needs to be aware of this.
402                  */
403                 vtable->init_failed = 1;
404                 LeaveCriticalSection (&lock->initialization_section);
405                 --lock->waiting_count;
406                 if (lock->waiting_count == 0) {
407                         DeleteCriticalSection (&lock->initialization_section);
408                         g_free (lock);
409                         return TRUE;
410                 }
411         }
412         return FALSE;
413 }
414
415 void
416 mono_release_type_locks (MonoThread *thread)
417 {
418         mono_type_initialization_lock ();
419         g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
420         mono_type_initialization_unlock ();
421 }
422
423 static gpointer
424 default_trampoline (MonoMethod *method)
425 {
426         return method;
427 }
428
429 static gpointer
430 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
431 {
432         g_error ("remoting not installed");
433         return NULL;
434 }
435
436 static gpointer
437 default_delegate_trampoline (MonoMethod *method, gpointer addr)
438 {
439         g_assert_not_reached ();
440         return NULL;
441 }
442
443 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
444 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
445 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
446
447 void
448 mono_install_trampoline (MonoTrampoline func) 
449 {
450         arch_create_jit_trampoline = func? func: default_trampoline;
451 }
452
453 void
454 mono_install_remoting_trampoline (MonoRemotingTrampoline func) 
455 {
456         arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
457 }
458
459 void
460 mono_install_delegate_trampoline (MonoDelegateTrampoline func) 
461 {
462         arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
463 }
464
465 static MonoCompileFunc default_mono_compile_method = NULL;
466
467 /**
468  * mono_install_compile_method:
469  * @func: function to install
470  *
471  * This is a VM internal routine
472  */
473 void        
474 mono_install_compile_method (MonoCompileFunc func)
475 {
476         default_mono_compile_method = func;
477 }
478
479 /**
480  * mono_compile_method:
481  * @method: The method to compile.
482  *
483  * This JIT-compiles the method, and returns the pointer to the native code
484  * produced.
485  */
486 gpointer 
487 mono_compile_method (MonoMethod *method)
488 {
489         if (!default_mono_compile_method) {
490                 g_error ("compile method called on uninitialized runtime");
491                 return NULL;
492         }
493         return default_mono_compile_method (method);
494 }
495
496 static MonoFreeMethodFunc default_mono_free_method = NULL;
497
498 /**
499  * mono_install_free_method:
500  * @func: pointer to the MonoFreeMethodFunc used to release a method
501  *
502  * This is an internal VM routine, it is used for the engines to
503  * register a handler to release the resources associated with a method.
504  *
505  * Methods are freed when no more references to the delegate that holds
506  * them are left.
507  */
508 void
509 mono_install_free_method (MonoFreeMethodFunc func)
510 {
511         default_mono_free_method = func;
512 }
513
514 /**
515  * mono_runtime_free_method:
516  * @domain; domain where the method is hosted
517  * @method: method to release
518  *
519  * This routine is invoked to free the resources associated with
520  * a method that has been JIT compiled.  This is used to discard
521  * methods that were used only temporarily (for example, used in marshalling)
522  *
523  */
524 void
525 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
526 {
527         if (default_mono_free_method != NULL)
528                 default_mono_free_method (domain, method);
529
530         mono_free_method (method);
531 }
532
533 static MonoInitVTableFunc init_vtable_func = NULL;
534
535 /**
536  * mono_install_init_vtable:
537  * @func: pointer to the function to be installed
538  *
539  *   Register a function which will be called by the runtime to initialize the
540  * method pointers inside a vtable. The JIT can use this function to load the
541  * vtable from the AOT file for example.
542  */
543 void
544 mono_install_init_vtable (MonoInitVTableFunc func)
545 {
546         init_vtable_func = func;
547 }
548
549 /*
550  * The vtables in the root appdomain are assumed to be reachable by other 
551  * roots, and we don't use typed allocation in the other domains.
552  */
553
554 /* The sync block is no longer a GC pointer */
555 #define GC_HEADER_BITMAP (0)
556
557 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
558
559 static gsize*
560 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
561 {
562         MonoClassField *field;
563         MonoClass *p;
564         guint32 pos;
565         int max_size;
566
567         if (static_fields)
568                 max_size = mono_class_data_size (class) / sizeof (gpointer);
569         else
570                 max_size = class->instance_size / sizeof (gpointer);
571         if (max_size >= size) {
572                 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
573         }
574
575         for (p = class; p != NULL; p = p->parent) {
576                 gpointer iter = NULL;
577                 while ((field = mono_class_get_fields (p, &iter))) {
578                         MonoType *type;
579
580                         if (static_fields) {
581                                 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
582                                         continue;
583                         } else {
584                                 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
585                                         continue;
586                         }
587                         /* FIXME: should not happen, flag as type load error */
588                         if (field->type->byref)
589                                 break;
590
591                         pos = field->offset / sizeof (gpointer);
592                         pos += offset;
593
594                         type = mono_type_get_underlying_type (field->type);
595                         switch (type->type) {
596                         case MONO_TYPE_I:
597                         case MONO_TYPE_PTR:
598                         case MONO_TYPE_FNPTR:
599                                 break;
600                         /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
601                         case MONO_TYPE_U:
602 #ifdef HAVE_SGEN_GC
603                                 break;
604 #else
605                                 if (class->image != mono_defaults.corlib)
606                                         break;
607 #endif
608                         case MONO_TYPE_STRING:
609                         case MONO_TYPE_SZARRAY:
610                         case MONO_TYPE_CLASS:
611                         case MONO_TYPE_OBJECT:
612                         case MONO_TYPE_ARRAY:
613                                 g_assert ((field->offset % sizeof(gpointer)) == 0);
614
615                                 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
616                                 *max_set = MAX (*max_set, pos);
617                                 break;
618                         case MONO_TYPE_GENERICINST:
619                                 if (!mono_type_generic_inst_is_valuetype (type)) {
620                                         g_assert ((field->offset % sizeof(gpointer)) == 0);
621
622                                         bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
623                                         *max_set = MAX (*max_set, pos);
624                                         break;
625                                 } else {
626                                         /* fall through */
627                                 }
628                         case MONO_TYPE_VALUETYPE: {
629                                 MonoClass *fclass = mono_class_from_mono_type (field->type);
630                                 if (fclass->has_references) {
631                                         /* remove the object header */
632                                         compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
633                                 }
634                                 break;
635                         }
636                         case MONO_TYPE_I1:
637                         case MONO_TYPE_U1:
638                         case MONO_TYPE_I2:
639                         case MONO_TYPE_U2:
640                         case MONO_TYPE_I4:
641                         case MONO_TYPE_U4:
642                         case MONO_TYPE_I8:
643                         case MONO_TYPE_U8:
644                         case MONO_TYPE_R4:
645                         case MONO_TYPE_R8:
646                         case MONO_TYPE_BOOLEAN:
647                         case MONO_TYPE_CHAR:
648                                 break;
649                         default:
650                                 g_assert_not_reached ();
651                                 break;
652                         }
653                 }
654                 if (static_fields)
655                         break;
656         }
657         return bitmap;
658 }
659
660 #if 0
661 /* 
662  * similar to the above, but sets the bits in the bitmap for any non-ref field
663  * and ignores static fields
664  */
665 static gsize*
666 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
667 {
668         MonoClassField *field;
669         MonoClass *p;
670         guint32 pos, pos2;
671         int max_size;
672
673         max_size = class->instance_size / sizeof (gpointer);
674         if (max_size >= size) {
675                 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
676         }
677
678         for (p = class; p != NULL; p = p->parent) {
679                 gpointer iter = NULL;
680                 while ((field = mono_class_get_fields (p, &iter))) {
681                         MonoType *type;
682
683                         if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
684                                 continue;
685                         /* FIXME: should not happen, flag as type load error */
686                         if (field->type->byref)
687                                 break;
688
689                         pos = field->offset / sizeof (gpointer);
690                         pos += offset;
691
692                         type = mono_type_get_underlying_type (field->type);
693                         switch (type->type) {
694 #if SIZEOF_VOID_P == 8
695                         case MONO_TYPE_I:
696                         case MONO_TYPE_U:
697                         case MONO_TYPE_PTR:
698                         case MONO_TYPE_FNPTR:
699 #endif
700                         case MONO_TYPE_I8:
701                         case MONO_TYPE_U8:
702                         case MONO_TYPE_R8:
703                                 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
704                                         pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
705                                         bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
706                                 }
707                                 /* fall through */
708 #if SIZEOF_VOID_P == 4
709                         case MONO_TYPE_I:
710                         case MONO_TYPE_U:
711                         case MONO_TYPE_PTR:
712                         case MONO_TYPE_FNPTR:
713 #endif
714                         case MONO_TYPE_I4:
715                         case MONO_TYPE_U4:
716                         case MONO_TYPE_R4:
717                                 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
718                                         pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
719                                         bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
720                                 }
721                                 /* fall through */
722                         case MONO_TYPE_CHAR:
723                         case MONO_TYPE_I2:
724                         case MONO_TYPE_U2:
725                                 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
726                                         pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
727                                         bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
728                                 }
729                                 /* fall through */
730                         case MONO_TYPE_BOOLEAN:
731                         case MONO_TYPE_I1:
732                         case MONO_TYPE_U1:
733                                 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
734                                 break;
735                         case MONO_TYPE_STRING:
736                         case MONO_TYPE_SZARRAY:
737                         case MONO_TYPE_CLASS:
738                         case MONO_TYPE_OBJECT:
739                         case MONO_TYPE_ARRAY:
740                                 break;
741                         case MONO_TYPE_GENERICINST:
742                                 if (!mono_type_generic_inst_is_valuetype (type)) {
743                                         break;
744                                 } else {
745                                         /* fall through */
746                                 }
747                         case MONO_TYPE_VALUETYPE: {
748                                 MonoClass *fclass = mono_class_from_mono_type (field->type);
749                                 /* remove the object header */
750                                 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
751                                 break;
752                         }
753                         default:
754                                 g_assert_not_reached ();
755                                 break;
756                         }
757                 }
758         }
759         return bitmap;
760 }
761
762 /**
763  * mono_class_insecure_overlapping:
764  * check if a class with explicit layout has references and non-references
765  * fields overlapping.
766  *
767  * Returns: TRUE if it is insecure to load the type.
768  */
769 gboolean
770 mono_class_insecure_overlapping (MonoClass *klass)
771 {
772         int max_set = 0;
773         gsize *bitmap;
774         gsize default_bitmap [4] = {0};
775         gsize *nrbitmap;
776         gsize default_nrbitmap [4] = {0};
777         int i, insecure = FALSE;
778                 return FALSE;
779
780         bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
781         nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
782
783         for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
784                 int idx = i % (sizeof (bitmap [0]) * 8);
785                 if (bitmap [idx] & nrbitmap [idx]) {
786                         insecure = TRUE;
787                         break;
788                 }
789         }
790         if (bitmap != default_bitmap)
791                 g_free (bitmap);
792         if (nrbitmap != default_nrbitmap)
793                 g_free (nrbitmap);
794         if (insecure) {
795                 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
796                 return FALSE;
797         }
798         return insecure;
799 }
800 #endif
801
802 static void
803 mono_class_compute_gc_descriptor (MonoClass *class)
804 {
805         int max_set = 0;
806         gsize *bitmap;
807         gsize default_bitmap [4] = {0};
808         static gboolean gcj_inited = FALSE;
809
810         if (!gcj_inited) {
811                 mono_loader_lock ();
812
813                 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
814                 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
815                 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
816
817 #ifdef HAVE_GC_GCJ_MALLOC
818
819                 GC_init_gcj_malloc (5, NULL);
820
821 #ifdef GC_REDIRECT_TO_LOCAL
822                 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
823                 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
824 #endif
825                 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
826                 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
827 #endif
828                 gcj_inited = TRUE;
829                 mono_loader_unlock ();
830         }
831
832         if (!class->inited)
833                 mono_class_init (class);
834
835         if (class->gc_descr_inited)
836                 return;
837
838         class->gc_descr_inited = TRUE;
839         class->gc_descr = GC_NO_DESCRIPTOR;
840
841         bitmap = default_bitmap;
842         if (class == mono_defaults.string_class) {
843                 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
844         } else if (class->rank) {
845                 mono_class_compute_gc_descriptor (class->element_class);
846 #ifdef HAVE_SGEN_GC
847                 /* libgc has no usable support for arrays... */
848                 if (!class->element_class->valuetype) {
849                         gsize abm = 1;
850                         class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
851                         /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
852                                 class->name_space, class->name);*/
853                 } else {
854                         /* remove the object header */
855                         bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
856                         class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
857                         /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
858                                 class->name_space, class->name);*/
859                         if (bitmap != default_bitmap)
860                                 g_free (bitmap);
861                 }
862 #endif
863         } else {
864                 /*static int count = 0;
865                 if (count++ > 58)
866                         return;*/
867                 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
868 #ifdef HAVE_BOEHM_GC
869                 /* It seems there are issues when the bitmap doesn't fit: play it safe */
870                 if (max_set >= 30) {
871                         /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
872                         if (bitmap != default_bitmap)
873                                 g_free (bitmap);
874                         return;
875                 }
876 #endif
877                 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
878                 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
879                 if (bitmap != default_bitmap)
880                         g_free (bitmap);
881         }
882 }
883
884 /**
885  * field_is_special_static:
886  * @fklass: The MonoClass to look up.
887  * @field: The MonoClassField describing the field.
888  *
889  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
890  * SPECIAL_STATIC_NONE otherwise.
891  */
892 static gint32
893 field_is_special_static (MonoClass *fklass, MonoClassField *field)
894 {
895         MonoCustomAttrInfo *ainfo;
896         int i;
897         ainfo = mono_custom_attrs_from_field (fklass, field);
898         if (!ainfo)
899                 return FALSE;
900         for (i = 0; i < ainfo->num_attrs; ++i) {
901                 MonoClass *klass = ainfo->attrs [i].ctor->klass;
902                 if (klass->image == mono_defaults.corlib) {
903                         if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
904                                 mono_custom_attrs_free (ainfo);
905                                 return SPECIAL_STATIC_THREAD;
906                         }
907                         else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
908                                 mono_custom_attrs_free (ainfo);
909                                 return SPECIAL_STATIC_CONTEXT;
910                         }
911                 }
912         }
913         mono_custom_attrs_free (ainfo);
914         return SPECIAL_STATIC_NONE;
915 }
916
917 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
918
919 /**
920  * mono_class_vtable:
921  * @domain: the application domain
922  * @class: the class to initialize
923  *
924  * VTables are domain specific because we create domain specific code, and 
925  * they contain the domain specific static class data.
926  */
927 MonoVTable *
928 mono_class_vtable (MonoDomain *domain, MonoClass *class)
929 {
930         MonoClassRuntimeInfo *runtime_info;
931
932         g_assert (class);
933
934         /* this check can be inlined in jitted code, too */
935         runtime_info = class->runtime_info;
936         if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
937                 return runtime_info->domain_vtables [domain->domain_id];
938         return mono_class_create_runtime_vtable (domain, class);
939 }
940
941 static MonoVTable *
942 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
943 {
944         MonoVTable *vt;
945         MonoClassRuntimeInfo *runtime_info, *old_info;
946         MonoClassField *field;
947         char *t;
948         int i;
949         gboolean inited = FALSE;
950         guint32 vtable_size, class_size;
951         guint32 cindex;
952         guint32 constant_cols [MONO_CONSTANT_SIZE];
953         gpointer iter;
954         gpointer *interface_offsets;
955
956         mono_domain_lock (domain);
957         runtime_info = class->runtime_info;
958         if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
959                 mono_domain_unlock (domain);
960                 return runtime_info->domain_vtables [domain->domain_id];
961         }
962         if (!class->inited || class->exception_type) {
963                 if (!mono_class_init (class) || class->exception_type){
964                         MonoException *exc;
965                         mono_domain_unlock (domain);
966                         exc = mono_class_get_exception_for_failure (class);
967                         g_assert (exc);
968                         mono_raise_exception (exc);
969                 }
970         }
971
972         mono_class_init (class);
973
974         /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
975         if (class->image->dynamic)
976                 mono_class_setup_vtable (class);
977
978         vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
979                 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
980
981         mono_stats.used_class_count++;
982         mono_stats.class_vtable_size += vtable_size;
983         interface_offsets = mono_mempool_alloc0 (domain->mp,  vtable_size);
984
985         vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
986         vt->klass = class;
987         vt->rank = class->rank;
988         vt->domain = domain;
989
990         mono_class_compute_gc_descriptor (class);
991                 /*
992                  * We can't use typed allocation in the non-root domains, since the
993                  * collector needs the GC descriptor stored in the vtable even after
994                  * the mempool containing the vtable is destroyed when the domain is
995                  * unloaded. An alternative might be to allocate vtables in the GC
996                  * heap, but this does not seem to work (it leads to crashes inside
997                  * libgc). If that approach is tried, two gc descriptors need to be
998                  * allocated for each class: one for the root domain, and one for all
999                  * other domains. The second descriptor should contain a bit for the
1000                  * vtable field in MonoObject, since we can no longer assume the 
1001                  * vtable is reachable by other roots after the appdomain is unloaded.
1002                  */
1003 #ifdef HAVE_BOEHM_GC
1004         if (domain != mono_get_root_domain ())
1005                 vt->gc_descr = GC_NO_DESCRIPTOR;
1006         else
1007 #endif
1008                 vt->gc_descr = class->gc_descr;
1009
1010         if ((class_size = mono_class_data_size (class))) {
1011                 if (class->has_static_refs) {
1012                         gpointer statics_gc_descr;
1013                         int max_set = 0;
1014                         gsize default_bitmap [4] = {0};
1015                         gsize *bitmap;
1016
1017                         bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1018                         /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1019                         statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1020                         vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1021                         mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1022                         if (bitmap != default_bitmap)
1023                                 g_free (bitmap);
1024                 } else {
1025                         vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1026                 }
1027                 mono_stats.class_static_data_size += class_size;
1028         }
1029
1030         cindex = -1;
1031         iter = NULL;
1032         while ((field = mono_class_get_fields (class, &iter))) {
1033                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1034                         continue;
1035                 if (mono_field_is_deleted (field))
1036                         continue;
1037                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1038                         gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1039                         if (special_static != SPECIAL_STATIC_NONE) {
1040                                 guint32 size, offset;
1041                                 gint32 align;
1042                                 size = mono_type_size (field->type, &align);
1043                                 offset = mono_alloc_special_static_data (special_static, size, align);
1044                                 if (!domain->special_static_fields)
1045                                         domain->special_static_fields = g_hash_table_new (NULL, NULL);
1046                                 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1047                                 continue;
1048                         }
1049                 }
1050                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1051                         MonoClass *fklass = mono_class_from_mono_type (field->type);
1052                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1053                         t = (char*)vt->data + field->offset;
1054                         if (fklass->valuetype) {
1055                                 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1056                         } else {
1057                                 /* it's a pointer type: add check */
1058                                 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1059                                 *t = *(char *)field->data;
1060                         }
1061                         continue;
1062                 }
1063                 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1064                         continue;
1065
1066                 /* later do this only on demand if needed */
1067                 if (!field->data) {
1068                         cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1069                         g_assert (cindex);
1070                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1071
1072                         mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1073                         field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1074                         field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1075                 }
1076                 
1077         }
1078
1079         vt->max_interface_id = class->max_interface_id;
1080         
1081         /* initialize interface offsets */
1082         for (i = 0; i <= class->max_interface_id; ++i) {
1083                 int slot = class->interface_offsets [i];
1084                 if (slot >= 0)
1085                         interface_offsets [class->max_interface_id - i] = &(vt->vtable [slot]);
1086         }
1087
1088         /* 
1089          * arch_create_jit_trampoline () can recursively call this function again
1090          * because it compiles icall methods right away.
1091          */
1092         /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1093          * as we change the code in appdomain.c to invalidate vtables by
1094          * looking at the possible MonoClasses created for the domain.
1095          */
1096         g_hash_table_insert (domain->class_vtable_hash, class, vt);
1097         /* class->runtime_info is protected by the loader lock, both when
1098          * it it enlarged and when it is stored info.
1099          */
1100         mono_loader_lock ();
1101         old_info = class->runtime_info;
1102         if (old_info && old_info->max_domain >= domain->domain_id) {
1103                 /* someone already created a large enough runtime info */
1104                 old_info->domain_vtables [domain->domain_id] = vt;
1105         } else {
1106                 int new_size = domain->domain_id;
1107                 if (old_info)
1108                         new_size = MAX (new_size, old_info->max_domain);
1109                 new_size++;
1110                 /* make the new size a power of two */
1111                 i = 2;
1112                 while (new_size > i)
1113                         i <<= 1;
1114                 new_size = i;
1115                 /* this is a bounded memory retention issue: may want to 
1116                  * handle it differently when we'll have a rcu-like system.
1117                  */
1118                 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1119                 runtime_info->max_domain = new_size - 1;
1120                 /* copy the stuff from the older info */
1121                 if (old_info) {
1122                         memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1123                 }
1124                 runtime_info->domain_vtables [domain->domain_id] = vt;
1125                 /* keep this last (add membarrier) */
1126                 class->runtime_info = runtime_info;
1127         }
1128         mono_loader_unlock ();
1129
1130         /* initialize vtable */
1131         if (init_vtable_func)
1132                 inited = init_vtable_func (vt);
1133
1134         if (!inited) {
1135                 mono_class_setup_vtable (class);
1136
1137                 for (i = 0; i < class->vtable_size; ++i) {
1138                         MonoMethod *cm;
1139
1140                         if ((cm = class->vtable [i])) {
1141                                 if (mono_method_signature (cm)->generic_param_count)
1142                                         vt->vtable [i] = cm;
1143                                 else
1144                                         vt->vtable [i] = arch_create_jit_trampoline (cm);
1145                         }
1146                 }
1147         }
1148
1149         mono_domain_unlock (domain);
1150
1151         /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1152         if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1153                 MonoException *exc = mono_class_get_exception_for_failure (class);
1154                 g_assert (exc);
1155                 mono_raise_exception (exc);
1156         }
1157
1158         /* make sure the the parent is initialized */
1159         if (class->parent)
1160                 mono_class_vtable (domain, class->parent);
1161
1162         vt->type = mono_type_get_object (domain, &class->byval_arg);
1163         if (class->contextbound)
1164                 vt->remote = 1;
1165         else
1166                 vt->remote = 0;
1167
1168         return vt;
1169 }
1170
1171 /**
1172  * mono_class_proxy_vtable:
1173  * @domain: the application domain
1174  * @remove_class: the remote class
1175  *
1176  * Creates a vtable for transparent proxies. It is basically
1177  * a copy of the real vtable of the class wrapped in @remote_class,
1178  * but all function pointers invoke the remoting functions, and
1179  * vtable->klass points to the transparent proxy class, and not to @class.
1180  */
1181 static MonoVTable *
1182 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1183 {
1184         MonoVTable *vt, *pvt;
1185         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1186         MonoClass *k;
1187         GSList *extra_interfaces = NULL;
1188         MonoClass *class = remote_class->proxy_class;
1189         gpointer *interface_offsets;
1190
1191         vt = mono_class_vtable (domain, class);
1192         max_interface_id = vt->max_interface_id;
1193         
1194         /* Calculate vtable space for extra interfaces */
1195         for (j = 0; j < remote_class->interface_count; j++) {
1196                 MonoClass* iclass = remote_class->interfaces[j];
1197                 GPtrArray *ifaces;
1198                 int method_count;
1199
1200                 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != -1) 
1201                         continue;       /* interface implemented by the class */
1202                 if (g_slist_find (extra_interfaces, iclass))
1203                         continue;
1204                         
1205                 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1206                 
1207                 method_count = mono_class_num_methods (iclass);
1208         
1209                 ifaces = mono_class_get_implemented_interfaces (iclass);
1210                 if (ifaces) {
1211                         for (i = 0; i < ifaces->len; ++i) {
1212                                 MonoClass *ic = g_ptr_array_index (ifaces, i);
1213                                 if (ic->interface_id <= class->max_interface_id && class->interface_offsets[ic->interface_id] != -1) 
1214                                         continue;       /* interface implemented by the class */
1215                                 if (g_slist_find (extra_interfaces, ic))
1216                                         continue;
1217                                 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1218                                 method_count += mono_class_num_methods (ic);
1219                         }
1220                         g_ptr_array_free (ifaces, TRUE);
1221                 }
1222
1223                 extra_interface_vtsize += method_count * sizeof (gpointer);
1224                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1225         }
1226
1227         vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1228                 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1229
1230         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1231
1232         interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1233         pvt = (MonoVTable*)(interface_offsets + max_interface_id + 1);
1234         memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1235
1236         pvt->klass = mono_defaults.transparent_proxy_class;
1237         /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1238         pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1239
1240         /* initialize vtable */
1241         mono_class_setup_vtable (class);
1242         for (i = 0; i < class->vtable_size; ++i) {
1243                 MonoMethod *cm;
1244                     
1245                 if ((cm = class->vtable [i]))
1246                         pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
1247         }
1248
1249         if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1250                 /* create trampolines for abstract methods */
1251                 for (k = class; k; k = k->parent) {
1252                         MonoMethod* m;
1253                         gpointer iter = NULL;
1254                         while ((m = mono_class_get_methods (k, &iter)))
1255                                 if (!pvt->vtable [m->slot])
1256                                         pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
1257                 }
1258         }
1259
1260         pvt->max_interface_id = max_interface_id;
1261
1262         /* initialize interface offsets */
1263         for (i = 0; i <= class->max_interface_id; ++i) {
1264                 int slot = class->interface_offsets [i];
1265                 if (slot >= 0)
1266                         interface_offsets [max_interface_id - i] = &(pvt->vtable [slot]);
1267         }
1268
1269         if (extra_interfaces) {
1270                 int slot = class->vtable_size;
1271                 MonoClass* interf;
1272                 gpointer iter;
1273                 MonoMethod* cm;
1274                 GSList *list_item;
1275
1276                 /* Create trampolines for the methods of the interfaces */
1277                 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1278                         interf = list_item->data;
1279                         interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1280
1281                         iter = NULL;
1282                         j = 0;
1283                         while ((cm = mono_class_get_methods (interf, &iter)))
1284                                 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
1285                         
1286                         slot += mono_class_num_methods (interf);
1287                 }
1288                 g_slist_free (extra_interfaces);
1289         }
1290
1291         return pvt;
1292 }
1293
1294 /**
1295  * mono_class_has_special_static_fields:
1296  * 
1297  *   Returns whenever @klass has any thread/context static fields.
1298  */
1299 gboolean
1300 mono_class_has_special_static_fields (MonoClass *klass)
1301 {
1302         MonoClassField *field;
1303         gpointer iter;
1304
1305         iter = NULL;
1306         while ((field = mono_class_get_fields (klass, &iter))) {
1307                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1308                         continue;
1309                 if (mono_field_is_deleted (field))
1310                         continue;
1311                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1312                         if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
1313                                 return TRUE;
1314                 }
1315         }
1316
1317         return FALSE;
1318 }
1319
1320 /**
1321  * create_remote_class_key:
1322  * Creates an array of pointers that can be used as a hash key for a remote class.
1323  * The first element of the array is the number of pointers.
1324  */
1325 static gpointer*
1326 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1327 {
1328         gpointer *key;
1329         int i, j;
1330         
1331         if (remote_class == NULL) {
1332                 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1333                         key = g_malloc (sizeof(gpointer) * 3);
1334                         key [0] = GINT_TO_POINTER (2);
1335                         key [1] = mono_defaults.marshalbyrefobject_class;
1336                         key [2] = extra_class;
1337                 } else {
1338                         key = g_malloc (sizeof(gpointer) * 2);
1339                         key [0] = GINT_TO_POINTER (1);
1340                         key [1] = extra_class;
1341                 }
1342         } else {
1343                 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1344                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1345                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1346                         key [1] = remote_class->proxy_class;
1347
1348                         // Keep the list of interfaces sorted
1349                         for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1350                                 if (extra_class && remote_class->interfaces [i] > extra_class) {
1351                                         key [j++] = extra_class;
1352                                         extra_class = NULL;
1353                                 }
1354                                 key [j] = remote_class->interfaces [i];
1355                         }
1356                         if (extra_class)
1357                                 key [j] = extra_class;
1358                 } else {
1359                         // Replace the old class. The interface list is the same
1360                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1361                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1362                         key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1363                         for (i = 0; i < remote_class->interface_count; i++)
1364                                 key [2 + i] = remote_class->interfaces [i];
1365                 }
1366         }
1367         
1368         return key;
1369 }
1370
1371 /**
1372  * copy_remote_class_key:
1373  *
1374  *   Make a copy of KEY in the mempool MP and return the copy.
1375  */
1376 static gpointer*
1377 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1378 {
1379         int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1380         gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1381
1382         memcpy (mp_key, key, key_size);
1383
1384         return mp_key;
1385 }
1386
1387 /**
1388  * mono_remote_class:
1389  * @domain: the application domain
1390  * @class_name: name of the remote class
1391  *
1392  * Creates and initializes a MonoRemoteClass object for a remote type. 
1393  * 
1394  */
1395 MonoRemoteClass*
1396 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1397 {
1398         MonoRemoteClass *rc;
1399         gpointer* key, *mp_key;
1400         
1401         key = create_remote_class_key (NULL, proxy_class);
1402         
1403         mono_domain_lock (domain);
1404         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1405
1406         if (rc) {
1407                 g_free (key);
1408                 mono_domain_unlock (domain);
1409                 return rc;
1410         }
1411
1412         mp_key = copy_remote_class_key (domain->mp, key);
1413         g_free (key);
1414         key = mp_key;
1415
1416         if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1417                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1418                 rc->interface_count = 1;
1419                 rc->interfaces [0] = proxy_class;
1420                 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1421         } else {
1422                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1423                 rc->interface_count = 0;
1424                 rc->proxy_class = proxy_class;
1425         }
1426         
1427         rc->default_vtable = NULL;
1428         rc->xdomain_vtable = NULL;
1429         rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1430
1431         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1432
1433         mono_domain_unlock (domain);
1434         return rc;
1435 }
1436
1437 /**
1438  * clone_remote_class:
1439  * Creates a copy of the remote_class, adding the provided class or interface
1440  */
1441 static MonoRemoteClass*
1442 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1443 {
1444         MonoRemoteClass *rc;
1445         gpointer* key, *mp_key;
1446         
1447         key = create_remote_class_key (remote_class, extra_class);
1448         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1449         if (rc != NULL) {
1450                 g_free (key);
1451                 return rc;
1452         }
1453
1454         mp_key = copy_remote_class_key (domain->mp, key);
1455         g_free (key);
1456         key = mp_key;
1457
1458         if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1459                 int i,j;
1460                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1461                 rc->proxy_class = remote_class->proxy_class;
1462                 rc->interface_count = remote_class->interface_count + 1;
1463                 
1464                 // Keep the list of interfaces sorted, since the hash key of
1465                 // the remote class depends on this
1466                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1467                         if (remote_class->interfaces [i] > extra_class && i == j)
1468                                 rc->interfaces [j++] = extra_class;
1469                         rc->interfaces [j] = remote_class->interfaces [i];
1470                 }
1471                 if (i == j)
1472                         rc->interfaces [j] = extra_class;
1473         } else {
1474                 // Replace the old class. The interface array is the same
1475                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1476                 rc->proxy_class = extra_class;
1477                 rc->interface_count = remote_class->interface_count;
1478                 if (rc->interface_count > 0)
1479                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1480         }
1481         
1482         rc->default_vtable = NULL;
1483         rc->xdomain_vtable = NULL;
1484         rc->proxy_class_name = remote_class->proxy_class_name;
1485
1486         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1487
1488         return rc;
1489 }
1490
1491 gpointer
1492 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1493 {
1494         mono_domain_lock (domain);
1495         if (rp->target_domain_id != -1) {
1496                 if (remote_class->xdomain_vtable == NULL)
1497                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1498                 mono_domain_unlock (domain);
1499                 return remote_class->xdomain_vtable;
1500         }
1501         if (remote_class->default_vtable == NULL) {
1502                 MonoType *type;
1503                 MonoClass *klass;
1504                 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1505                 klass = mono_class_from_mono_type (type);
1506                 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1507                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1508                 else
1509                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1510         }
1511         
1512         mono_domain_unlock (domain);
1513         return remote_class->default_vtable;
1514 }
1515
1516 /**
1517  * mono_upgrade_remote_class:
1518  * @domain: the application domain
1519  * @tproxy: the proxy whose remote class has to be upgraded.
1520  * @klass: class to which the remote class can be casted.
1521  *
1522  * Updates the vtable of the remote class by adding the necessary method slots
1523  * and interface offsets so it can be safely casted to klass. klass can be a
1524  * class or an interface.
1525  */
1526 void
1527 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1528 {
1529         MonoTransparentProxy *tproxy;
1530         MonoRemoteClass *remote_class;
1531         gboolean redo_vtable;
1532
1533         mono_domain_lock (domain);
1534
1535         tproxy = (MonoTransparentProxy*) proxy_object;
1536         remote_class = tproxy->remote_class;
1537         
1538         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1539                 int i;
1540                 redo_vtable = TRUE;
1541                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1542                         if (remote_class->interfaces [i] == klass)
1543                                 redo_vtable = FALSE;
1544         }
1545         else {
1546                 redo_vtable = (remote_class->proxy_class != klass);
1547         }
1548
1549         if (redo_vtable) {
1550                 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1551                 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1552         }
1553         
1554         mono_domain_unlock (domain);
1555 }
1556
1557
1558 /**
1559  * mono_object_get_virtual_method:
1560  * @obj: object to operate on.
1561  * @method: method 
1562  *
1563  * Retrieves the MonoMethod that would be called on obj if obj is passed as
1564  * the instance of a callvirt of method.
1565  */
1566 MonoMethod*
1567 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1568 {
1569         MonoClass *klass;
1570         MonoMethod **vtable;
1571         gboolean is_proxy;
1572         MonoMethod *res = NULL;
1573
1574         klass = mono_object_class (obj);
1575         if (klass == mono_defaults.transparent_proxy_class) {
1576                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1577                 is_proxy = TRUE;
1578         } else {
1579                 is_proxy = FALSE;
1580         }
1581
1582         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1583                         return method;
1584
1585         mono_class_setup_vtable (klass);
1586         vtable = klass->vtable;
1587
1588         /* check method->slot is a valid index: perform isinstance? */
1589         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1590                 if (!is_proxy)
1591                         res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1592         } else {
1593                 if (method->slot != -1)
1594                         res = vtable [method->slot];
1595         }
1596
1597         if (is_proxy) {
1598                 if (!res) res = method;   /* It may be an interface or abstract class method */
1599                 res = mono_marshal_get_remoting_invoke (res);
1600         }
1601
1602         g_assert (res);
1603         
1604         return res;
1605 }
1606
1607 static MonoObject*
1608 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1609 {
1610         g_error ("runtime invoke called on uninitialized runtime");
1611         return NULL;
1612 }
1613
1614 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1615
1616 /**
1617  * mono_runtime_invoke:
1618  * @method: method to invoke
1619  * @obJ: object instance
1620  * @params: arguments to the method
1621  * @exc: exception information.
1622  *
1623  * Invokes the method represented by @method on the object @obj.
1624  *
1625  * obj is the 'this' pointer, it should be NULL for static
1626  * methods, a MonoObject* for object instances and a pointer to
1627  * the value type for value types.
1628  *
1629  * The params array contains the arguments to the method with the
1630  * same convention: MonoObject* pointers for object instances and
1631  * pointers to the value type otherwise. 
1632  * 
1633  * From unmanaged code you'll usually use the
1634  * mono_runtime_invoke() variant.
1635  *
1636  * Note that this function doesn't handle virtual methods for
1637  * you, it will exec the exact method you pass: we still need to
1638  * expose a function to lookup the derived class implementation
1639  * of a virtual method (there are examples of this in the code,
1640  * though).
1641  * 
1642  * You can pass NULL as the exc argument if you don't want to
1643  * catch exceptions, otherwise, *exc will be set to the exception
1644  * thrown, if any.  if an exception is thrown, you can't use the
1645  * MonoObject* result from the function.
1646  * 
1647  * If the method returns a value type, it is boxed in an object
1648  * reference.
1649  */
1650 MonoObject*
1651 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1652 {
1653         return default_mono_runtime_invoke (method, obj, params, exc);
1654 }
1655
1656 static void
1657 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1658 {
1659         int t;
1660         if (type->byref) {
1661                 gpointer *p = (gpointer*)dest;
1662                 *p = value;
1663                 return;
1664         }
1665         t = type->type;
1666 handle_enum:
1667         switch (t) {
1668         case MONO_TYPE_BOOLEAN:
1669         case MONO_TYPE_I1:
1670         case MONO_TYPE_U1: {
1671                 guint8 *p = (guint8*)dest;
1672                 *p = value ? *(guint8*)value : 0;
1673                 return;
1674         }
1675         case MONO_TYPE_I2:
1676         case MONO_TYPE_U2:
1677         case MONO_TYPE_CHAR: {
1678                 guint16 *p = (guint16*)dest;
1679                 *p = value ? *(guint16*)value : 0;
1680                 return;
1681         }
1682 #if SIZEOF_VOID_P == 4
1683         case MONO_TYPE_I:
1684         case MONO_TYPE_U:
1685 #endif
1686         case MONO_TYPE_I4:
1687         case MONO_TYPE_U4: {
1688                 gint32 *p = (gint32*)dest;
1689                 *p = value ? *(gint32*)value : 0;
1690                 return;
1691         }
1692 #if SIZEOF_VOID_P == 8
1693         case MONO_TYPE_I:
1694         case MONO_TYPE_U:
1695 #endif
1696         case MONO_TYPE_I8:
1697         case MONO_TYPE_U8: {
1698                 gint64 *p = (gint64*)dest;
1699                 *p = value ? *(gint64*)value : 0;
1700                 return;
1701         }
1702         case MONO_TYPE_R4: {
1703                 float *p = (float*)dest;
1704                 *p = value ? *(float*)value : 0;
1705                 return;
1706         }
1707         case MONO_TYPE_R8: {
1708                 double *p = (double*)dest;
1709                 *p = value ? *(double*)value : 0;
1710                 return;
1711         }
1712         case MONO_TYPE_STRING:
1713         case MONO_TYPE_SZARRAY:
1714         case MONO_TYPE_CLASS:
1715         case MONO_TYPE_OBJECT:
1716         case MONO_TYPE_ARRAY:
1717                 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
1718                 return;
1719         case MONO_TYPE_FNPTR:
1720         case MONO_TYPE_PTR: {
1721                 gpointer *p = (gpointer*)dest;
1722                 *p = deref_pointer? *(gpointer*)value: value;
1723                 return;
1724         }
1725         case MONO_TYPE_VALUETYPE:
1726                 /* note that 't' and 'type->type' can be different */
1727                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
1728                         t = type->data.klass->enum_basetype->type;
1729                         goto handle_enum;
1730                 } else {
1731                         int size;
1732                         size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
1733                         if (value == NULL)
1734                                 memset (dest, 0, size);
1735                         else
1736                                 memcpy (dest, value, size);
1737                 }
1738                 return;
1739         case MONO_TYPE_GENERICINST:
1740                 t = type->data.generic_class->container_class->byval_arg.type;
1741                 goto handle_enum;
1742         default:
1743                 g_warning ("got type %x", type->type);
1744                 g_assert_not_reached ();
1745         }
1746 }
1747
1748 /**
1749  * mono_field_set_value:
1750  * @obj: Instance object
1751  * @field: MonoClassField describing the field to set
1752  * @value: The value to be set
1753  *
1754  * Sets the value of the field described by @field in the object instance @obj
1755  * to the value passed in @value.   This method should only be used for instance
1756  * fields.   For static fields, use mono_field_static_set_value.
1757  *
1758  * The value must be on the native format of the field type. 
1759  */
1760 void
1761 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1762 {
1763         void *dest;
1764
1765         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1766
1767         dest = (char*)obj + field->offset;
1768         set_value (field->type, dest, value, FALSE);
1769 }
1770
1771 /**
1772  * mono_field_static_set_value:
1773  * @field: MonoClassField describing the field to set
1774  * @value: The value to be set
1775  *
1776  * Sets the value of the static field described by @field
1777  * to the value passed in @value.
1778  *
1779  * The value must be on the native format of the field type. 
1780  */
1781 void
1782 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1783 {
1784         void *dest;
1785
1786         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1787         /* you cant set a constant! */
1788         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1789         
1790         dest = (char*)vt->data + field->offset;
1791         set_value (field->type, dest, value, FALSE);
1792 }
1793
1794 /* Used by the debugger */
1795 void *
1796 mono_vtable_get_static_field_data (MonoVTable *vt)
1797 {
1798         return vt->data;
1799 }
1800
1801 /**
1802  * mono_field_get_value:
1803  * @obj: Object instance
1804  * @field: MonoClassField describing the field to fetch information from
1805  * @value: pointer to the location where the value will be stored
1806  *
1807  * Use this routine to get the value of the field @field in the object
1808  * passed.
1809  *
1810  * The pointer provided by value must be of the field type, for reference
1811  * types this is a MonoObject*, for value types its the actual pointer to
1812  * the value type.
1813  *
1814  * For example:
1815  *     int i;
1816  *     mono_field_get_value (obj, int_field, &i);
1817  */
1818 void
1819 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1820 {
1821         void *src;
1822
1823         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1824
1825         src = (char*)obj + field->offset;
1826         set_value (field->type, value, src, TRUE);
1827 }
1828
1829 /**
1830  * mono_field_get_value_object:
1831  * @domain: domain where the object will be created (if boxing)
1832  * @field: MonoClassField describing the field to fetch information from
1833  * @obj: The object instance for the field.
1834  *
1835  * Returns: a new MonoObject with the value from the given field.  If the
1836  * field represents a value type, the value is boxed.
1837  *
1838  */
1839 MonoObject *
1840 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1841 {       
1842         MonoObject *o;
1843         MonoClass *klass;
1844         MonoVTable *vtable = NULL;
1845         gchar *v;
1846         gboolean is_static = FALSE;
1847         gboolean is_ref = FALSE;
1848
1849         switch (field->type->type) {
1850         case MONO_TYPE_STRING:
1851         case MONO_TYPE_OBJECT:
1852         case MONO_TYPE_CLASS:
1853         case MONO_TYPE_ARRAY:
1854         case MONO_TYPE_SZARRAY:
1855                 is_ref = TRUE;
1856                 break;
1857         case MONO_TYPE_U1:
1858         case MONO_TYPE_I1:
1859         case MONO_TYPE_BOOLEAN:
1860         case MONO_TYPE_U2:
1861         case MONO_TYPE_I2:
1862         case MONO_TYPE_CHAR:
1863         case MONO_TYPE_U:
1864         case MONO_TYPE_I:
1865         case MONO_TYPE_U4:
1866         case MONO_TYPE_I4:
1867         case MONO_TYPE_R4:
1868         case MONO_TYPE_U8:
1869         case MONO_TYPE_I8:
1870         case MONO_TYPE_R8:
1871         case MONO_TYPE_VALUETYPE:
1872                 is_ref = field->type->byref;
1873                 break;
1874         case MONO_TYPE_GENERICINST:
1875                 is_ref = !field->type->data.generic_class->container_class->valuetype;
1876                 break;
1877         default:
1878                 g_error ("type 0x%x not handled in "
1879                          "mono_field_get_value_object", field->type->type);
1880                 return NULL;
1881         }
1882
1883         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1884                 is_static = TRUE;
1885                 vtable = mono_class_vtable (domain, field->parent);
1886                 if (!vtable->initialized)
1887                         mono_runtime_class_init (vtable);
1888         }
1889         
1890         if (is_ref) {
1891                 if (is_static) {
1892                         mono_field_static_get_value (vtable, field, &o);
1893                 } else {
1894                         mono_field_get_value (obj, field, &o);
1895                 }
1896                 return o;
1897         }
1898
1899         /* boxed value type */
1900         klass = mono_class_from_mono_type (field->type);
1901         o = mono_object_new (domain, klass);
1902         v = ((gchar *) o) + sizeof (MonoObject);
1903         if (is_static) {
1904                 mono_field_static_get_value (vtable, field, v);
1905         } else {
1906                 mono_field_get_value (obj, field, v);
1907         }
1908
1909         return o;
1910 }
1911
1912 int
1913 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1914 {
1915         int retval = 0;
1916         const char *p = blob;
1917         mono_metadata_decode_blob_size (p, &p);
1918
1919         switch (type) {
1920         case MONO_TYPE_BOOLEAN:
1921         case MONO_TYPE_U1:
1922         case MONO_TYPE_I1:
1923                 *(guint8 *) value = *p;
1924                 break;
1925         case MONO_TYPE_CHAR:
1926         case MONO_TYPE_U2:
1927         case MONO_TYPE_I2:
1928                 *(guint16*) value = read16 (p);
1929                 break;
1930         case MONO_TYPE_U4:
1931         case MONO_TYPE_I4:
1932                 *(guint32*) value = read32 (p);
1933                 break;
1934         case MONO_TYPE_U8:
1935         case MONO_TYPE_I8:
1936                 *(guint64*) value = read64 (p);
1937                 break;
1938         case MONO_TYPE_R4:
1939                 readr4 (p, (float*) value);
1940                 break;
1941         case MONO_TYPE_R8:
1942                 readr8 (p, (double*) value);
1943                 break;
1944         case MONO_TYPE_STRING:
1945                 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1946                 break;
1947         case MONO_TYPE_CLASS:
1948                 *(gpointer*) value = NULL;
1949                 break;
1950         default:
1951                 retval = -1;
1952                 g_warning ("type 0x%02x should not be in constant table", type);
1953         }
1954         return retval;
1955 }
1956
1957 static void
1958 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1959 {
1960         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1961         mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1962 }
1963
1964 /**
1965  * mono_field_static_get_value:
1966  * @vt: vtable to the object
1967  * @field: MonoClassField describing the field to fetch information from
1968  * @value: where the value is returned
1969  *
1970  * Use this routine to get the value of the static field @field value.
1971  *
1972  * The pointer provided by value must be of the field type, for reference
1973  * types this is a MonoObject*, for value types its the actual pointer to
1974  * the value type.
1975  *
1976  * For example:
1977  *     int i;
1978  *     mono_field_static_get_value (vt, int_field, &i);
1979  */
1980 void
1981 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1982 {
1983         void *src;
1984
1985         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1986         
1987         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1988                 get_default_field_value (vt->domain, field, value);
1989                 return;
1990         }
1991
1992         src = (char*)vt->data + field->offset;
1993         set_value (field->type, value, src, TRUE);
1994 }
1995
1996 /**
1997  * mono_property_set_value:
1998  * @prop: MonoProperty to set
1999  * @obj: instance object on which to act
2000  * @params: parameters to pass to the propery
2001  * @exc: optional exception
2002  *
2003  * Invokes the property's set method with the given arguments on the
2004  * object instance obj (or NULL for static properties). 
2005  * 
2006  * You can pass NULL as the exc argument if you don't want to
2007  * catch exceptions, otherwise, *exc will be set to the exception
2008  * thrown, if any.  if an exception is thrown, you can't use the
2009  * MonoObject* result from the function.
2010  */
2011 void
2012 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2013 {
2014         default_mono_runtime_invoke (prop->set, obj, params, exc);
2015 }
2016
2017 /**
2018  * mono_property_get_value:
2019  * @prop: MonoProperty to fetch
2020  * @obj: instance object on which to act
2021  * @params: parameters to pass to the propery
2022  * @exc: optional exception
2023  *
2024  * Invokes the property's get method with the given arguments on the
2025  * object instance obj (or NULL for static properties). 
2026  * 
2027  * You can pass NULL as the exc argument if you don't want to
2028  * catch exceptions, otherwise, *exc will be set to the exception
2029  * thrown, if any.  if an exception is thrown, you can't use the
2030  * MonoObject* result from the function.
2031  *
2032  * Returns: the value from invoking the get method on the property.
2033  */
2034 MonoObject*
2035 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2036 {
2037         return default_mono_runtime_invoke (prop->get, obj, params, exc);
2038 }
2039
2040 /*
2041  * mono_nullable_init:
2042  * @buf: The nullable structure to initialize.
2043  * @value: the value to initialize from
2044  * @klass: the type for the object
2045  *
2046  * Initialize the nullable structure pointed to by @buf from @value which
2047  * should be a boxed value type.   The size of @buf should be able to hold
2048  * as much data as the @klass->instance_size (which is the number of bytes
2049  * that will be copies).
2050  *
2051  * Since Nullables have variable structure, we can not define a C
2052  * structure for them.
2053  */
2054 void
2055 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2056 {
2057         MonoClass *param_class = klass->cast_class;
2058                                 
2059         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2060         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2061
2062         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2063         if (value)
2064                 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2065         else
2066                 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2067 }
2068
2069 /**
2070  * mono_nullable_box:
2071  * @buf: The buffer representing the data to be boxed
2072  * @klass: the type to box it as.
2073  *
2074  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2075  * @buf.
2076  */
2077 MonoObject*
2078 mono_nullable_box (guint8 *buf, MonoClass *klass)
2079 {
2080         MonoClass *param_class = klass->cast_class;
2081
2082         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2083         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2084
2085         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2086                 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2087                 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2088                 return o;
2089         }
2090         else
2091                 return NULL;
2092 }
2093
2094 /**
2095  * mono_get_delegate_invoke:
2096  * @klass: The delegate class
2097  *
2098  * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2099  */
2100 MonoMethod *
2101 mono_get_delegate_invoke (MonoClass *klass)
2102 {
2103         MonoMethod *im;
2104
2105         im = mono_class_get_method_from_name (klass, "Invoke", -1);
2106         g_assert (im);
2107
2108         return im;
2109 }
2110
2111 /**
2112  * mono_runtime_delegate_invoke:
2113  * @delegate: pointer to a delegate object.
2114  * @params: parameters for the delegate.
2115  * @exc: Pointer to the exception result.
2116  *
2117  * Invokes the delegate method @delegate with the parameters provided.
2118  *
2119  * You can pass NULL as the exc argument if you don't want to
2120  * catch exceptions, otherwise, *exc will be set to the exception
2121  * thrown, if any.  if an exception is thrown, you can't use the
2122  * MonoObject* result from the function.
2123  */
2124 MonoObject*
2125 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2126 {
2127         MonoMethod *im;
2128
2129         im = mono_get_delegate_invoke (delegate->vtable->klass);
2130         g_assert (im);
2131
2132         return mono_runtime_invoke (im, delegate, params, exc);
2133 }
2134
2135 static char **main_args = NULL;
2136 static int num_main_args;
2137
2138 /**
2139  * mono_runtime_get_main_args:
2140  *
2141  * Returns: a MonoArray with the arguments passed to the main program
2142  */
2143 MonoArray*
2144 mono_runtime_get_main_args (void)
2145 {
2146         MonoArray *res;
2147         int i;
2148         MonoDomain *domain = mono_domain_get ();
2149
2150         if (!main_args)
2151                 return NULL;
2152
2153         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2154
2155         for (i = 0; i < num_main_args; ++i)
2156                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2157
2158         return res;
2159 }
2160
2161 static void
2162 fire_process_exit_event (void)
2163 {
2164         MonoClassField *field;
2165         MonoDomain *domain = mono_domain_get ();
2166         gpointer pa [2];
2167         MonoObject *delegate, *exc;
2168         
2169         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2170         g_assert (field);
2171
2172         if (domain != mono_get_root_domain ())
2173                 return;
2174
2175         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
2176         if (delegate == NULL)
2177                 return;
2178
2179         pa [0] = domain;
2180         pa [1] = NULL;
2181         mono_runtime_delegate_invoke (delegate, pa, &exc);
2182 }
2183
2184 /**
2185  * mono_runtime_run_main:
2186  * @method: the method to start the application with (usually Main)
2187  * @argc: number of arguments from the command line
2188  * @argv: array of strings from the command line
2189  * @exc: excetption results
2190  *
2191  * Execute a standard Main() method (argc/argv contains the
2192  * executable name). This method also sets the command line argument value
2193  * needed by System.Environment.
2194  *
2195  * 
2196  */
2197 int
2198 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2199                        MonoObject **exc)
2200 {
2201         int i;
2202         MonoArray *args = NULL;
2203         MonoDomain *domain = mono_domain_get ();
2204         gchar *utf8_fullpath;
2205         int result;
2206
2207         g_assert (method != NULL);
2208         
2209         mono_thread_set_main (mono_thread_current ());
2210
2211         main_args = g_new0 (char*, argc);
2212         num_main_args = argc;
2213
2214         if (!g_path_is_absolute (argv [0])) {
2215                 gchar *basename = g_path_get_basename (argv [0]);
2216                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2217                                                     basename,
2218                                                     NULL);
2219
2220                 utf8_fullpath = mono_utf8_from_external (fullpath);
2221                 if(utf8_fullpath == NULL) {
2222                         /* Printing the arg text will cause glib to
2223                          * whinge about "Invalid UTF-8", but at least
2224                          * its relevant, and shows the problem text
2225                          * string.
2226                          */
2227                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2228                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2229                         exit (-1);
2230                 }
2231
2232                 g_free (fullpath);
2233                 g_free (basename);
2234         } else {
2235                 utf8_fullpath = mono_utf8_from_external (argv[0]);
2236                 if(utf8_fullpath == NULL) {
2237                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2238                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2239                         exit (-1);
2240                 }
2241         }
2242
2243         main_args [0] = utf8_fullpath;
2244
2245         for (i = 1; i < argc; ++i) {
2246                 gchar *utf8_arg;
2247
2248                 utf8_arg=mono_utf8_from_external (argv[i]);
2249                 if(utf8_arg==NULL) {
2250                         /* Ditto the comment about Invalid UTF-8 here */
2251                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2252                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2253                         exit (-1);
2254                 }
2255
2256                 main_args [i] = utf8_arg;
2257         }
2258         argc--;
2259         argv++;
2260         if (mono_method_signature (method)->param_count) {
2261                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2262                 for (i = 0; i < argc; ++i) {
2263                         /* The encodings should all work, given that
2264                          * we've checked all these args for the
2265                          * main_args array.
2266                          */
2267                         gchar *str = mono_utf8_from_external (argv [i]);
2268                         MonoString *arg = mono_string_new (domain, str);
2269                         mono_array_setref (args, i, arg);
2270                         g_free (str);
2271                 }
2272         } else {
2273                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2274         }
2275         
2276         mono_assembly_set_main (method->klass->image->assembly);
2277
2278         result = mono_runtime_exec_main (method, args, exc);
2279         fire_process_exit_event ();
2280         return result;
2281 }
2282
2283 /* Used in mono_unhandled_exception */
2284 static MonoObject *
2285 create_unhandled_exception_eventargs (MonoObject *exc)
2286 {
2287         MonoClass *klass;
2288         gpointer args [2];
2289         MonoMethod *method = NULL;
2290         MonoBoolean is_terminating = TRUE;
2291         MonoObject *obj;
2292
2293         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2294         g_assert (klass);
2295
2296         mono_class_init (klass);
2297
2298         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2299         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2300         g_assert (method);
2301
2302         args [0] = exc;
2303         args [1] = &is_terminating;
2304
2305         obj = mono_object_new (mono_domain_get (), klass);
2306         mono_runtime_invoke (method, obj, args, NULL);
2307
2308         return obj;
2309 }
2310
2311 /**
2312  * mono_unhandled_exception:
2313  * @exc: exception thrown
2314  *
2315  * This is a VM internal routine.
2316  *
2317  * We call this function when we detect an unhandled exception
2318  * in the default domain.
2319  *
2320  * It invokes the * UnhandledException event in AppDomain or prints
2321  * a warning to the console 
2322  */
2323 void
2324 mono_unhandled_exception (MonoObject *exc)
2325 {
2326         MonoDomain *domain = mono_domain_get ();
2327         MonoClassField *field;
2328         MonoObject *delegate;
2329
2330         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
2331                                              "UnhandledException");
2332         g_assert (field);
2333
2334         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2335                 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
2336
2337                 /* set exitcode only in the main thread */
2338                 if (mono_thread_current () == main_thread)
2339                         mono_environment_exitcode_set (1);
2340                 if (domain != mono_get_root_domain () || !delegate) {
2341                         mono_print_unhandled_exception (exc);
2342                 } else {
2343                         MonoObject *e = NULL;
2344                         gpointer pa [2];
2345
2346                         pa [0] = domain->domain;
2347                         pa [1] = create_unhandled_exception_eventargs (exc);
2348                         mono_runtime_delegate_invoke (delegate, pa, &e);
2349                         
2350                         if (e) {
2351                                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2352                                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2353                                 g_free (msg);
2354                         }
2355                 }
2356         }
2357 }
2358
2359 /*
2360  * Launch a new thread to execute a function
2361  *
2362  * main_func is called back from the thread with main_args as the
2363  * parameter.  The callback function is expected to start Main()
2364  * eventually.  This function then waits for all managed threads to
2365  * finish.
2366  * It is not necesseray anymore to execute managed code in a subthread,
2367  * so this function should not be used anymore by default: just
2368  * execute the code and then call mono_thread_manage ().
2369  */
2370 void
2371 mono_runtime_exec_managed_code (MonoDomain *domain,
2372                                 MonoMainThreadFunc main_func,
2373                                 gpointer main_args)
2374 {
2375         mono_thread_create (domain, main_func, main_args);
2376
2377         mono_thread_manage ();
2378 }
2379
2380 /*
2381  * Execute a standard Main() method (args doesn't contain the
2382  * executable name).
2383  */
2384 int
2385 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2386 {
2387         MonoDomain *domain;
2388         gpointer pa [1];
2389         int rval;
2390
2391         g_assert (args);
2392
2393         pa [0] = args;
2394
2395         domain = mono_object_domain (args);
2396         if (!domain->entry_assembly) {
2397                 gchar *str;
2398                 MonoAssembly *assembly;
2399
2400                 assembly = method->klass->image->assembly;
2401                 domain->entry_assembly = assembly;
2402                 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2403
2404                 str = g_strconcat (assembly->image->name, ".config", NULL);
2405                 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2406                 g_free (str);
2407         }
2408
2409         /* FIXME: check signature of method */
2410         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
2411                 MonoObject *res;
2412                 res = mono_runtime_invoke (method, NULL, pa, exc);
2413                 if (!exc || !*exc)
2414                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
2415                 else
2416                         rval = -1;
2417
2418                 mono_environment_exitcode_set (rval);
2419         } else {
2420                 mono_runtime_invoke (method, NULL, pa, exc);
2421                 if (!exc || !*exc)
2422                         rval = 0;
2423                 else {
2424                         /* If the return type of Main is void, only
2425                          * set the exitcode if an exception was thrown
2426                          * (we don't want to blow away an
2427                          * explicitly-set exit code)
2428                          */
2429                         rval = -1;
2430                         mono_environment_exitcode_set (rval);
2431                 }
2432         }
2433
2434         return rval;
2435 }
2436
2437 /**
2438  * mono_install_runtime_invoke:
2439  * @func: Function to install
2440  *
2441  * This is a VM internal routine
2442  */
2443 void
2444 mono_install_runtime_invoke (MonoInvokeFunc func)
2445 {
2446         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2447 }
2448
2449 /**
2450  * mono_runtime_invoke_array:
2451  * @method: method to invoke
2452  * @obJ: object instance
2453  * @params: arguments to the method
2454  * @exc: exception information.
2455  *
2456  * Invokes the method represented by @method on the object @obj.
2457  *
2458  * obj is the 'this' pointer, it should be NULL for static
2459  * methods, a MonoObject* for object instances and a pointer to
2460  * the value type for value types.
2461  *
2462  * The params array contains the arguments to the method with the
2463  * same convention: MonoObject* pointers for object instances and
2464  * pointers to the value type otherwise. The _invoke_array
2465  * variant takes a C# object[] as the params argument (MonoArray
2466  * *params): in this case the value types are boxed inside the
2467  * respective reference representation.
2468  * 
2469  * From unmanaged code you'll usually use the
2470  * mono_runtime_invoke() variant.
2471  *
2472  * Note that this function doesn't handle virtual methods for
2473  * you, it will exec the exact method you pass: we still need to
2474  * expose a function to lookup the derived class implementation
2475  * of a virtual method (there are examples of this in the code,
2476  * though).
2477  * 
2478  * You can pass NULL as the exc argument if you don't want to
2479  * catch exceptions, otherwise, *exc will be set to the exception
2480  * thrown, if any.  if an exception is thrown, you can't use the
2481  * MonoObject* result from the function.
2482  * 
2483  * If the method returns a value type, it is boxed in an object
2484  * reference.
2485  */
2486 MonoObject*
2487 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
2488                            MonoObject **exc)
2489 {
2490         MonoMethodSignature *sig = mono_method_signature (method);
2491         gpointer *pa = NULL;
2492         int i;
2493
2494         if (NULL != params) {
2495                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
2496                 for (i = 0; i < mono_array_length (params); i++) {
2497                         MonoType *t = sig->params [i];
2498
2499                 again:
2500                         switch (t->type) {
2501                         case MONO_TYPE_U1:
2502                         case MONO_TYPE_I1:
2503                         case MONO_TYPE_BOOLEAN:
2504                         case MONO_TYPE_U2:
2505                         case MONO_TYPE_I2:
2506                         case MONO_TYPE_CHAR:
2507                         case MONO_TYPE_U:
2508                         case MONO_TYPE_I:
2509                         case MONO_TYPE_U4:
2510                         case MONO_TYPE_I4:
2511                         case MONO_TYPE_U8:
2512                         case MONO_TYPE_I8:
2513                         case MONO_TYPE_R4:
2514                         case MONO_TYPE_R8:
2515                         case MONO_TYPE_VALUETYPE:
2516                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
2517                                         if (t->byref)
2518                                                 /* FIXME: */
2519                                                 g_assert_not_reached ();
2520                                         /* The runtime invoke wrapper needs the original boxed vtype */
2521                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
2522                                 } else {
2523                                         /* MS seems to create the objects if a null is passed in */
2524                                         if (!((gpointer *)params->vector)[i])
2525                                                 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
2526
2527                                         if (t->byref) {
2528                                                 /*
2529                                                  * We can't pass the unboxed vtype byref to the callee, since
2530                                                  * that would mean the callee would be able to modify boxed
2531                                                  * primitive types. So we (and MS) make a copy of the boxed
2532                                                  * object, pass that to the callee, and replace the original
2533                                                  * boxed object in the arg array with the copy.
2534                                                  */
2535                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
2536                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
2537                                                 mono_array_setref (params, i, copy);
2538                                         }
2539                                                 
2540                                         pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
2541                                 }
2542                                 break;
2543                         case MONO_TYPE_STRING:
2544                         case MONO_TYPE_OBJECT:
2545                         case MONO_TYPE_CLASS:
2546                         case MONO_TYPE_ARRAY:
2547                         case MONO_TYPE_SZARRAY:
2548                                 if (t->byref)
2549                                         pa [i] = &(((gpointer *)params->vector)[i]);
2550                                 else
2551                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
2552                                 break;
2553                         case MONO_TYPE_GENERICINST:
2554                                 t = &t->data.generic_class->container_class->byval_arg;
2555                                 goto again;
2556                         default:
2557                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2558                         }
2559                 }
2560         }
2561
2562         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2563                 void *o = obj;
2564
2565                 if (mono_class_is_nullable (method->klass)) {
2566                         /* Need to create a boxed vtype instead */
2567                         g_assert (!obj);
2568
2569                         if (!params)
2570                                 return NULL;
2571                         else
2572                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
2573                 }
2574
2575                 if (!obj) {
2576                         obj = mono_object_new (mono_domain_get (), method->klass);
2577                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2578                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2579                         }
2580                         if (method->klass->valuetype)
2581                                 o = mono_object_unbox (obj);
2582                         else
2583                                 o = obj;
2584                 }
2585                 else if (method->klass->valuetype)
2586                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
2587
2588                 mono_runtime_invoke (method, o, pa, exc);
2589                 return obj;
2590         } else {
2591                 /* obj must be already unboxed if needed */
2592                 return mono_runtime_invoke (method, obj, pa, exc);
2593         }
2594 }
2595
2596 static void
2597 arith_overflow (void)
2598 {
2599         mono_raise_exception (mono_get_exception_overflow ());
2600 }
2601
2602 /**
2603  * mono_object_allocate:
2604  * @size: number of bytes to allocate
2605  *
2606  * This is a very simplistic routine until we have our GC-aware
2607  * memory allocator. 
2608  *
2609  * Returns: an allocated object of size @size, or NULL on failure.
2610  */
2611 static inline void *
2612 mono_object_allocate (size_t size, MonoVTable *vtable)
2613 {
2614         MonoObject *o;
2615         mono_stats.new_object_count++;
2616         ALLOC_OBJECT (o, vtable, size);
2617
2618         return o;
2619 }
2620
2621 /**
2622  * mono_object_allocate_ptrfree:
2623  * @size: number of bytes to allocate
2624  *
2625  * Note that the memory allocated is not zeroed.
2626  * Returns: an allocated object of size @size, or NULL on failure.
2627  */
2628 static inline void *
2629 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
2630 {
2631         MonoObject *o;
2632         mono_stats.new_object_count++;
2633         ALLOC_PTRFREE (o, vtable, size);
2634         return o;
2635 }
2636
2637 static inline void *
2638 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
2639 {
2640         void *o;
2641         ALLOC_TYPED (o, size, vtable);
2642         mono_stats.new_object_count++;
2643
2644         return o;
2645 }
2646
2647 /**
2648  * mono_object_new:
2649  * @klass: the class of the object that we want to create
2650  *
2651  * Returns: a newly created object whose definition is
2652  * looked up using @klass.   This will not invoke any constructors, 
2653  * so the consumer of this routine has to invoke any constructors on
2654  * its own to initialize the object.
2655  */
2656 MonoObject *
2657 mono_object_new (MonoDomain *domain, MonoClass *klass)
2658 {
2659         MONO_ARCH_SAVE_REGS;
2660         return mono_object_new_specific (mono_class_vtable (domain, klass));
2661 }
2662
2663 /**
2664  * mono_object_new_specific:
2665  * @vtable: the vtable of the object that we want to create
2666  *
2667  * Returns: A newly created object with class and domain specified
2668  * by @vtable
2669  */
2670 MonoObject *
2671 mono_object_new_specific (MonoVTable *vtable)
2672 {
2673         MonoObject *o;
2674
2675         MONO_ARCH_SAVE_REGS;
2676         
2677         /* check for is_com_object for COM Interop */
2678         if (vtable->remote || vtable->klass->is_com_object)
2679         {
2680                 gpointer pa [1];
2681                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
2682
2683                 if (im == NULL) {
2684                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
2685
2686                         if (!klass->inited)
2687                                 mono_class_init (klass);
2688
2689                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
2690                         g_assert (im);
2691                         vtable->domain->create_proxy_for_type_method = im;
2692                 }
2693         
2694                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2695
2696                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
2697                 if (o != NULL) return o;
2698         }
2699
2700         return mono_object_new_alloc_specific (vtable);
2701 }
2702
2703 MonoObject *
2704 mono_object_new_alloc_specific (MonoVTable *vtable)
2705 {
2706         MonoObject *o;
2707
2708         if (!vtable->klass->has_references) {
2709                 o = mono_object_new_ptrfree (vtable);
2710         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2711                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2712         } else {
2713 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2714                 o = mono_object_allocate (vtable->klass->instance_size, vtable);
2715         }
2716         if (vtable->klass->has_finalize)
2717                 mono_object_register_finalizer (o);
2718         
2719         mono_profiler_allocation (o, vtable->klass);
2720         return o;
2721 }
2722
2723 MonoObject*
2724 mono_object_new_fast (MonoVTable *vtable)
2725 {
2726         MonoObject *o;
2727         ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
2728         return o;
2729 }
2730
2731 static MonoObject*
2732 mono_object_new_ptrfree (MonoVTable *vtable)
2733 {
2734         MonoObject *obj;
2735         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2736 #if NEED_TO_ZERO_PTRFREE
2737         /* an inline memset is much faster for the common vcase of small objects
2738          * note we assume the allocated size is a multiple of sizeof (void*).
2739          */
2740         if (vtable->klass->instance_size < 128) {
2741                 gpointer *p, *end;
2742                 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
2743                 p = (gpointer*)((char*)obj + sizeof (MonoObject));
2744                 while (p < end) {
2745                         *p = NULL;
2746                         ++p;
2747                 }
2748         } else {
2749                 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
2750         }
2751 #endif
2752         return obj;
2753 }
2754
2755 static MonoObject*
2756 mono_object_new_ptrfree_box (MonoVTable *vtable)
2757 {
2758         MonoObject *obj;
2759         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2760         /* the object will be boxed right away, no need to memzero it */
2761         return obj;
2762 }
2763
2764 /**
2765  * mono_class_get_allocation_ftn:
2766  * @vtable: vtable
2767  * @for_box: the object will be used for boxing
2768  * @pass_size_in_words: 
2769  *
2770  * Return the allocation function appropriate for the given class.
2771  */
2772
2773 void*
2774 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
2775 {
2776         *pass_size_in_words = FALSE;
2777
2778         if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2779                 return mono_object_new_specific;
2780
2781         if (!vtable->klass->has_references) {
2782                 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
2783                 if (for_box)
2784                         return mono_object_new_ptrfree_box;
2785                 return mono_object_new_ptrfree;
2786         }
2787
2788         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2789
2790                 return mono_object_new_fast;
2791
2792                 /* 
2793                  * FIXME: This is actually slower than mono_object_new_fast, because
2794                  * of the overhead of parameter passing.
2795                  */
2796                 /*
2797                 *pass_size_in_words = TRUE;
2798 #ifdef GC_REDIRECT_TO_LOCAL
2799                 return GC_local_gcj_fast_malloc;
2800 #else
2801                 return GC_gcj_fast_malloc;
2802 #endif
2803                 */
2804         }
2805
2806         return mono_object_new_specific;
2807 }
2808
2809 /**
2810  * mono_object_new_from_token:
2811  * @image: Context where the type_token is hosted
2812  * @token: a token of the type that we want to create
2813  *
2814  * Returns: A newly created object whose definition is
2815  * looked up using @token in the @image image
2816  */
2817 MonoObject *
2818 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
2819 {
2820         MonoClass *class;
2821
2822         class = mono_class_get (image, token);
2823
2824         return mono_object_new (domain, class);
2825 }
2826
2827
2828 /**
2829  * mono_object_clone:
2830  * @obj: the object to clone
2831  *
2832  * Returns: A newly created object who is a shallow copy of @obj
2833  */
2834 MonoObject *
2835 mono_object_clone (MonoObject *obj)
2836 {
2837         MonoObject *o;
2838         int size;
2839
2840         size = obj->vtable->klass->instance_size;
2841         o = mono_object_allocate (size, obj->vtable);
2842         /* do not copy the sync state */
2843         memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
2844
2845 #ifdef HAVE_SGEN_GC
2846         if (obj->vtable->klass->has_references)
2847                 mono_gc_wbarrier_object (o);
2848 #endif
2849         mono_profiler_allocation (o, obj->vtable->klass);
2850
2851         if (obj->vtable->klass->has_finalize)
2852                 mono_object_register_finalizer (o);
2853         return o;
2854 }
2855
2856 /**
2857  * mono_array_full_copy:
2858  * @src: source array to copy
2859  * @dest: destination array
2860  *
2861  * Copies the content of one array to another with exactly the same type and size.
2862  */
2863 void
2864 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2865 {
2866         int size;
2867         MonoClass *klass = src->obj.vtable->klass;
2868
2869         MONO_ARCH_SAVE_REGS;
2870
2871         g_assert (klass == dest->obj.vtable->klass);
2872
2873         size = mono_array_length (src);
2874         g_assert (size == mono_array_length (dest));
2875         size *= mono_array_element_size (klass);
2876 #ifdef HAVE_SGEN_GC
2877         if (klass->valuetype) {
2878                 if (klass->has_references)
2879                         mono_value_copy_array (dest, 0, src, mono_array_length (src));
2880                 else
2881                         memcpy (&dest->vector, &src->vector, size);
2882         } else {
2883                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
2884         }
2885 #else
2886         memcpy (&dest->vector, &src->vector, size);
2887 #endif
2888 }
2889
2890 /**
2891  * mono_array_clone_in_domain:
2892  * @domain: the domain in which the array will be cloned into
2893  * @array: the array to clone
2894  *
2895  * This routine returns a copy of the array that is hosted on the
2896  * specified MonoDomain.
2897  */
2898 MonoArray*
2899 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2900 {
2901         MonoArray *o;
2902         guint32 size, i;
2903         guint32 *sizes;
2904         MonoClass *klass = array->obj.vtable->klass;
2905
2906         MONO_ARCH_SAVE_REGS;
2907
2908         if (array->bounds == NULL) {
2909                 size = mono_array_length (array);
2910                 o = mono_array_new_full (domain, klass, &size, NULL);
2911
2912                 size *= mono_array_element_size (klass);
2913 #ifdef HAVE_SGEN_GC
2914                 if (klass->valuetype) {
2915                         if (klass->has_references)
2916                                 mono_value_copy_array (o, 0, array, mono_array_length (array));
2917                         else
2918                                 memcpy (&o->vector, &array->vector, size);
2919                 } else {
2920                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
2921                 }
2922 #else
2923                 memcpy (&o->vector, &array->vector, size);
2924 #endif
2925                 return o;
2926         }
2927         
2928         sizes = alloca (klass->rank * sizeof(guint32) * 2);
2929         size = mono_array_element_size (klass);
2930         for (i = 0; i < klass->rank; ++i) {
2931                 sizes [i] = array->bounds [i].length;
2932                 size *= array->bounds [i].length;
2933                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2934         }
2935         o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2936 #ifdef HAVE_SGEN_GC
2937         if (klass->valuetype) {
2938                 if (klass->has_references)
2939                         mono_value_copy_array (o, 0, array, mono_array_length (array));
2940                 else
2941                         memcpy (&o->vector, &array->vector, size);
2942         } else {
2943                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
2944         }
2945 #else
2946         memcpy (&o->vector, &array->vector, size);
2947 #endif
2948
2949         return o;
2950 }
2951
2952 /**
2953  * mono_array_clone:
2954  * @array: the array to clone
2955  *
2956  * Returns: A newly created array who is a shallow copy of @array
2957  */
2958 MonoArray*
2959 mono_array_clone (MonoArray *array)
2960 {
2961         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2962 }
2963
2964 /* helper macros to check for overflow when calculating the size of arrays */
2965 #define MYGUINT32_MAX 4294967295U
2966 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2967         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2968 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2969         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2970         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2971
2972 /**
2973  * mono_array_new_full:
2974  * @domain: domain where the object is created
2975  * @array_class: array class
2976  * @lengths: lengths for each dimension in the array
2977  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2978  *
2979  * This routine creates a new array objects with the given dimensions,
2980  * lower bounds and type.
2981  */
2982 MonoArray*
2983 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
2984 {
2985         guint32 byte_len, len, bounds_size;
2986         MonoObject *o;
2987         MonoArray *array;
2988         MonoVTable *vtable;
2989         int i;
2990
2991         if (!array_class->inited)
2992                 mono_class_init (array_class);
2993
2994         byte_len = mono_array_element_size (array_class);
2995         len = 1;
2996
2997         /* A single dimensional array with a 0 lower bound is the same as an szarray */
2998         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
2999                 len = lengths [0];
3000                 if ((int) len < 0)
3001                         arith_overflow ();
3002                 bounds_size = 0;
3003         } else {
3004                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3005
3006                 for (i = 0; i < array_class->rank; ++i) {
3007                         if ((int) lengths [i] < 0)
3008                                 arith_overflow ();
3009                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3010                                 mono_gc_out_of_memory (MYGUINT32_MAX);
3011                         len *= lengths [i];
3012                 }
3013         }
3014
3015         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3016                 mono_gc_out_of_memory (MYGUINT32_MAX);
3017         byte_len *= len;
3018         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3019                 mono_gc_out_of_memory (MYGUINT32_MAX);
3020         byte_len += sizeof (MonoArray);
3021         if (bounds_size) {
3022                 /* align */
3023                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3024                         mono_gc_out_of_memory (MYGUINT32_MAX);
3025                 byte_len = (byte_len + 3) & ~3;
3026                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3027                         mono_gc_out_of_memory (MYGUINT32_MAX);
3028                 byte_len += bounds_size;
3029         }
3030         /* 
3031          * Following three lines almost taken from mono_object_new ():
3032          * they need to be kept in sync.
3033          */
3034         vtable = mono_class_vtable (domain, array_class);
3035         if (!array_class->has_references) {
3036                 o = mono_object_allocate_ptrfree (byte_len, vtable);
3037 #if NEED_TO_ZERO_PTRFREE
3038                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3039 #endif
3040         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3041                 o = mono_object_allocate_spec (byte_len, vtable);
3042         }else {
3043                 o = mono_object_allocate (byte_len, vtable);
3044         }
3045
3046         array = (MonoArray*)o;
3047         array->max_length = len;
3048
3049         if (bounds_size) {
3050                 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3051                 array->bounds = bounds;
3052                 for (i = 0; i < array_class->rank; ++i) {
3053                         bounds [i].length = lengths [i];
3054                         if (lower_bounds)
3055                                 bounds [i].lower_bound = lower_bounds [i];
3056                 }
3057         }
3058
3059         mono_profiler_allocation (o, array_class);
3060
3061         return array;
3062 }
3063
3064 /**
3065  * mono_array_new:
3066  * @domain: domain where the object is created
3067  * @eclass: element class
3068  * @n: number of array elements
3069  *
3070  * This routine creates a new szarray with @n elements of type @eclass.
3071  */
3072 MonoArray *
3073 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
3074 {
3075         MonoClass *ac;
3076
3077         MONO_ARCH_SAVE_REGS;
3078
3079         ac = mono_array_class_get (eclass, 1);
3080         g_assert (ac != NULL);
3081
3082         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3083 }
3084
3085 /**
3086  * mono_array_new_specific:
3087  * @vtable: a vtable in the appropriate domain for an initialized class
3088  * @n: number of array elements
3089  *
3090  * This routine is a fast alternative to mono_array_new() for code which
3091  * can be sure about the domain it operates in.
3092  */
3093 MonoArray *
3094 mono_array_new_specific (MonoVTable *vtable, guint32 n)
3095 {
3096         MonoObject *o;
3097         MonoArray *ao;
3098         guint32 byte_len, elem_size;
3099
3100         MONO_ARCH_SAVE_REGS;
3101
3102         if ((int) n < 0)
3103                 arith_overflow ();
3104         
3105         elem_size = mono_array_element_size (vtable->klass);
3106         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
3107                 mono_gc_out_of_memory (MYGUINT32_MAX);
3108         byte_len = n * elem_size;
3109         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3110                 mono_gc_out_of_memory (MYGUINT32_MAX);
3111         byte_len += sizeof (MonoArray);
3112         if (!vtable->klass->has_references) {
3113                 o = mono_object_allocate_ptrfree (byte_len, vtable);
3114 #if NEED_TO_ZERO_PTRFREE
3115                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3116 #endif
3117         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3118                 o = mono_object_allocate_spec (byte_len, vtable);
3119         } else {
3120 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3121                 o = mono_object_allocate (byte_len, vtable);
3122         }
3123
3124         ao = (MonoArray *)o;
3125         ao->bounds = NULL;
3126         ao->max_length = n;
3127         mono_profiler_allocation (o, vtable->klass);
3128
3129         return ao;
3130 }
3131
3132 /**
3133  * mono_string_new_utf16:
3134  * @text: a pointer to an utf16 string
3135  * @len: the length of the string
3136  *
3137  * Returns: A newly created string object which contains @text.
3138  */
3139 MonoString *
3140 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3141 {
3142         MonoString *s;
3143         
3144         s = mono_string_new_size (domain, len);
3145         g_assert (s != NULL);
3146
3147         memcpy (mono_string_chars (s), text, len * 2);
3148
3149         return s;
3150 }
3151
3152 /**
3153  * mono_string_new_size:
3154  * @text: a pointer to an utf16 string
3155  * @len: the length of the string
3156  *
3157  * Returns: A newly created string object of @len
3158  */
3159 MonoString *
3160 mono_string_new_size (MonoDomain *domain, gint32 len)
3161 {
3162         MonoString *s;
3163         MonoVTable *vtable;
3164         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3165
3166         /* overflow ? can't fit it, can't allocate it! */
3167         if (len > size)
3168                 mono_gc_out_of_memory (-1);
3169
3170         vtable = mono_class_vtable (domain, mono_defaults.string_class);
3171
3172         s = mono_object_allocate_ptrfree (size, vtable);
3173
3174         s->length = len;
3175 #if NEED_TO_ZERO_PTRFREE
3176         s->chars [len] = 0;
3177 #endif
3178         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3179
3180         return s;
3181 }
3182
3183 /**
3184  * mono_string_new_len:
3185  * @text: a pointer to an utf8 string
3186  * @length: number of bytes in @text to consider
3187  *
3188  * Returns: A newly created string object which contains @text.
3189  */
3190 MonoString*
3191 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3192 {
3193         GError *error = NULL;
3194         MonoString *o = NULL;
3195         guint16 *ut;
3196         glong items_written;
3197
3198         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3199
3200         if (!error)
3201                 o = mono_string_new_utf16 (domain, ut, items_written);
3202         else 
3203                 g_error_free (error);
3204
3205         g_free (ut);
3206
3207         return o;
3208 }
3209
3210 /**
3211  * mono_string_new:
3212  * @text: a pointer to an utf8 string
3213  *
3214  * Returns: A newly created string object which contains @text.
3215  */
3216 MonoString*
3217 mono_string_new (MonoDomain *domain, const char *text)
3218 {
3219         GError *error = NULL;
3220         MonoString *o = NULL;
3221         guint16 *ut;
3222         glong items_written;
3223         int l;
3224
3225         l = strlen (text);
3226         
3227         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3228
3229         if (!error)
3230                 o = mono_string_new_utf16 (domain, ut, items_written);
3231         else 
3232                 g_error_free (error);
3233
3234         g_free (ut);
3235
3236         return o;
3237 }
3238
3239 /**
3240  * mono_string_new_wrapper:
3241  * @text: pointer to utf8 characters.
3242  *
3243  * Helper function to create a string object from @text in the current domain.
3244  */
3245 MonoString*
3246 mono_string_new_wrapper (const char *text)
3247 {
3248         MonoDomain *domain = mono_domain_get ();
3249
3250         MONO_ARCH_SAVE_REGS;
3251
3252         if (text)
3253                 return mono_string_new (domain, text);
3254
3255         return NULL;
3256 }
3257
3258 /**
3259  * mono_value_box:
3260  * @class: the class of the value
3261  * @value: a pointer to the unboxed data
3262  *
3263  * Returns: A newly created object which contains @value.
3264  */
3265 MonoObject *
3266 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3267 {
3268         MonoObject *res;
3269         int size;
3270         MonoVTable *vtable;
3271
3272         g_assert (class->valuetype);
3273
3274         vtable = mono_class_vtable (domain, class);
3275         size = mono_class_instance_size (class);
3276         res = mono_object_allocate (size, vtable);
3277         mono_profiler_allocation (res, class);
3278
3279         size = size - sizeof (MonoObject);
3280
3281 #ifdef HAVE_SGEN_GC
3282         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3283 #endif
3284
3285 #if NO_UNALIGNED_ACCESS
3286         memcpy ((char *)res + sizeof (MonoObject), value, size);
3287 #else
3288         switch (size) {
3289         case 1:
3290                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3291                 break;
3292         case 2:
3293                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3294                 break;
3295         case 4:
3296                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3297                 break;
3298         case 8:
3299                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3300                 break;
3301         default:
3302                 memcpy ((char *)res + sizeof (MonoObject), value, size);
3303         }
3304 #endif
3305         if (class->has_finalize)
3306                 mono_object_register_finalizer (res);
3307         return res;
3308 }
3309
3310 /*
3311  * mono_value_copy:
3312  * @dest: destination pointer
3313  * @src: source pointer
3314  * @klass: a valuetype class
3315  *
3316  * Copy a valuetype from @src to @dest. This function must be used
3317  * when @klass contains references fields.
3318  */
3319 void
3320 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3321 {
3322         int size = mono_class_value_size (klass, NULL);
3323         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3324         memcpy (dest, src, size);
3325 }
3326
3327 /*
3328  * mono_value_copy_array:
3329  * @dest: destination array
3330  * @dest_idx: index in the @dest array
3331  * @src: source pointer
3332  * @count: number of items
3333  *
3334  * Copy @count valuetype items from @src to @dest. This function must be used
3335  * when @klass contains references fields.
3336  * Overlap is handled.
3337  */
3338 void
3339 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3340 {
3341         int size = mono_array_element_size (dest->obj.vtable->klass);
3342         char *d = mono_array_addr_with_size (dest, size, dest_idx);
3343         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3344         memmove (d, src, size * count);
3345 }
3346
3347 /**
3348  * mono_object_get_domain:
3349  * @obj: object to query
3350  * 
3351  * Returns: the MonoDomain where the object is hosted
3352  */
3353 MonoDomain*
3354 mono_object_get_domain (MonoObject *obj)
3355 {
3356         return mono_object_domain (obj);
3357 }
3358
3359 /**
3360  * mono_object_get_class:
3361  * @obj: object to query
3362  * 
3363  * Returns: the MonOClass of the object.
3364  */
3365 MonoClass*
3366 mono_object_get_class (MonoObject *obj)
3367 {
3368         return mono_object_class (obj);
3369 }
3370 /**
3371  * mono_object_get_size:
3372  * @o: object to query
3373  * 
3374  * Returns: the size, in bytes, of @o
3375  */
3376 guint
3377 mono_object_get_size (MonoObject* o)
3378 {
3379         MonoClass* klass = mono_object_class (o);
3380         if (klass == mono_defaults.string_class) {
3381                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
3382         } else if (o->vtable->rank) {
3383                 MonoArray *array = (MonoArray*)o;
3384                 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
3385                 if (array->bounds) {
3386                         size += 3;
3387                         size &= ~3;
3388                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
3389                 }
3390                 return size;
3391         } else {
3392                 return mono_class_instance_size (klass);
3393         }
3394 }
3395
3396 /**
3397  * mono_object_unbox:
3398  * @obj: object to unbox
3399  * 
3400  * Returns: a pointer to the start of the valuetype boxed in this
3401  * object.
3402  *
3403  * This method will assert if the object passed is not a valuetype.
3404  */
3405 gpointer
3406 mono_object_unbox (MonoObject *obj)
3407 {
3408         /* add assert for valuetypes? */
3409         g_assert (obj->vtable->klass->valuetype);
3410         return ((char*)obj) + sizeof (MonoObject);
3411 }
3412
3413 /**
3414  * mono_object_isinst:
3415  * @obj: an object
3416  * @klass: a pointer to a class 
3417  *
3418  * Returns: @obj if @obj is derived from @klass
3419  */
3420 MonoObject *
3421 mono_object_isinst (MonoObject *obj, MonoClass *klass)
3422 {
3423         if (!klass->inited)
3424                 mono_class_init (klass);
3425
3426         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
3427                 return mono_object_isinst_mbyref (obj, klass);
3428
3429         if (!obj)
3430                 return NULL;
3431
3432         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
3433 }
3434
3435 MonoObject *
3436 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
3437 {
3438         MonoVTable *vt;
3439
3440         if (!obj)
3441                 return NULL;
3442
3443         vt = obj->vtable;
3444         
3445         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3446                 if (klass->interface_id <= vt->max_interface_id) {
3447                         /* the interface_offsets array is stored before the vtable */
3448                         gpointer *interface_offsets = (gpointer*)vt;
3449                         if (interface_offsets [- (klass->interface_id + 1)] != NULL)
3450                                 return obj;
3451                 }
3452         } else {
3453                 MonoClass *oklass = vt->klass;
3454                 if ((oklass == mono_defaults.transparent_proxy_class))
3455                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
3456         
3457                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
3458                         return obj;
3459         }
3460
3461         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
3462         {
3463                 MonoDomain *domain = mono_domain_get ();
3464                 MonoObject *res;
3465                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
3466                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
3467                 MonoMethod *im = NULL;
3468                 gpointer pa [2];
3469
3470                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
3471                 im = mono_object_get_virtual_method (rp, im);
3472                 g_assert (im);
3473         
3474                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
3475                 pa [1] = obj;
3476
3477                 res = mono_runtime_invoke (im, rp, pa, NULL);
3478         
3479                 if (*(MonoBoolean *) mono_object_unbox(res)) {
3480                         /* Update the vtable of the remote type, so it can safely cast to this new type */
3481                         mono_upgrade_remote_class (domain, obj, klass);
3482                         return obj;
3483                 }
3484         }
3485
3486         return NULL;
3487 }
3488
3489 /**
3490  * mono_object_castclass_mbyref:
3491  * @obj: an object
3492  * @klass: a pointer to a class 
3493  *
3494  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
3495  */
3496 MonoObject *
3497 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
3498 {
3499         if (!obj) return NULL;
3500         if (mono_object_isinst_mbyref (obj, klass)) return obj;
3501                 
3502         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
3503                                                         "System",
3504                                                         "InvalidCastException"));
3505         return NULL;
3506 }
3507
3508 typedef struct {
3509         MonoDomain *orig_domain;
3510         MonoString *ins;
3511         MonoString *res;
3512 } LDStrInfo;
3513
3514 static void
3515 str_lookup (MonoDomain *domain, gpointer user_data)
3516 {
3517         LDStrInfo *info = user_data;
3518         if (info->res || domain == info->orig_domain)
3519                 return;
3520         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
3521 }
3522
3523 #ifdef HAVE_SGEN_GC
3524
3525 static MonoString*
3526 mono_string_get_pinned (MonoString *str)
3527 {
3528         int size;
3529         MonoString *news;
3530         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
3531         news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
3532         memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
3533         news->length = mono_string_length (str);
3534         return news;
3535 }
3536
3537 #else
3538 #define mono_string_get_pinned(str) (str)
3539 #endif
3540
3541 static MonoString*
3542 mono_string_is_interned_lookup (MonoString *str, int insert)
3543 {
3544         MonoGHashTable *ldstr_table;
3545         MonoString *res;
3546         MonoDomain *domain;
3547         
3548         domain = ((MonoObject *)str)->vtable->domain;
3549         ldstr_table = domain->ldstr_table;
3550         ldstr_lock ();
3551         if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
3552                 ldstr_unlock ();
3553                 return res;
3554         }
3555         if (insert) {
3556                 str = mono_string_get_pinned (str);
3557                 mono_g_hash_table_insert (ldstr_table, str, str);
3558                 ldstr_unlock ();
3559                 return str;
3560         } else {
3561                 LDStrInfo ldstr_info;
3562                 ldstr_info.orig_domain = domain;
3563                 ldstr_info.ins = str;
3564                 ldstr_info.res = NULL;
3565
3566                 mono_domain_foreach (str_lookup, &ldstr_info);
3567                 if (ldstr_info.res) {
3568                         /* 
3569                          * the string was already interned in some other domain:
3570                          * intern it in the current one as well.
3571                          */
3572                         mono_g_hash_table_insert (ldstr_table, str, str);
3573                         ldstr_unlock ();
3574                         return str;
3575                 }
3576         }
3577         ldstr_unlock ();
3578         return NULL;
3579 }
3580
3581 /**
3582  * mono_string_is_interned:
3583  * @o: String to probe
3584  *
3585  * Returns whether the string has been interned.
3586  */
3587 MonoString*
3588 mono_string_is_interned (MonoString *o)
3589 {
3590         return mono_string_is_interned_lookup (o, FALSE);
3591 }
3592
3593 /**
3594  * mono_string_intern:
3595  * @o: String to intern
3596  *
3597  * Interns the string passed.  
3598  * Returns: The interned string.
3599  */
3600 MonoString*
3601 mono_string_intern (MonoString *str)
3602 {
3603         return mono_string_is_interned_lookup (str, TRUE);
3604 }
3605
3606 /**
3607  * mono_ldstr:
3608  * @domain: the domain where the string will be used.
3609  * @image: a metadata context
3610  * @idx: index into the user string table.
3611  * 
3612  * Implementation for the ldstr opcode.
3613  * Returns: a loaded string from the @image/@idx combination.
3614  */
3615 MonoString*
3616 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
3617 {
3618         MONO_ARCH_SAVE_REGS;
3619
3620         if (image->dynamic)
3621                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
3622         else
3623                 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
3624 }
3625
3626 /**
3627  * mono_ldstr_metdata_sig
3628  * @domain: the domain for the string
3629  * @sig: the signature of a metadata string
3630  *
3631  * Returns: a MonoString for a string stored in the metadata
3632  */
3633 static MonoString*
3634 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
3635 {
3636         const char *str = sig;
3637         MonoString *o, *interned;
3638         size_t len2;
3639         
3640         len2 = mono_metadata_decode_blob_size (str, &str);
3641         len2 >>= 1;
3642
3643         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
3644 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
3645         {
3646                 int i;
3647                 guint16 *p2 = (guint16*)mono_string_chars (o);
3648                 for (i = 0; i < len2; ++i) {
3649                         *p2 = GUINT16_FROM_LE (*p2);
3650                         ++p2;
3651                 }
3652         }
3653 #endif
3654         ldstr_lock ();
3655         if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
3656                 ldstr_unlock ();
3657                 /* o will get garbage collected */
3658                 return interned;
3659         }
3660
3661         o = mono_string_get_pinned (o);
3662         mono_g_hash_table_insert (domain->ldstr_table, o, o);
3663         ldstr_unlock ();
3664
3665         return o;
3666 }
3667
3668 /**
3669  * mono_string_to_utf8:
3670  * @s: a System.String
3671  *
3672  * Return the UTF8 representation for @s.
3673  * the resulting buffer nedds to be freed with g_free().
3674  */
3675 char *
3676 mono_string_to_utf8 (MonoString *s)
3677 {
3678         char *as;
3679         GError *error = NULL;
3680
3681         if (s == NULL)
3682                 return NULL;
3683
3684         if (!s->length)
3685                 return g_strdup ("");
3686
3687         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
3688         if (error) {
3689                 MonoException *exc = mono_get_exception_argument ("string", error->message);
3690                 g_error_free (error);
3691                 mono_raise_exception(exc);
3692         }
3693
3694         return as;
3695 }
3696
3697 /**
3698  * mono_string_to_utf16:
3699  * @s: a MonoString
3700  *
3701  * Return an null-terminated array of the utf-16 chars
3702  * contained in @s. The result must be freed with g_free().
3703  * This is a temporary helper until our string implementation
3704  * is reworked to always include the null terminating char.
3705  */
3706 gunichar2 *
3707 mono_string_to_utf16 (MonoString *s)
3708 {
3709         char *as;
3710
3711         if (s == NULL)
3712                 return NULL;
3713
3714         as = g_malloc ((s->length * 2) + 2);
3715         as [(s->length * 2)] = '\0';
3716         as [(s->length * 2) + 1] = '\0';
3717
3718         if (!s->length) {
3719                 return (gunichar2 *)(as);
3720         }
3721         
3722         memcpy (as, mono_string_chars(s), s->length * 2);
3723         return (gunichar2 *)(as);
3724 }
3725
3726 /**
3727  * mono_string_from_utf16:
3728  * @data: the UTF16 string (LPWSTR) to convert
3729  *
3730  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
3731  *
3732  * Returns: a MonoString.
3733  */
3734 MonoString *
3735 mono_string_from_utf16 (gunichar2 *data)
3736 {
3737         MonoDomain *domain = mono_domain_get ();
3738         int len = 0;
3739
3740         if (!data)
3741                 return NULL;
3742
3743         while (data [len]) len++;
3744
3745         return mono_string_new_utf16 (domain, data, len);
3746 }
3747
3748 /**
3749  * mono_string_to_utf8_mp:
3750  * @s: a System.String
3751  *
3752  * Same as mono_string_to_utf8, but allocate the string from a mempool.
3753  */
3754 char *
3755 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
3756 {
3757         char *r = mono_string_to_utf8 (s);
3758         char *mp_s;
3759         int len;
3760
3761         if (!r)
3762                 return NULL;
3763
3764         len = strlen (r) + 1;
3765         mp_s = mono_mempool_alloc (mp, len);
3766         memcpy (mp_s, r, len);
3767
3768         g_free (r);
3769
3770         return mp_s;
3771 }
3772
3773 static void
3774 default_ex_handler (MonoException *ex)
3775 {
3776         MonoObject *o = (MonoObject*)ex;
3777         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
3778         exit (1);
3779 }
3780
3781 static MonoExceptionFunc ex_handler = default_ex_handler;
3782
3783 /**
3784  * mono_install_handler:
3785  * @func: exception handler
3786  *
3787  * This is an internal JIT routine used to install the handler for exceptions
3788  * being throwh.
3789  */
3790 void
3791 mono_install_handler (MonoExceptionFunc func)
3792 {
3793         ex_handler = func? func: default_ex_handler;
3794 }
3795
3796 /**
3797  * mono_raise_exception:
3798  * @ex: exception object
3799  *
3800  * Signal the runtime that the exception @ex has been raised in unmanaged code.
3801  */
3802 void
3803 mono_raise_exception (MonoException *ex) 
3804 {
3805         /*
3806          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
3807          * that will cause gcc to omit the function epilog, causing problems when
3808          * the JIT tries to walk the stack, since the return address on the stack
3809          * will point into the next function in the executable, not this one.
3810          */
3811
3812         if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
3813                 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
3814         
3815         ex_handler (ex);
3816 }
3817
3818 /**
3819  * mono_wait_handle_new:
3820  * @domain: Domain where the object will be created
3821  * @handle: Handle for the wait handle
3822  *
3823  * Returns: A new MonoWaitHandle created in the given domain for the given handle
3824  */
3825 MonoWaitHandle *
3826 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
3827 {
3828         MonoWaitHandle *res;
3829         gpointer params [1];
3830         static MonoMethod *handle_set;
3831
3832         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
3833
3834         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
3835         if (!handle_set)
3836                 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
3837
3838         params [0] = &handle;
3839         mono_runtime_invoke (handle_set, res, params, NULL);
3840
3841         return res;
3842 }
3843
3844 HANDLE
3845 mono_wait_handle_get_handle (MonoWaitHandle *handle)
3846 {
3847         static MonoClassField *f_os_handle;
3848         static MonoClassField *f_safe_handle;
3849
3850         if (!f_os_handle && !f_safe_handle) {
3851                 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
3852                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
3853         }
3854
3855         if (f_os_handle) {
3856                 HANDLE retval;
3857                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
3858                 return retval;
3859         } else {
3860                 MonoSafeHandle *sh;
3861                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
3862                 return sh->handle;
3863         }
3864 }
3865
3866 /**
3867  * mono_async_result_new:
3868  * @domain:domain where the object will be created.
3869  * @handle: wait handle.
3870  * @state: state to pass to AsyncResult
3871  * @data: C closure data.
3872  *
3873  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3874  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3875  *
3876  */
3877 MonoAsyncResult *
3878 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
3879 {
3880         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3881         MonoMethod *method = mono_get_context_capture_method ();
3882
3883         /* we must capture the execution context from the original thread */
3884         if (method) {
3885                 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
3886                 /* note: result may be null if the flow is suppressed */
3887         }
3888
3889         res->data = data;
3890         MONO_OBJECT_SETREF (res, object_data, object_data);
3891         MONO_OBJECT_SETREF (res, async_state, state);
3892         if (handle != NULL)
3893                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
3894
3895         res->sync_completed = FALSE;
3896         res->completed = FALSE;
3897
3898         return res;
3899 }
3900
3901 void
3902 mono_message_init (MonoDomain *domain,
3903                    MonoMethodMessage *this, 
3904                    MonoReflectionMethod *method,
3905                    MonoArray *out_args)
3906 {
3907         MonoMethodSignature *sig = mono_method_signature (method->method);
3908         MonoString *name;
3909         int i, j;
3910         char **names;
3911         guint8 arg_type;
3912
3913         MONO_OBJECT_SETREF (this, method, method);
3914
3915         MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
3916         MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
3917         this->async_result = NULL;
3918         this->call_type = CallType_Sync;
3919
3920         names = g_new (char *, sig->param_count);
3921         mono_method_get_param_names (method->method, (const char **) names);
3922         MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
3923         
3924         for (i = 0; i < sig->param_count; i++) {
3925                  name = mono_string_new (domain, names [i]);
3926                  mono_array_setref (this->names, i, name);      
3927         }
3928
3929         g_free (names);
3930         for (i = 0, j = 0; i < sig->param_count; i++) {
3931
3932                 if (sig->params [i]->byref) {
3933                         if (out_args) {
3934                                 MonoObject* arg = mono_array_get (out_args, gpointer, j);
3935                                 mono_array_setref (this->args, i, arg);
3936                                 j++;
3937                         }
3938                         arg_type = 2;
3939                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3940                                 arg_type |= 1;
3941                 } else {
3942                         arg_type = 1;
3943                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
3944                                 arg_type |= 4;
3945                 }
3946                 mono_array_set (this->arg_types, guint8, i, arg_type);
3947         }
3948 }
3949
3950 /**
3951  * mono_remoting_invoke:
3952  * @real_proxy: pointer to a RealProxy object
3953  * @msg: The MonoMethodMessage to execute
3954  * @exc: used to store exceptions
3955  * @out_args: used to store output arguments
3956  *
3957  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3958  * IMessage interface and it is not trivial to extract results from there. So
3959  * we call an helper method PrivateInvoke instead of calling
3960  * RealProxy::Invoke() directly.
3961  *
3962  * Returns: the result object.
3963  */
3964 MonoObject *
3965 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
3966                       MonoObject **exc, MonoArray **out_args)
3967 {
3968         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3969         gpointer pa [4];
3970
3971         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3972
3973         if (!im) {
3974                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
3975                 g_assert (im);
3976                 real_proxy->vtable->domain->private_invoke_method = im;
3977         }
3978
3979         pa [0] = real_proxy;
3980         pa [1] = msg;
3981         pa [2] = exc;
3982         pa [3] = out_args;
3983
3984         return mono_runtime_invoke (im, NULL, pa, exc);
3985 }
3986
3987 MonoObject *
3988 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
3989                      MonoObject **exc, MonoArray **out_args) 
3990 {
3991         MonoDomain *domain; 
3992         MonoMethod *method;
3993         MonoMethodSignature *sig;
3994         MonoObject *ret;
3995         int i, j, outarg_count = 0;
3996
3997         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3998
3999                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4000                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4001                         target = tp->rp->unwrapped_server;
4002                 } else {
4003                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4004                 }
4005         }
4006
4007         domain = mono_domain_get (); 
4008         method = msg->method->method;
4009         sig = mono_method_signature (method);
4010
4011         for (i = 0; i < sig->param_count; i++) {
4012                 if (sig->params [i]->byref) 
4013                         outarg_count++;
4014         }
4015
4016         /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4017         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
4018         *exc = NULL;
4019
4020         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4021
4022         for (i = 0, j = 0; i < sig->param_count; i++) {
4023                 if (sig->params [i]->byref) {
4024                         MonoObject* arg;
4025                         arg = mono_array_get (msg->args, gpointer, i);
4026                         mono_array_setref (*out_args, j, arg);
4027                         j++;
4028                 }
4029         }
4030
4031         return ret;
4032 }
4033
4034 /**
4035  * mono_print_unhandled_exception:
4036  * @exc: The exception
4037  *
4038  * Prints the unhandled exception.
4039  */
4040 void
4041 mono_print_unhandled_exception (MonoObject *exc)
4042 {
4043         char *message = (char *) "";
4044         MonoString *str; 
4045         MonoMethod *method;
4046         MonoClass *klass;
4047         gboolean free_message = FALSE;
4048
4049         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4050                 klass = exc->vtable->klass;
4051                 method = NULL;
4052                 while (klass && method == NULL) {
4053                         method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4054                         if (method == NULL)
4055                                 klass = klass->parent;
4056                 }
4057
4058                 g_assert (method);
4059
4060                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4061                 if (str) {
4062                         message = mono_string_to_utf8 (str);
4063                         free_message = TRUE;
4064                 }
4065         }                               
4066
4067         /*
4068          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
4069          *         exc->vtable->klass->name, message);
4070          */
4071         g_printerr ("\nUnhandled Exception: %s\n", message);
4072         
4073         if (free_message)
4074                 g_free (message);
4075 }
4076
4077 /**
4078  * mono_delegate_ctor:
4079  * @this: pointer to an uninitialized delegate object
4080  * @target: target object
4081  * @addr: pointer to native code
4082  *
4083  * This is used to initialize a delegate. We also insert the method_info if
4084  * we find the info with mono_jit_info_table_find().
4085  */
4086 void
4087 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4088 {
4089         MonoDomain *domain = mono_domain_get ();
4090         MonoDelegate *delegate = (MonoDelegate *)this;
4091         MonoMethod *method = NULL;
4092         MonoClass *class;
4093         MonoJitInfo *ji;
4094
4095         g_assert (this);
4096         g_assert (addr);
4097
4098         class = this->vtable->klass;
4099
4100         if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4101                 method = ji->method;
4102                 MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, method, NULL));
4103         }
4104
4105         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4106                 g_assert (method);
4107                 method = mono_marshal_get_remoting_invoke (method);
4108                 delegate->method_ptr = mono_compile_method (method);
4109                 MONO_OBJECT_SETREF (delegate, target, target);
4110         } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4111                 method = mono_marshal_get_unbox_wrapper (method);
4112                 delegate->method_ptr = mono_compile_method (method);
4113                 MONO_OBJECT_SETREF (delegate, target, target);
4114         } else {
4115                 if (method) {
4116                         /* 
4117                          * Replace the original trampoline with a delegate trampoline
4118                          * which will patch delegate->method_ptr with the address of the
4119                          * compiled method.
4120                          */
4121                         addr = arch_create_delegate_trampoline (method, addr);
4122                 }
4123                 delegate->method_ptr = addr;
4124                 MONO_OBJECT_SETREF (delegate, target, target);
4125         }
4126 }
4127
4128 /**
4129  * mono_method_call_message_new:
4130  * @method: method to encapsulate
4131  * @params: parameters to the method
4132  * @invoke: optional, delegate invoke.
4133  * @cb: async callback delegate.
4134  * @state: state passed to the async callback.
4135  *
4136  * Translates arguments pointers into a MonoMethodMessage.
4137  */
4138 MonoMethodMessage *
4139 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
4140                               MonoDelegate **cb, MonoObject **state)
4141 {
4142         MonoDomain *domain = mono_domain_get ();
4143         MonoMethodSignature *sig = mono_method_signature (method);
4144         MonoMethodMessage *msg;
4145         int i, count, type;
4146
4147         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
4148         
4149         if (invoke) {
4150                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4151                 count =  sig->param_count - 2;
4152         } else {
4153                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4154                 count =  sig->param_count;
4155         }
4156
4157         for (i = 0; i < count; i++) {
4158                 gpointer vpos;
4159                 MonoClass *class;
4160                 MonoObject *arg;
4161
4162                 if (sig->params [i]->byref)
4163                         vpos = *((gpointer *)params [i]);
4164                 else 
4165                         vpos = params [i];
4166
4167                 type = sig->params [i]->type;
4168                 class = mono_class_from_mono_type (sig->params [i]);
4169
4170                 if (class->valuetype)
4171                         arg = mono_value_box (domain, class, vpos);
4172                 else 
4173                         arg = *((MonoObject **)vpos);
4174                       
4175                 mono_array_setref (msg->args, i, arg);
4176         }
4177
4178         if (cb != NULL && state != NULL) {
4179                 *cb = *((MonoDelegate **)params [i]);
4180                 i++;
4181                 *state = *((MonoObject **)params [i]);
4182         }
4183
4184         return msg;
4185 }
4186
4187 /**
4188  * mono_method_return_message_restore:
4189  *
4190  * Restore results from message based processing back to arguments pointers
4191  */
4192 void
4193 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4194 {
4195         MonoMethodSignature *sig = mono_method_signature (method);
4196         int i, j, type, size, out_len;
4197         
4198         if (out_args == NULL)
4199                 return;
4200         out_len = mono_array_length (out_args);
4201         if (out_len == 0)
4202                 return;
4203
4204         for (i = 0, j = 0; i < sig->param_count; i++) {
4205                 MonoType *pt = sig->params [i];
4206
4207                 if (pt->byref) {
4208                         char *arg;
4209                         if (j >= out_len)
4210                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4211
4212                         arg = mono_array_get (out_args, gpointer, j);
4213                         type = pt->type;
4214
4215                         switch (type) {
4216                         case MONO_TYPE_VOID:
4217                                 g_assert_not_reached ();
4218                                 break;
4219                         case MONO_TYPE_U1:
4220                         case MONO_TYPE_I1:
4221                         case MONO_TYPE_BOOLEAN:
4222                         case MONO_TYPE_U2:
4223                         case MONO_TYPE_I2:
4224                         case MONO_TYPE_CHAR:
4225                         case MONO_TYPE_U4:
4226                         case MONO_TYPE_I4:
4227                         case MONO_TYPE_I8:
4228                         case MONO_TYPE_U8:
4229                         case MONO_TYPE_R4:
4230                         case MONO_TYPE_R8:
4231                         case MONO_TYPE_VALUETYPE: {
4232                                 if (arg) {
4233                                         size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4234                                         memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
4235                                 }
4236                                 else {
4237                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4238                                         memset (*((gpointer *)params [i]), 0, size);
4239                                 }
4240                                 break;
4241                         }
4242                         case MONO_TYPE_STRING:
4243                         case MONO_TYPE_CLASS: 
4244                         case MONO_TYPE_ARRAY:
4245                         case MONO_TYPE_SZARRAY:
4246                         case MONO_TYPE_OBJECT:
4247                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4248                                 break;
4249                         default:
4250                                 g_assert_not_reached ();
4251                         }
4252
4253                         j++;
4254                 }
4255         }
4256 }
4257
4258 /**
4259  * mono_load_remote_field:
4260  * @this: pointer to an object
4261  * @klass: klass of the object containing @field
4262  * @field: the field to load
4263  * @res: a storage to store the result
4264  *
4265  * This method is called by the runtime on attempts to load fields of
4266  * transparent proxy objects. @this points to such TP, @klass is the class of
4267  * the object containing @field. @res is a storage location which can be
4268  * used to store the result.
4269  *
4270  * Returns: an address pointing to the value of field.
4271  */
4272 gpointer
4273 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4274 {
4275         static MonoMethod *getter = NULL;
4276         MonoDomain *domain = mono_domain_get ();
4277         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4278         MonoClass *field_class;
4279         MonoMethodMessage *msg;
4280         MonoArray *out_args;
4281         MonoObject *exc;
4282         char* full_name;
4283
4284         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4285         g_assert (res != NULL);
4286
4287         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4288                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4289                 return res;
4290         }
4291         
4292         if (!getter) {
4293                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4294                 g_assert (getter);
4295         }
4296         
4297         field_class = mono_class_from_mono_type (field->type);
4298
4299         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4300         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4301         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4302
4303         full_name = mono_type_get_full_name (klass);
4304         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4305         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4306         g_free (full_name);
4307
4308         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4309
4310         if (exc) mono_raise_exception ((MonoException *)exc);
4311
4312         if (mono_array_length (out_args) == 0)
4313                 return NULL;
4314
4315         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4316
4317         if (field_class->valuetype) {
4318                 return ((char *)*res) + sizeof (MonoObject);
4319         } else
4320                 return res;
4321 }
4322
4323 /**
4324  * mono_load_remote_field_new:
4325  * @this: 
4326  * @klass: 
4327  * @field:
4328  *
4329  * Missing documentation.
4330  */
4331 MonoObject *
4332 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
4333 {
4334         static MonoMethod *getter = NULL;
4335         MonoDomain *domain = mono_domain_get ();
4336         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4337         MonoClass *field_class;
4338         MonoMethodMessage *msg;
4339         MonoArray *out_args;
4340         MonoObject *exc, *res;
4341         char* full_name;
4342
4343         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4344
4345         field_class = mono_class_from_mono_type (field->type);
4346
4347         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4348                 gpointer val;
4349                 if (field_class->valuetype) {
4350                         res = mono_object_new (domain, field_class);
4351                         val = ((gchar *) res) + sizeof (MonoObject);
4352                 } else {
4353                         val = &res;
4354                 }
4355                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
4356                 return res;
4357         }
4358
4359         if (!getter) {
4360                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4361                 g_assert (getter);
4362         }
4363         
4364         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4365         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4366
4367         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4368
4369         full_name = mono_type_get_full_name (klass);
4370         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4371         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4372         g_free (full_name);
4373
4374         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4375
4376         if (exc) mono_raise_exception ((MonoException *)exc);
4377
4378         if (mono_array_length (out_args) == 0)
4379                 res = NULL;
4380         else
4381                 res = mono_array_get (out_args, MonoObject *, 0);
4382
4383         return res;
4384 }
4385
4386 /**
4387  * mono_store_remote_field:
4388  * @this: pointer to an object
4389  * @klass: klass of the object containing @field
4390  * @field: the field to load
4391  * @val: the value/object to store
4392  *
4393  * This method is called by the runtime on attempts to store fields of
4394  * transparent proxy objects. @this points to such TP, @klass is the class of
4395  * the object containing @field. @val is the new value to store in @field.
4396  */
4397 void
4398 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
4399 {
4400         static MonoMethod *setter = NULL;
4401         MonoDomain *domain = mono_domain_get ();
4402         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4403         MonoClass *field_class;
4404         MonoMethodMessage *msg;
4405         MonoArray *out_args;
4406         MonoObject *exc;
4407         MonoObject *arg;
4408         char* full_name;
4409
4410         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4411
4412         field_class = mono_class_from_mono_type (field->type);
4413
4414         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4415                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
4416                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
4417                 return;
4418         }
4419
4420         if (!setter) {
4421                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4422                 g_assert (setter);
4423         }
4424
4425         if (field_class->valuetype)
4426                 arg = mono_value_box (domain, field_class, val);
4427         else 
4428                 arg = *((MonoObject **)val);
4429                 
4430
4431         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4432         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4433
4434         full_name = mono_type_get_full_name (klass);
4435         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4436         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4437         mono_array_setref (msg->args, 2, arg);
4438         g_free (full_name);
4439
4440         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4441
4442         if (exc) mono_raise_exception ((MonoException *)exc);
4443 }
4444
4445 /**
4446  * mono_store_remote_field_new:
4447  * @this:
4448  * @klass:
4449  * @field:
4450  * @arg:
4451  *
4452  * Missing documentation
4453  */
4454 void
4455 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
4456 {
4457         static MonoMethod *setter = NULL;
4458         MonoDomain *domain = mono_domain_get ();
4459         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4460         MonoClass *field_class;
4461         MonoMethodMessage *msg;
4462         MonoArray *out_args;
4463         MonoObject *exc;
4464         char* full_name;
4465
4466         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4467
4468         field_class = mono_class_from_mono_type (field->type);
4469
4470         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4471                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
4472                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
4473                 return;
4474         }
4475
4476         if (!setter) {
4477                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4478                 g_assert (setter);
4479         }
4480
4481         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4482         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4483
4484         full_name = mono_type_get_full_name (klass);
4485         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4486         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4487         mono_array_setref (msg->args, 2, arg);
4488         g_free (full_name);
4489
4490         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4491
4492         if (exc) mono_raise_exception ((MonoException *)exc);
4493 }
4494
4495 /*
4496  * mono_get_addr_from_ftnptr:
4497  *
4498  *   Given a pointer to a function descriptor, return the function address.
4499  * This is only needed on IA64.
4500  */
4501 gpointer
4502 mono_get_addr_from_ftnptr (gpointer descr)
4503 {
4504 #ifdef __ia64__
4505         return *(gpointer*)descr;
4506 #else
4507         return descr;
4508 #endif
4509 }       
4510
4511 #if 0
4512 /**
4513  * mono_string_chars:
4514  * @s: a MonoString
4515  *
4516  * Returns a pointer to the UCS16 characters stored in the MonoString
4517  */
4518 gunichar2 *
4519 mono_string_chars(MonoString *s)
4520 {
4521         /* This method is here only for documentation extraction, this is a macro */
4522 }
4523
4524 /**
4525  * mono_string_length:
4526  * @s: MonoString
4527  *
4528  * Returns the lenght in characters of the string
4529  */
4530 int
4531 mono_string_length (MonoString *s)
4532 {
4533         /* This method is here only for documentation extraction, this is a macro */
4534 }
4535
4536 #endif