2002-04-06 Dietmar Maurer <dietmar@ximian.com>
[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  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/loader.h>
16 #include <mono/metadata/object.h>
17 #include <mono/metadata/appdomain.h>
18 #if HAVE_BOEHM_GC
19 #include <gc/gc.h>
20 #endif
21
22 void
23 mono_runtime_object_init (MonoObject *this)
24 {
25         int i;
26         MonoMethod *method = NULL;
27         MonoClass *klass = this->vtable->klass;
28
29         for (i = 0; i < klass->method.count; ++i) {
30                 if (!strcmp (".ctor", klass->methods [i]->name) &&
31                     klass->methods [i]->signature->param_count == 0) {
32                         method = klass->methods [i];
33                         break;
34                 }
35         }
36
37         g_assert (method);
38
39         mono_runtime_invoke (method, this, NULL);
40 }
41
42 /*
43  * runtime_class_init:
44  * @klass: klass that needs to be initialized
45  *
46  * This routine calls the class constructor for @class.
47  */
48 void
49 mono_runtime_class_init (MonoClass *klass)
50 {
51         int i;
52
53         for (i = 0; i < klass->method.count; ++i) {
54                 MonoMethod *method = klass->methods [i];
55                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
56                     (strcmp (".cctor", method->name) == 0)) {
57                         mono_runtime_invoke (method, NULL, NULL);
58                         return;
59                 }
60         }
61         /* No class constructor found */
62
63 }
64
65 static MonoInvokeFunc default_mono_runtime_invoke = NULL;
66
67 MonoObject*
68 mono_runtime_invoke (MonoMethod *method, void *obj, void **params)
69 {
70         if (!default_mono_runtime_invoke) {
71                 g_error ("runtime invoke called on uninitialized runtime");
72                 return NULL;
73         }
74         return default_mono_runtime_invoke (method, obj, params);
75 }
76
77 int
78 mono_runtime_exec_main (MonoMethod *method, MonoArray *args)
79 {
80         gpointer pa [1];
81
82         pa [0] = args;
83
84         if (method->signature->ret->type == MONO_TYPE_I4) {
85                 MonoObject *res;
86                 res = mono_runtime_invoke (method, NULL, pa);
87                 return *(guint32 *)((char *)res + sizeof (MonoObject));
88         } else {
89                 mono_runtime_invoke (method, NULL, pa);
90                 return 0;
91         }
92 }
93
94 void
95 mono_install_runtime_invoke (MonoInvokeFunc func)
96 {
97         default_mono_runtime_invoke = func;
98 }
99
100 MonoObject*
101 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params)
102 {
103         MonoMethodSignature *sig = method->signature;
104         gpointer *pa;
105         int i;
106
107         pa = alloca (sizeof (gpointer) * params->bounds->length);
108
109         for (i = 0; i < params->bounds->length; i++) {
110                 if (sig->params [i]->byref) {
111                         /* nothing to do */
112                 }
113
114                 switch (sig->params [i]->type) {
115                 case MONO_TYPE_U1:
116                 case MONO_TYPE_I1:
117                 case MONO_TYPE_BOOLEAN:
118                 case MONO_TYPE_U2:
119                 case MONO_TYPE_I2:
120                 case MONO_TYPE_CHAR:
121                 case MONO_TYPE_U:
122                 case MONO_TYPE_I:
123                 case MONO_TYPE_U4:
124                 case MONO_TYPE_I4:
125                 case MONO_TYPE_U8:
126                 case MONO_TYPE_I8:
127                 case MONO_TYPE_VALUETYPE:
128                         pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
129                         break;
130                 case MONO_TYPE_STRING:
131                 case MONO_TYPE_OBJECT:
132                 case MONO_TYPE_CLASS:
133                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
134                         break;
135                 default:
136                         g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
137                 }
138         }
139
140         if (!strcmp (method->name, ".ctor")) {
141                 obj = mono_object_new (mono_domain_get (), method->klass);
142                 mono_runtime_invoke (method, obj, pa);
143                 return obj;
144         } else
145                 return mono_runtime_invoke (method, obj, pa);
146 }
147
148 /**
149  * mono_object_allocate:
150  * @size: number of bytes to allocate
151  *
152  * This is a very simplistic routine until we have our GC-aware
153  * memory allocator. 
154  *
155  * Returns: an allocated object of size @size, or NULL on failure.
156  */
157 void *
158 mono_object_allocate (size_t size)
159 {
160 #if HAVE_BOEHM_GC
161         void *o = GC_debug_malloc (size, "object", 1);
162 #else
163         void *o = calloc (1, size);
164 #endif
165
166         return o;
167 }
168
169 /**
170  * mono_object_free:
171  *
172  * Frees the memory used by the object.  Debugging purposes
173  * only, as we will have our GC system.
174  */
175 void
176 mono_object_free (MonoObject *o)
177 {
178 #if HAVE_BOEHM_GC
179         g_error ("mono_object_free called with boehm gc.");
180 #else
181         MonoClass *c = o->vtable->klass;
182         
183         memset (o, 0, c->instance_size);
184         free (o);
185 #endif
186 }
187
188 /**
189  * mono_object_new:
190  * @klass: the class of the object that we want to create
191  *
192  * Returns: A newly created object whose definition is
193  * looked up using @klass
194  */
195 MonoObject *
196 mono_object_new (MonoDomain *domain, MonoClass *klass)
197 {
198         static guint32 uoid = 0;
199         MonoObject *o;
200
201         if (!klass->inited)
202                 mono_class_init (klass);
203
204
205         if (klass->ghcimpl) {
206                 o = mono_object_allocate (klass->instance_size);
207                 o->vtable = mono_class_vtable (domain, klass);
208         } else {
209                 guint32 *t;
210                 t = mono_object_allocate (klass->instance_size + 4);
211                 *t = ++uoid;
212                 o = (MonoObject *)(++t);
213                 o->vtable = mono_class_vtable (domain, klass);
214         }
215
216         return o;
217 }
218
219 /**
220  * mono_object_new_from_token:
221  * @image: Context where the type_token is hosted
222  * @token: a token of the type that we want to create
223  *
224  * Returns: A newly created object whose definition is
225  * looked up using @token in the @image image
226  */
227 MonoObject *
228 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
229 {
230         MonoClass *class;
231
232         class = mono_class_get (image, token);
233
234         return mono_object_new (domain, class);
235 }
236
237
238 /**
239  * mono_object_clone:
240  * @obj: the object to clone
241  *
242  * Returns: A newly created object who is a shallow copy of @obj
243  */
244 MonoObject *
245 mono_object_clone (MonoObject *obj)
246 {
247         MonoObject *o;
248         int size;
249
250         size = obj->vtable->klass->instance_size;
251         o = mono_object_allocate (size);
252
253         memcpy (o, obj, size);
254
255         return o;
256 }
257
258 /**
259  * mono_array_clone:
260  * @array: the array to clone
261  *
262  * Returns: A newly created array who is a shallow copy of @array
263  */
264 MonoArray*
265 mono_array_clone (MonoArray *array)
266 {
267         MonoArray *o;
268         int size, i;
269         guint32 *sizes;
270         MonoClass *klass = array->obj.vtable->klass;
271         
272         sizes = alloca (klass->rank * sizeof(guint32) * 2);
273         size = mono_array_element_size (klass);
274         for (i = 0; i < klass->rank; ++i) {
275                 sizes [i] = array->bounds [i].length;
276                 size *= array->bounds [i].length;
277                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
278         }
279         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
280                                  klass, sizes, sizes + klass->rank);
281         memcpy (o, array, sizeof(MonoArray) + size);
282
283         return o;
284 }
285
286 /*
287  * mono_array_new_full:
288  * @domain: domain where the object is created
289  * @array_class: array class
290  * @lengths: lengths for each dimension in the array
291  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
292  *
293  * This routine creates a new array objects with the given dimensions,
294  * lower bounds and type.
295  */
296 MonoArray*
297 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
298                      guint32 *lengths, guint32 *lower_bounds)
299 {
300         guint32 byte_len;
301         MonoObject *o;
302         MonoArray *array;
303         MonoArrayBounds *bounds;
304         int i;
305
306         if (!array_class->inited)
307                 mono_class_init (array_class);
308
309         byte_len = mono_array_element_size (array_class);
310
311 #if HAVE_BOEHM_GC
312         bounds = GC_debug_malloc (sizeof (MonoArrayBounds) * array_class->rank, "bounds", 0);
313 #else
314         bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
315 #endif
316         for (i = 0; i < array_class->rank; ++i) {
317                 bounds [i].length = lengths [i];
318                 byte_len *= lengths [i];
319         }
320
321         if (lower_bounds)
322                 for (i = 0; i < array_class->rank; ++i)
323                         bounds [i].lower_bound = lower_bounds [i];
324         /* 
325          * Following three lines almost taken from mono_object_new ():
326          * they need to be kept in sync.
327          */
328         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
329         if (!o)
330                 G_BREAKPOINT ();
331         o->vtable = mono_class_vtable (domain, array_class);
332
333         array = (MonoArray*)o;
334
335         array->bounds = bounds;
336         array->max_length = bounds [0].length;
337
338         return array;
339 }
340
341 /*
342  * mono_array_new:
343  * @domain: domain where the object is created
344  * @eclass: element class
345  * @n: number of array elements
346  *
347  * This routine creates a new szarray with @n elements of type @eclass.
348  */
349 MonoArray *
350 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
351 {
352         MonoClass *ac;
353
354         ac = mono_array_class_get (&eclass->byval_arg, 1);
355         g_assert (ac != NULL);
356
357         return mono_array_new_full (domain, ac, &n, NULL);
358 }
359
360 /**
361  * mono_string_new_utf16:
362  * @text: a pointer to an utf16 string
363  * @len: the length of the string
364  *
365  * Returns: A newly created string object which contains @text.
366  */
367 MonoString *
368 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
369 {
370         MonoString *s;
371         MonoArray *ca;
372
373         s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
374         g_assert (s != NULL);
375
376         ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
377         g_assert (ca != NULL);
378         
379         s->c_str = ca;
380         s->length = len;
381
382         memcpy (ca->vector, text, len * 2);
383
384         return s;
385 }
386
387 /*
388  * mono_string_new_len:
389  * @text: a pointer to an utf8 string
390  * @length: number of bytes in @text to consider
391  *
392  * Returns: A newly created string object which contains @text.
393  */
394 MonoString*
395 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
396 {
397         GError *error = NULL;
398         MonoString *o = NULL;
399         guint16 *ut;
400         glong items_written;
401
402         
403         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
404
405         if (!error)
406                 o = mono_string_new_utf16 (domain, ut, items_written);
407         else 
408                 g_error_free (error);
409
410         g_free (ut);
411
412         return o;
413 }
414
415 /**
416  * mono_string_new:
417  * @text: a pointer to an utf8 string
418  *
419  * Returns: A newly created string object which contains @text.
420  */
421 MonoString*
422 mono_string_new (MonoDomain *domain, const char *text)
423 {
424         GError *error = NULL;
425         MonoString *o = NULL;
426         guint16 *ut;
427         glong items_written;
428         int l;
429
430         l = strlen (text);
431         
432         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
433
434         if (!error)
435                 o = mono_string_new_utf16 (domain, ut, items_written);
436         else 
437                 g_error_free (error);
438
439         g_free (ut);
440
441         return o;
442 }
443
444 /*
445  * mono_string_new_wrapper:
446  * @text: pointer to utf8 characters.
447  *
448  * Helper function to create a string object from @text in the current domain.
449  */
450 MonoString*
451 mono_string_new_wrapper (const char *text)
452 {
453         MonoDomain *domain = mono_domain_get ();
454
455         return mono_string_new (domain, text);
456 }
457
458 /**
459  * mono_value_box:
460  * @class: the class of the value
461  * @value: a pointer to the unboxed data
462  *
463  * Returns: A newly created object which contains @value.
464  */
465 MonoObject *
466 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
467 {
468         MonoObject *res;
469         int size;
470
471         g_assert (class->valuetype);
472
473         size = mono_class_instance_size (class);
474         res = mono_object_allocate (size);
475         res->vtable = mono_class_vtable (domain, class);
476
477         size = size - sizeof (MonoObject);
478
479         memcpy ((char *)res + sizeof (MonoObject), value, size);
480
481         return res;
482 }
483
484 /**
485  * mono_object_isinst:
486  * @obj: an object
487  * @klass: a pointer to a class 
488  *
489  * Returns: @obj if @obj is derived from @klass
490  */
491 MonoObject *
492 mono_object_isinst (MonoObject *obj, MonoClass *klass)
493 {
494         MonoVTable *vt;
495         MonoClass *oklass;
496
497         if (!obj)
498                 return NULL;
499
500         vt = obj->vtable;
501         oklass = vt->klass;
502
503         if (!klass->inited)
504                 mono_class_init (klass);
505
506         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
507                 if ((klass->interface_id <= oklass->max_interface_id) &&
508                     vt->interface_offsets [klass->interface_id])
509                         return obj;
510         } else {
511                 if (oklass == mono_defaults.transparent_proxy_class) {
512                         /* fixme: add check for IRemotingTypeInfo */
513                         MonoRealProxy *rp = ((MonoTransparentProxy *)obj)->rp;
514                         MonoType *type;
515                         type = ((MonoReflectionType *)rp->class_to_proxy)->type;
516                         oklass = mono_class_from_mono_type (type);
517                 }
518                 if (oklass->rank && oklass->rank == klass->rank) {
519                         if ((oklass->element_class->baseval - klass->element_class->baseval) <= 
520                             klass->element_class->diffval)
521                                 return obj;
522                 } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
523                         return obj;
524         }
525
526         return NULL;
527 }
528
529 static MonoString*
530 mono_string_is_interned_lookup (MonoString *str, int insert)
531 {
532         MonoGHashTable *ldstr_table;
533         MonoString *res;
534         char *ins = g_malloc (4 + str->length * 2);
535         char *p;
536         int bloblen;
537         
538         /* Encode the length */
539         p = ins;
540         mono_metadata_encode_value (2 * str->length, p, &p);
541         bloblen = p - ins;
542         p = ins;
543         mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
544         bloblen = (p - ins) + 2 * str->length;
545         /*
546          * ins is stored in the hash table as a key and needs to have the same
547          * representation as in the metadata: we swap the character bytes on big
548          * endian boxes.
549          */
550 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
551         {
552                 int i;
553                 char *p2 = mono_array_addr (str->c_str, char, 0);
554                 for (i = 0; i < str->length; ++i) {
555                         *p++ = p2 [1];
556                         *p++ = p2 [0];
557                         p2 += 2;
558                 }
559         }
560 #else
561         memcpy (p, str->c_str->vector, str->length * 2);
562 #endif
563         ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
564         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
565                 g_free (ins);
566                 return res;
567         }
568         if (insert) {
569                 mono_g_hash_table_insert (ldstr_table, ins, str);
570                 return str;
571         }
572         g_free (ins);
573         return NULL;
574 }
575
576 MonoString*
577 mono_string_is_interned (MonoString *o)
578 {
579         return mono_string_is_interned_lookup (o, FALSE);
580 }
581
582 MonoString*
583 mono_string_intern (MonoString *str)
584 {
585         return mono_string_is_interned_lookup (str, TRUE);
586 }
587
588 /*
589  * mono_ldstr:
590  * @domain: the domain where the string will be used.
591  * @image: a metadata context
592  * @idx: index into the user string table.
593  * 
594  * Implementation for the ldstr opcode.
595  */
596 MonoString*
597 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
598 {
599         const char *str, *sig;
600         MonoString *o;
601         size_t len2;
602                 
603         sig = str = mono_metadata_user_string (image, idx);
604         
605         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig)))
606                 return o;
607         
608         len2 = mono_metadata_decode_blob_size (str, &str);
609         len2 >>= 1;
610
611         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
612 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
613         {
614                 int i;
615                 guint16 *p2 = (guint16*)mono_array_addr (o->c_str, guint16, 0);
616                 for (i = 0; i < len2; ++i) {
617                         *p2 = GUINT16_FROM_LE (*p2);
618                         ++p2;
619                 }
620         }
621 #endif
622         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
623
624         return o;
625 }
626
627 /*
628  * mono_string_to_utf8:
629  * @s: a System.String
630  *
631  * Return the UTF8 representation for @s.
632  * the resulting buffer nedds to be freed with g_free().
633  */
634 char *
635 mono_string_to_utf8 (MonoString *s)
636 {
637         char *as, *vector;
638         GError *error = NULL;
639
640         g_assert (s != NULL);
641
642         if (!s->length || !s->c_str)
643                 return g_strdup ("");
644
645         vector = (char*)s->c_str->vector;
646
647         g_assert (vector != NULL);
648
649         as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
650         if (error)
651                 g_warning (error->message);
652
653         return as;
654 }
655
656 /*
657  * mono_string_to_utf16:
658  * @s: a MonoString
659  *
660  * Return an null-terminated array of the utf-16 chars
661  * contained in @s. The result must be freed with g_free().
662  * This is a temporary helper until our string implementation
663  * is reworked to always include the null terminating char.
664  */
665 gunichar2 *
666 mono_string_to_utf16 (MonoString *s)
667 {
668         char *as;
669
670         g_assert (s != NULL);
671
672         as = g_malloc ((s->length * 2) + 2);
673         as [(s->length * 2)] = '\0';
674         as [(s->length * 2) + 1] = '\0';
675
676         if (!s->length || !s->c_str) {
677                 return (gunichar2 *)(as);
678         }
679         
680         memcpy (as, mono_string_chars(s), s->length * 2);
681         
682         return (gunichar2 *)(as);
683 }
684
685 static void
686 default_ex_handler (MonoException *ex)
687 {
688         MonoObject *o = (MonoObject*)ex;
689         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
690 }
691
692 static MonoExceptionFunc ex_handler = default_ex_handler;
693
694 void
695 mono_install_handler        (MonoExceptionFunc func)
696 {
697         ex_handler = func? func: default_ex_handler;
698 }
699
700 /*
701  * mono_raise_exception:
702  * @ex: exception object
703  *
704  * Signal the runtime that the exception @ex has been raised in unmanaged code.
705  */
706 void
707 mono_raise_exception (MonoException *ex) 
708 {
709         ex_handler (ex);
710 }
711
712 MonoWaitHandle *
713 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
714 {
715         MonoWaitHandle *res;
716
717         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
718
719         res->handle = handle;
720
721         return res;
722 }
723
724 MonoAsyncResult *
725 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
726 {
727         MonoAsyncResult *res;
728
729         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
730
731         res->data = data;
732         res->async_state = state;
733         res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
734         res->sync_completed = FALSE;
735         res->completed = FALSE;
736
737         return res;
738 }
739
740 void
741 mono_message_init (MonoDomain *domain,
742                    MonoMethodMessage *this, 
743                    MonoReflectionMethod *method,
744                    MonoArray *out_args)
745 {
746         MonoMethodSignature *sig = method->method->signature;
747         MonoString *name;
748         int i, j;
749         char **names;
750         guint8 arg_type;
751
752         this->method = method;
753
754         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
755         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
756
757         names = g_new (char *, sig->param_count);
758         mono_method_get_param_names (method->method, (const char **) names);
759         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
760         
761         for (i = 0; i < sig->param_count; i++) {
762                  name = mono_string_new (domain, names [i]);
763                  mono_array_set (this->names, gpointer, i, name);       
764         }
765
766         g_free (names);
767         
768         for (i = 0, j = 0; i < sig->param_count; i++) {
769
770                 if (sig->params [i]->byref) {
771                         if (out_args) {
772                                 gpointer arg = mono_array_get (out_args, gpointer, j);
773                                 mono_array_set (this->args, gpointer, i, arg);
774                                 j++;
775                         }
776                         arg_type = 2;
777                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN)
778                                 arg_type |= 1;
779                 } else {
780                         arg_type = 1;
781                 }
782
783                 mono_array_set (this->arg_types, guint8, i, arg_type);
784         }
785 }
786
787 /**
788  * mono_remoting_invoke:
789  * @real_proxy: pointer to a RealProxy object
790  * @msg: The MonoMethodMessage to execute
791  * @exc: used to store exceptions
792  * @out_args: used to store output arguments
793  *
794  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
795  * IMessage interface and it is not trivial to extract results from there. So
796  * we call an helper method PrivateInvoke instead of calling
797  * RealProxy::Invoke() directly.
798  *
799  * Returns: the result object.
800  */
801 MonoObject *
802 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
803                       MonoObject **exc, MonoArray **out_args)
804 {
805         static MonoMethod *im = NULL;
806         gpointer pa [4];
807
808         //static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;
809
810         /* fixme: make this domain dependent */
811         if (!im) {
812                 MonoClass *klass;
813                 int i;
814
815                 klass = mono_defaults.real_proxy_class; 
816                        
817                 for (i = 0; i < klass->method.count; ++i) {
818                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
819                             klass->methods [i]->signature->param_count == 4) {
820                                 im = klass->methods [i];
821                                 break;
822                         }
823                 }
824         
825                 g_assert (im);
826         }
827
828         pa [0] = real_proxy;
829         pa [1] = msg;
830         pa [2] = exc;
831         pa [3] = out_args;
832
833         return mono_runtime_invoke (im, NULL, pa);
834 }
835
836 MonoObject *
837 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
838                      MonoObject **exc, MonoArray **out_args) 
839 {
840         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
841
842                 return mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)target)->rp, 
843                                              msg, exc, out_args);
844
845         } else {
846                 MonoDomain *domain = mono_domain_get (); 
847                 MonoMethod *method = msg->method->method;
848                 MonoMethodSignature *sig = method->signature;
849                 MonoObject *res;
850                 int i, j, outarg_count = 0;
851
852                 for (i = 0; i < sig->param_count; i++) {
853                         if (sig->params [i]->byref) 
854                                 outarg_count++;
855                 }
856
857                 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
858                 *exc = NULL;
859
860                 for (i = 0, j = 0; i < sig->param_count; i++) {
861                         if (sig->params [i]->byref) {
862                                 gpointer arg;
863                                 arg = mono_array_get (msg->args, gpointer, i);
864                                 mono_array_set (*out_args, gpointer, j, arg);
865                                 j++;
866                         }
867                 }
868
869                 return mono_runtime_invoke_array (method, target, msg->args);
870         }
871 }
872
873
874