2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
14 #include <mono/metadata/mono-endian.h>
15 #include <mono/metadata/tabledefs.h>
16 #include <mono/metadata/tokentype.h>
17 #include <mono/metadata/loader.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/appdomain.h>
27 mono_runtime_object_init (MonoObject *this)
30 MonoMethod *method = NULL;
31 MonoClass *klass = this->vtable->klass;
33 for (i = 0; i < klass->method.count; ++i) {
34 if (!strcmp (".ctor", klass->methods [i]->name) &&
35 klass->methods [i]->signature->param_count == 0) {
36 method = klass->methods [i];
43 mono_runtime_invoke (method, this, NULL);
48 * @klass: klass that needs to be initialized
50 * This routine calls the class constructor for @class.
53 mono_runtime_class_init (MonoClass *klass)
57 for (i = 0; i < klass->method.count; ++i) {
58 MonoMethod *method = klass->methods [i];
59 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
60 (strcmp (".cctor", method->name) == 0)) {
61 mono_runtime_invoke (method, NULL, NULL);
65 /* No class constructor found */
69 default_trampoline (MonoMethod *method)
75 default_remoting_trampoline (MonoMethod *method)
77 g_error ("remoting not installed");
81 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
82 static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
85 mono_install_trampoline (MonoTrampoline func)
87 arch_create_jit_trampoline = func? func: default_trampoline;
91 mono_install_remoting_trampoline (MonoTrampoline func)
93 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
96 #if 0 && HAVE_BOEHM_GC
98 vtable_finalizer (void *obj, void *data) {
99 g_print ("%s finalized (%p)\n", (char*)data, obj);
105 * @domain: the application domain
106 * @class: the class to initialize
108 * VTables are domain specific because we create domain specific code, and
109 * they contain the domain specific static class data.
112 mono_class_vtable (MonoDomain *domain, MonoClass *class)
116 MonoClassField *field;
118 guint32 cols [MONO_CONSTANT_SIZE];
125 /* can interfaces have static fields? */
126 if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
127 g_assert_not_reached ();
129 mono_domain_lock (domain);
130 if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
131 mono_domain_unlock (domain);
136 mono_class_init (class);
138 // mono_stats.used_class_count++;
139 // mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
141 vt = mono_mempool_alloc0 (domain->mp, sizeof (MonoVTable) +
142 class->vtable_size * sizeof (gpointer));
146 if (class->class_size) {
148 vt->data = GC_malloc (class->class_size + 8);
149 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
150 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
151 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
153 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
156 // mono_stats.class_static_data_size += class->class_size + 8;
159 for (i = class->field.first; i < class->field.last; ++i) {
160 field = &class->fields [i - class->field.first];
161 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
163 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
165 cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1));
167 g_warning ("constant for field %s not found", field->name);
170 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, cols, MONO_CONSTANT_SIZE);
171 p = mono_metadata_blob_heap (class->image, cols [MONO_CONSTANT_VALUE]);
172 len = mono_metadata_decode_blob_size (p, &p);
173 t = (char*)vt->data + field->offset;
174 /* should we check that the type matches? */
175 switch (cols [MONO_CONSTANT_TYPE]) {
176 case MONO_TYPE_BOOLEAN:
184 guint16 *val = (guint16*)t;
190 guint32 *val = (guint32*)t;
196 guint64 *val = (guint64*)t;
201 float *val = (float*)t;
206 double *val = (double*)t;
210 case MONO_TYPE_STRING: {
211 gpointer *val = (gpointer*)t;
212 //*val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
215 case MONO_TYPE_CLASS:
216 /* nothing to do, we malloc0 the data and the value can be 0 only */
219 g_warning ("type 0x%02x should not be in constant table", cols [MONO_CONSTANT_TYPE]);
223 vt->max_interface_id = class->max_interface_id;
225 vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
226 sizeof (gpointer) * (class->max_interface_id + 1));
228 /* initialize interface offsets */
229 for (k = class; k ; k = k->parent) {
230 for (i = 0; i < k->interface_count; i++) {
232 MonoClass *ic = k->interfaces [i];
233 slot = class->interface_offsets [ic->interface_id];
234 vt->interface_offsets [ic->interface_id] = &vt->vtable [slot];
238 /* initialize vtable */
239 for (i = 0; i < class->vtable_size; ++i) {
242 if ((cm = class->vtable [i]))
243 vt->vtable [i] = arch_create_jit_trampoline (cm);
246 mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
247 mono_domain_unlock (domain);
249 mono_runtime_class_init (class);
255 * mono_class_proxy_vtable:
256 * @domain: the application domain
257 * @class: the class to proxy
259 * Creates a vtable for transparent proxies. It is basically
260 * a copy of the real vtable of @class, but all function pointers invoke
261 * the remoting functions, and vtable->klass points to the
262 * transparent proxy class, and not to @class.
265 mono_class_proxy_vtable (MonoDomain *domain, MonoClass *class)
267 MonoVTable *vt, *pvt;
270 if ((pvt = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class)))
273 vt = mono_class_vtable (domain, class);
274 vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
276 // mono_stats.class_vtable_size += vtsize;
278 pvt = mono_mempool_alloc (domain->mp, vtsize);
279 memcpy (pvt, vt, vtsize);
281 pvt->klass = mono_defaults.transparent_proxy_class;
283 /* initialize vtable */
284 for (i = 0; i < class->vtable_size; ++i) {
287 if ((cm = class->vtable [i]))
288 pvt->vtable [i] = arch_create_remoting_trampoline (cm);
291 mono_g_hash_table_insert (domain->proxy_vtable_hash, class, pvt);
296 static MonoInvokeFunc default_mono_runtime_invoke = NULL;
299 mono_runtime_invoke (MonoMethod *method, void *obj, void **params)
301 if (!default_mono_runtime_invoke) {
302 g_error ("runtime invoke called on uninitialized runtime");
305 return default_mono_runtime_invoke (method, obj, params);
309 mono_runtime_exec_main (MonoMethod *method, MonoArray *args)
315 if (method->signature->ret->type == MONO_TYPE_I4) {
317 res = mono_runtime_invoke (method, NULL, pa);
318 return *(guint32 *)((char *)res + sizeof (MonoObject));
320 mono_runtime_invoke (method, NULL, pa);
326 mono_install_runtime_invoke (MonoInvokeFunc func)
328 default_mono_runtime_invoke = func;
332 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params)
334 MonoMethodSignature *sig = method->signature;
338 pa = alloca (sizeof (gpointer) * mono_array_length (params));
340 for (i = 0; i < mono_array_length (params); i++) {
341 if (sig->params [i]->byref) {
345 switch (sig->params [i]->type) {
348 case MONO_TYPE_BOOLEAN:
358 case MONO_TYPE_VALUETYPE:
359 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
361 case MONO_TYPE_STRING:
362 case MONO_TYPE_OBJECT:
363 case MONO_TYPE_CLASS:
364 pa [i] = (char *)(((gpointer *)params->vector)[i]);
367 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
371 if (!strcmp (method->name, ".ctor")) {
372 obj = mono_object_new (mono_domain_get (), method->klass);
373 mono_runtime_invoke (method, obj, pa);
376 return mono_runtime_invoke (method, obj, pa);
380 * mono_object_allocate:
381 * @size: number of bytes to allocate
383 * This is a very simplistic routine until we have our GC-aware
386 * Returns: an allocated object of size @size, or NULL on failure.
389 mono_object_allocate (size_t size)
392 void *o = GC_debug_malloc (size, "object", 1);
394 void *o = calloc (1, size);
403 * Frees the memory used by the object. Debugging purposes
404 * only, as we will have our GC system.
407 mono_object_free (MonoObject *o)
410 g_error ("mono_object_free called with boehm gc.");
412 MonoClass *c = o->vtable->klass;
414 memset (o, 0, c->instance_size);
421 * @klass: the class of the object that we want to create
423 * Returns: A newly created object whose definition is
424 * looked up using @klass
427 mono_object_new (MonoDomain *domain, MonoClass *klass)
429 static guint32 uoid = 0;
432 mono_stats.new_object_count++;
435 mono_class_init (klass);
437 if (klass->ghcimpl) {
438 o = mono_object_allocate (klass->instance_size);
441 t = mono_object_allocate (klass->instance_size + 4);
443 o = (MonoObject *)(++t);
445 o->vtable = mono_class_vtable (domain, klass);
451 * mono_object_new_from_token:
452 * @image: Context where the type_token is hosted
453 * @token: a token of the type that we want to create
455 * Returns: A newly created object whose definition is
456 * looked up using @token in the @image image
459 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
463 class = mono_class_get (image, token);
465 return mono_object_new (domain, class);
471 * @obj: the object to clone
473 * Returns: A newly created object who is a shallow copy of @obj
476 mono_object_clone (MonoObject *obj)
481 size = obj->vtable->klass->instance_size;
482 o = mono_object_allocate (size);
484 memcpy (o, obj, size);
491 * @array: the array to clone
493 * Returns: A newly created array who is a shallow copy of @array
496 mono_array_clone (MonoArray *array)
501 MonoClass *klass = array->obj.vtable->klass;
503 if (array->bounds == NULL) {
504 size = mono_array_length (array);
505 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
508 size *= mono_array_element_size (klass);
509 memcpy (o, array, sizeof (MonoArray) + size);
514 sizes = alloca (klass->rank * sizeof(guint32) * 2);
515 size = mono_array_element_size (klass);
516 for (i = 0; i < klass->rank; ++i) {
517 sizes [i] = array->bounds [i].length;
518 size *= array->bounds [i].length;
519 sizes [i + klass->rank] = array->bounds [i].lower_bound;
521 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
522 klass, sizes, sizes + klass->rank);
523 memcpy (o, array, sizeof(MonoArray) + size);
529 * mono_array_new_full:
530 * @domain: domain where the object is created
531 * @array_class: array class
532 * @lengths: lengths for each dimension in the array
533 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
535 * This routine creates a new array objects with the given dimensions,
536 * lower bounds and type.
539 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
540 guint32 *lengths, guint32 *lower_bounds)
542 guint32 byte_len, len;
545 MonoArrayBounds *bounds;
548 if (!array_class->inited)
549 mono_class_init (array_class);
551 byte_len = mono_array_element_size (array_class);
554 if (array_class->this_arg.type == MONO_TYPE_SZARRAY) {
559 bounds = GC_debug_malloc (sizeof (MonoArrayBounds) * array_class->rank, "bounds", 0);
561 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
563 for (i = 0; i < array_class->rank; ++i) {
564 bounds [i].length = lengths [i];
569 for (i = 0; i < array_class->rank; ++i)
570 bounds [i].lower_bound = lower_bounds [i];
575 * Following three lines almost taken from mono_object_new ():
576 * they need to be kept in sync.
578 o = mono_object_allocate (sizeof (MonoArray) + byte_len);
581 o->vtable = mono_class_vtable (domain, array_class);
583 array = (MonoArray*)o;
585 array->bounds = bounds;
586 array->max_length = len;
593 * @domain: domain where the object is created
594 * @eclass: element class
595 * @n: number of array elements
597 * This routine creates a new szarray with @n elements of type @eclass.
600 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
604 ac = mono_array_class_get (&eclass->byval_arg, 1);
605 g_assert (ac != NULL);
607 return mono_array_new_full (domain, ac, &n, NULL);
611 * mono_string_new_utf16:
612 * @text: a pointer to an utf16 string
613 * @len: the length of the string
615 * Returns: A newly created string object which contains @text.
618 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
623 s = mono_string_new_size (domain, len);
624 g_assert (s != NULL);
626 memcpy (s->c_str->vector, text, len * 2);
632 * mono_string_new_size:
633 * @text: a pointer to an utf16 string
634 * @len: the length of the string
636 * Returns: A newly created string object of @len
639 mono_string_new_size (MonoDomain *domain, gint32 len)
644 s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
645 g_assert (s != NULL);
647 ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
648 g_assert (ca != NULL);
657 * mono_string_new_len:
658 * @text: a pointer to an utf8 string
659 * @length: number of bytes in @text to consider
661 * Returns: A newly created string object which contains @text.
664 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
666 GError *error = NULL;
667 MonoString *o = NULL;
672 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
675 o = mono_string_new_utf16 (domain, ut, items_written);
677 g_error_free (error);
686 * @text: a pointer to an utf8 string
688 * Returns: A newly created string object which contains @text.
691 mono_string_new (MonoDomain *domain, const char *text)
693 GError *error = NULL;
694 MonoString *o = NULL;
701 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
704 o = mono_string_new_utf16 (domain, ut, items_written);
706 g_error_free (error);
714 * mono_string_new_wrapper:
715 * @text: pointer to utf8 characters.
717 * Helper function to create a string object from @text in the current domain.
720 mono_string_new_wrapper (const char *text)
722 MonoDomain *domain = mono_domain_get ();
724 return mono_string_new (domain, text);
729 * @class: the class of the value
730 * @value: a pointer to the unboxed data
732 * Returns: A newly created object which contains @value.
735 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
740 g_assert (class->valuetype);
742 size = mono_class_instance_size (class);
743 res = mono_object_allocate (size);
744 res->vtable = mono_class_vtable (domain, class);
746 size = size - sizeof (MonoObject);
748 memcpy ((char *)res + sizeof (MonoObject), value, size);
754 * mono_object_isinst:
756 * @klass: a pointer to a class
758 * Returns: @obj if @obj is derived from @klass
761 mono_object_isinst (MonoObject *obj, MonoClass *klass)
773 mono_class_init (klass);
775 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
776 if ((klass->interface_id <= oklass->max_interface_id) &&
777 vt->interface_offsets [klass->interface_id])
780 if (oklass == mono_defaults.transparent_proxy_class) {
781 /* fixme: add check for IRemotingTypeInfo */
782 oklass = ((MonoTransparentProxy *)obj)->klass;
785 if (oklass->rank == klass->rank &&
786 (oklass->element_class->baseval - klass->element_class->baseval) <=
787 klass->element_class->diffval)
790 } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
798 mono_string_is_interned_lookup (MonoString *str, int insert)
800 MonoGHashTable *ldstr_table;
803 char *ins = g_malloc (4 + str->length * 2);
807 /* Encode the length */
809 mono_metadata_encode_value (2 * str->length, p, &p);
812 mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
813 bloblen = (p - ins) + 2 * str->length;
815 * ins is stored in the hash table as a key and needs to have the same
816 * representation as in the metadata: we swap the character bytes on big
819 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
822 char *p2 = mono_array_addr (str->c_str, char, 0);
823 for (i = 0; i < str->length; ++i) {
830 memcpy (p, str->c_str->vector, str->length * 2);
832 domain = ((MonoObject *)str)->vtable->domain;
833 ldstr_table = domain->ldstr_table;
834 mono_domain_lock (domain);
835 if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
836 mono_domain_unlock (domain);
841 mono_g_hash_table_insert (ldstr_table, ins, str);
842 mono_domain_unlock (domain);
845 mono_domain_unlock (domain);
851 mono_string_is_interned (MonoString *o)
853 return mono_string_is_interned_lookup (o, FALSE);
857 mono_string_intern (MonoString *str)
859 return mono_string_is_interned_lookup (str, TRUE);
864 * @domain: the domain where the string will be used.
865 * @image: a metadata context
866 * @idx: index into the user string table.
868 * Implementation for the ldstr opcode.
871 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
873 const char *str, *sig;
877 sig = str = mono_metadata_user_string (image, idx);
879 mono_domain_lock (domain);
880 if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
881 mono_domain_unlock (domain);
885 len2 = mono_metadata_decode_blob_size (str, &str);
888 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
889 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
892 guint16 *p2 = (guint16*)mono_array_addr (o->c_str, guint16, 0);
893 for (i = 0; i < len2; ++i) {
894 *p2 = GUINT16_FROM_LE (*p2);
899 mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
900 mono_domain_unlock (domain);
906 * mono_string_to_utf8:
907 * @s: a System.String
909 * Return the UTF8 representation for @s.
910 * the resulting buffer nedds to be freed with g_free().
913 mono_string_to_utf8 (MonoString *s)
916 GError *error = NULL;
918 g_assert (s != NULL);
920 if (!s->length || !s->c_str)
921 return g_strdup ("");
923 vector = (char*)s->c_str->vector;
925 g_assert (vector != NULL);
927 as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
929 g_warning (error->message);
935 * mono_string_to_utf16:
938 * Return an null-terminated array of the utf-16 chars
939 * contained in @s. The result must be freed with g_free().
940 * This is a temporary helper until our string implementation
941 * is reworked to always include the null terminating char.
944 mono_string_to_utf16 (MonoString *s)
948 g_assert (s != NULL);
950 as = g_malloc ((s->length * 2) + 2);
951 as [(s->length * 2)] = '\0';
952 as [(s->length * 2) + 1] = '\0';
954 if (!s->length || !s->c_str) {
955 return (gunichar2 *)(as);
958 memcpy (as, mono_string_chars(s), s->length * 2);
960 return (gunichar2 *)(as);
964 default_ex_handler (MonoException *ex)
966 MonoObject *o = (MonoObject*)ex;
967 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
970 static MonoExceptionFunc ex_handler = default_ex_handler;
973 mono_install_handler (MonoExceptionFunc func)
975 ex_handler = func? func: default_ex_handler;
979 * mono_raise_exception:
980 * @ex: exception object
982 * Signal the runtime that the exception @ex has been raised in unmanaged code.
985 mono_raise_exception (MonoException *ex)
991 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
995 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
997 res->handle = handle;
1003 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
1005 MonoAsyncResult *res;
1007 res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
1010 res->async_state = state;
1011 res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
1012 res->sync_completed = FALSE;
1013 res->completed = FALSE;
1019 mono_message_init (MonoDomain *domain,
1020 MonoMethodMessage *this,
1021 MonoReflectionMethod *method,
1022 MonoArray *out_args)
1024 MonoMethodSignature *sig = method->method->signature;
1030 this->method = method;
1032 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
1033 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
1035 names = g_new (char *, sig->param_count);
1036 mono_method_get_param_names (method->method, (const char **) names);
1037 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
1039 for (i = 0; i < sig->param_count; i++) {
1040 name = mono_string_new (domain, names [i]);
1041 mono_array_set (this->names, gpointer, i, name);
1046 for (i = 0, j = 0; i < sig->param_count; i++) {
1048 if (sig->params [i]->byref) {
1050 gpointer arg = mono_array_get (out_args, gpointer, j);
1051 mono_array_set (this->args, gpointer, i, arg);
1055 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN)
1061 mono_array_set (this->arg_types, guint8, i, arg_type);
1066 * mono_remoting_invoke:
1067 * @real_proxy: pointer to a RealProxy object
1068 * @msg: The MonoMethodMessage to execute
1069 * @exc: used to store exceptions
1070 * @out_args: used to store output arguments
1072 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
1073 * IMessage interface and it is not trivial to extract results from there. So
1074 * we call an helper method PrivateInvoke instead of calling
1075 * RealProxy::Invoke() directly.
1077 * Returns: the result object.
1080 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
1081 MonoObject **exc, MonoArray **out_args)
1083 static MonoMethod *im = NULL;
1086 //static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;
1088 /* fixme: make this domain dependent */
1093 klass = mono_defaults.real_proxy_class;
1095 for (i = 0; i < klass->method.count; ++i) {
1096 if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
1097 klass->methods [i]->signature->param_count == 4) {
1098 im = klass->methods [i];
1106 pa [0] = real_proxy;
1111 return mono_runtime_invoke (im, NULL, pa);
1115 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
1116 MonoObject **exc, MonoArray **out_args)
1118 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
1120 return mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)target)->rp,
1121 msg, exc, out_args);
1124 MonoDomain *domain = mono_domain_get ();
1125 MonoMethod *method = msg->method->method;
1126 MonoMethodSignature *sig = method->signature;
1128 int i, j, outarg_count = 0;
1130 for (i = 0; i < sig->param_count; i++) {
1131 if (sig->params [i]->byref)
1135 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
1138 for (i = 0, j = 0; i < sig->param_count; i++) {
1139 if (sig->params [i]->byref) {
1141 arg = mono_array_get (msg->args, gpointer, i);
1142 mono_array_set (*out_args, gpointer, j, arg);
1147 return mono_runtime_invoke_array (method, target, msg->args);