#include "loader.h"
#include "metadata/marshal.h"
#include "metadata/tabledefs.h"
+#include "metadata/exception.h"
+#include "metadata/appdomain.h"
+
+#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
+ a = i,
+
+enum {
+#include "mono/cil/opcode.def"
+ LAST = 0xff
+};
+#undef OPDEF
+
+struct _MonoMethodBuilder {
+ MonoMethod *method;
+ GList *locals_list;
+ int locals;
+ guint32 code_size, pos;
+ unsigned char *code;
+};
+
+gpointer
+mono_delegate_to_ftnptr (MonoDelegate *delegate)
+{
+ MonoMethod *method, *invoke, *wrapper;
+ MonoMethodSignature *sig;
+ MonoClass *klass;
+
+ if (!delegate)
+ return NULL;
+
+ if (delegate->delegate_trampoline)
+ return delegate->delegate_trampoline;
+
+ klass = ((MonoObject *)delegate)->vtable->klass;
+ g_assert (klass->delegate);
+
+ method = delegate->method_info->method;
+ sig = method->signature;
+
+ invoke = mono_get_delegate_invoke (klass);
+ wrapper = mono_marshal_get_managed_wrapper (invoke, (MonoObject *)delegate);
+
+ delegate->delegate_trampoline = mono_compile_method (wrapper);
+
+ return delegate->delegate_trampoline;
+}
+
+gpointer
+mono_array_to_savearray (MonoArray *array)
+{
+ if (!array)
+ return NULL;
+
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_array_to_lparray (MonoArray *array)
+{
+ if (!array)
+ return NULL;
+
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_string_to_ansibstr (MonoString *string_obj)
+{
+ g_error ("implement me");
+ return NULL;
+}
+
+gpointer
+mono_string_to_bstr (MonoString *string_obj)
+{
+ g_error ("implement me");
+ return NULL;
+}
+
+void
+mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
+{
+ char *s;
+ int len;
+
+ g_assert (dst != NULL);
+ g_assert (size > 0);
+
+ if (!src) {
+ memset (dst, 0, size);
+ return;
+ }
+
+ s = mono_string_to_utf8 (src);
+ len = MIN (size, strlen (s));
+ memcpy (dst, s, len);
+ g_free (s);
+
+ *((char *)dst + size - 1) = 0;
+}
+
+void
+mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
+{
+ int len;
+
+ g_assert (dst != NULL);
+ g_assert (size > 1);
+
+ if (!src) {
+ memset (dst, 0, size);
+ return;
+ }
+
+ len = MIN (size, (mono_string_length (src) * 2));
+ memcpy (dst, mono_string_chars (src), len);
+
+ *((char *)dst + size - 1) = 0;
+ *((char *)dst + size - 2) = 0;
+}
+
+
+static MonoMethod *
+mono_find_method_by_name (MonoClass *klass, const char *name, int param_count)
+{
+ MonoMethod *res = NULL;
+ int i;
+
+ for (i = 0; i < klass->method.count; ++i) {
+ if ((klass->methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
+ klass->methods [i]->name[0] == name [0] &&
+ !strcmp (name, klass->methods [i]->name) &&
+ klass->methods [i]->signature->param_count == param_count) {
+ res = klass->methods [i];
+ break;
+ }
+ }
+ return res;
+}
+
+void
+mono_mb_free (MonoMethodBuilder *mb)
+{
+ g_list_free (mb->locals_list);
+ g_free (mb);
+}
+
+MonoMethodBuilder *
+mono_mb_new (MonoClass *klass, const char *name)
+{
+ MonoMethodBuilder *mb;
+ MonoMethod *m;
+
+ g_assert (klass != NULL);
+ g_assert (name != NULL);
+
+ mb = g_new0 (MonoMethodBuilder, 1);
+
+ mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
+
+ m->klass = klass;
+ m->name = g_strdup (name);
+ m->inline_info = 1;
+ m->inline_count = -1;
+ m->is_wrapper = 1;
+
+ mb->code_size = 256;
+ mb->code = g_malloc (mb->code_size);
+
+ return mb;
+}
+
+int
+mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
+{
+ int res = mb->locals;
+
+ g_assert (mb != NULL);
+ g_assert (type != NULL);
+
+ mb->locals_list = g_list_append (mb->locals_list, type);
+ mb->locals++;
+
+ return res;
+}
+
+MonoMethod *
+mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
+{
+ MonoMethodHeader *header;
+ GList *l;
+ int i;
+
+ g_assert (mb != NULL);
+
+ ((MonoMethodNormal *)mb->method)->header = header = (MonoMethodHeader *)
+ g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
+
+ if (max_stack < 8)
+ max_stack = 8;
+
+ header->max_stack = max_stack;
+
+ for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
+ header->locals [i] = (MonoType *)l->data;
+ }
+
+ mb->method->signature = signature;
+ header->code = mb->code;
+ header->code_size = mb->pos;
+ header->num_locals = mb->locals;
+
+#if 0
+ printf ("MB METHOD %s.%s:%s\n", mb->method->klass->name_space, mb->method->klass->name,
+ mb->method->name);
+
+ for (i = 0; i < mb->pos; i++)
+ printf (" IL%05x %02x\n", i, mb->code [i]);
+
+#endif
+
+ return mb->method;
+}
+
+guint32
+mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
+{
+ MonoMethodWrapper *mw;
+
+ g_assert (mb != NULL);
+
+ mw = (MonoMethodWrapper *)mb->method;
+
+ mw->data = g_list_append (mw->data, data);
+
+ return g_list_length (mw->data);
+}
+
+void
+mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
+{
+ *((gint32 *)(&mb->code [pos])) = value;
+}
+
+void
+mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
+{
+ if (mb->pos >= mb->code_size) {
+ mb->code_size += 64;
+ mb->code = g_realloc (mb->code, mb->code_size);
+ }
+
+ mb->code [mb->pos++] = op;
+}
+
+void
+mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
+{
+ if ((mb->pos + 4) >= mb->code_size) {
+ mb->code_size += 64;
+ mb->code = g_realloc (mb->code, mb->code_size);
+ }
+
+ *((gint32 *)(&mb->code [mb->pos])) = data;
+ mb->pos += 4;
+}
+
+void
+mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
+{
+ if ((mb->pos + 2) >= mb->code_size) {
+ mb->code_size += 64;
+ mb->code = g_realloc (mb->code, mb->code_size);
+ }
+
+ *((gint16 *)(&mb->code [mb->pos])) = data;
+ mb->pos += 2;
+}
+
+void
+mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
+{
+ if (argnum < 4) {
+ mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
+ } else if (argnum < 256) {
+ mono_mb_emit_byte (mb, CEE_LDARG_S);
+ mono_mb_emit_byte (mb, argnum);
+ } else {
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_LDARG);
+ mono_mb_emit_i4 (mb, argnum);
+ }
+}
+
+void
+mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
+{
+ if (argnum < 256) {
+ mono_mb_emit_byte (mb, CEE_LDARGA_S);
+ mono_mb_emit_byte (mb, argnum);
+ } else {
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_LDARGA);
+ mono_mb_emit_i4 (mb, argnum);
+ }
+}
+
+void
+mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
+{
+ if (num < 4) {
+ mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
+ } else if (num < 256) {
+ mono_mb_emit_byte (mb, CEE_LDLOC_S);
+ mono_mb_emit_byte (mb, num);
+ } else {
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_LDLOC);
+ mono_mb_emit_i4 (mb, num);
+ }
+}
+
+void
+mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
+{
+ if (num < 4) {
+ mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
+ } else if (num < 256) {
+ mono_mb_emit_byte (mb, CEE_STLOC_S);
+ mono_mb_emit_byte (mb, num);
+ } else {
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_STLOC);
+ mono_mb_emit_i4 (mb, num);
+ }
+}
+
+void
+mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
+{
+ if (value >= -1 && value < 8) {
+ mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
+ } else if (value >= -128 && value <= 127) {
+ mono_mb_emit_byte (mb, CEE_LDC_I4_S);
+ mono_mb_emit_byte (mb, value);
+ } else {
+ mono_mb_emit_byte (mb, CEE_LDC_I4);
+ mono_mb_emit_i4 (mb, value);
+ }
+}
+
+void
+mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
+{
+ if (!opt_sig)
+ opt_sig = method->signature;
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_LDFTN);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
+ mono_mb_emit_byte (mb, CEE_CALLI);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, opt_sig));
+}
+
+void
+mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
+{
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
+ mono_mb_emit_byte (mb, CEE_CALLI);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
+}
+
+void
+mono_mb_emit_exception (MonoMethodBuilder *mb)
+{
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_byte (mb, CEE_THROW);
+
+}
+
+void
+mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint8 local, gint8 incr)
+{
+ mono_mb_emit_ldloc (mb, local);
+ mono_mb_emit_icon (mb, incr);
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_stloc (mb, local);
+}
+
+static void
+emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, int msize)
+{
+ /* fixme: dont know what do do here - docs say
+ this does not work for value types */
+
+ g_warning ("not implemented");
+ g_assert_not_reached ();
+}
+
+static void
+emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, int msize)
+{
+ switch (conv) {
+ case MONO_MARSHAL_CONV_BOOL_I4:
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_U1);
+ mono_mb_emit_byte (mb, CEE_STIND_I4);
+ break;
+ case MONO_MARSHAL_CONV_STR_LPWSTR:
+ case MONO_MARSHAL_CONV_STR_LPSTR:
+ case MONO_MARSHAL_CONV_STR_LPTSTR:
+ case MONO_MARSHAL_CONV_STR_BSTR:
+ case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+ case MONO_MARSHAL_CONV_STR_TBSTR:
+ case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
+ case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
+ /* free space if ARG_2 == true */
+ mono_mb_emit_byte (mb, CEE_LDARG_2);
+ mono_mb_emit_byte (mb, CEE_BRFALSE_S);
+ mono_mb_emit_byte (mb, 4);
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_FREE);
+
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+ mono_mb_emit_byte (mb, conv);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+ break;
+ case MONO_MARSHAL_CONV_STR_BYVALSTR:
+ case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
+ if (!usize)
+ break;
+
+ mono_mb_emit_byte (mb, CEE_LDLOC_1); /* dst */
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I); /* src String */
+ mono_mb_emit_icon (mb, usize);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_PROC3);
+ mono_mb_emit_byte (mb, conv);
+ break;
+ }
+ case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
+ if (!usize)
+ break;
+
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, CEE_BRFALSE_S);
+ mono_mb_emit_byte (mb, 15);
+
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_icon (mb, usize);
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_CPBLK);
+ break;
+ }
+ case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
+ default:
+ g_error ("marshalling conversion %d not implemented", conv);
+ }
+}
+
+static void
+emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
+{
+ MonoMarshalType *info;
+ int i;
+
+ info = mono_marshal_load_type_info (klass);
+
+ for (i = 0; i < info->num_fields; i++) {
+ MonoMarshalNative ntype;
+ MonoMarshalConv conv;
+ MonoType *ftype = info->fields [i].field->type;
+ int msize = 0;
+ int usize = 0;
+ gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
+
+ if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+
+ ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
+
+ if (last_field) {
+ msize = klass->instance_size - info->fields [i].field->offset;
+ usize = info->native_size - info->fields [i].offset;
+ } else {
+ msize = klass->fields [i + 1].offset - info->fields [i].field->offset;
+ usize = info->fields [i + 1].offset - info->fields [i].offset;
+ }
+ g_assert (msize > 0 && usize > 0);
+
+ switch (conv) {
+ case MONO_MARSHAL_CONV_NONE:
+
+ if (ftype->byref || ftype->type == MONO_TYPE_I ||
+ ftype->type == MONO_TYPE_U) {
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+ break;
+ }
+
+ switch (ftype->type) {
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I4);
+ mono_mb_emit_byte (mb, CEE_STIND_I4);
+ break;
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I1);
+ mono_mb_emit_byte (mb, CEE_STIND_I1);
+ break;
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I2);
+ mono_mb_emit_byte (mb, CEE_STIND_I2);
+ break;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I8);
+ mono_mb_emit_byte (mb, CEE_STIND_I8);
+ break;
+ case MONO_TYPE_R4:
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_R4);
+ mono_mb_emit_byte (mb, CEE_STIND_R4);
+ break;
+ case MONO_TYPE_R8:
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_LDIND_R8);
+ mono_mb_emit_byte (mb, CEE_STIND_R8);
+ break;
+ case MONO_TYPE_VALUETYPE:
+ emit_struct_conv (mb, ftype->data.klass, to_object);
+ break;
+ default:
+ g_error ("marshalling type %02x not implemented", ftype->type);
+ }
+ break;
+
+ default:
+ if (to_object)
+ emit_ptr_to_str_conv (mb, conv, usize, msize);
+ else
+ emit_str_to_ptr_conv (mb, conv, usize, msize);
+ }
+
+ if (!last_field) {
+ mono_mb_emit_add_to_local (mb, 0, msize);
+ mono_mb_emit_add_to_local (mb, 1, usize);
+ }
+ }
+}
+
+static MonoObject *
+delegate_test (MonoDelegate *delegate, gpointer *params)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+MonoMethod *
+mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
+{
+ MonoMethodSignature *sig;
+ static MonoMethodSignature *csig = NULL;
+ MonoMethodBuilder *mb;
+ MonoMethod *res;
+ MonoClass *ret_class;
+ MonoType *ret_type;
+ int i;
+
+ g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
+ !strcmp (method->name, "BeginInvoke"));
+
+ sig = method->signature;
+
+ if (sig->ret->byref)
+ ret_type = &mono_defaults.int_class->byval_arg;
+ else if (sig->ret->type == MONO_TYPE_VALUETYPE && sig->ret->data.klass->enumtype)
+ ret_type = sig->ret->data.klass->enum_basetype;
+ else
+ ret_type = sig->ret;
+
+ ret_class = mono_class_from_mono_type (ret_type);
+
+
+ if (!csig) {
+ int sigsize = sizeof (MonoMethodSignature) + 2 * sizeof (MonoType *);
+ csig = g_malloc0 (sigsize);
+
+ /* MonoObject *begin_invoke (MonoDelegate *delegate, gpointer params[]) */
+ csig->param_count = 2;
+ csig->ret = &mono_defaults.object_class->byval_arg;
+ csig->params [0] = &mono_defaults.object_class->byval_arg;
+ csig->params [1] = &mono_defaults.int_class->byval_arg;
+ }
+
+ mb = mono_mb_new (method->klass, method->name);
+
+ /* allocate local 0 (pointer) *params[] */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ /* allocate local 1 (pointer) tmo */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ /* alloate space on stack to store an array of pointers to the arguments */
+ mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_LOCALLOC);
+ mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+ /* tmp = params */
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+ for (i = 0; i < sig->param_count; i++) {
+
+ mono_mb_emit_byte (mb, CEE_LDLOC_1);
+ mono_mb_emit_ldarg_addr (mb, i);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+ /* tmp = tmp + sizeof (gpointer) */
+ if (i < (sig->param_count - 1))
+ mono_mb_emit_add_to_local (mb, 1, sizeof (gpointer));
+ }
+
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDLOC_0);
+ mono_mb_emit_native_call (mb, csig, delegate_test);
+
+ /* unbox the result if necessary */
+
+ switch (ret_type->type) {
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_VOID:
+ /* nothing to do */
+ break;
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_U:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_VALUETYPE:
+ mono_mb_emit_byte (mb, CEE_UNBOX);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
+ break;
+ default:
+ g_warning ("type 0x%x not handled", ret_type->type);
+ g_assert_not_reached ();
+ }
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, sig, 0);
+ mono_mb_free (mb);
+ return res;
+}
+
+/*
+ * the returned method invokes all methods in a multicast delegate
+ */
+MonoMethod *
+mono_marshal_get_delegate_invoke (MonoMethod *method)
+{
+ MonoMethodSignature *sig, *static_sig;
+ int i, sigsize;
+ MonoMethodBuilder *mb;
+ MonoMethod *res;
+ GHashTable *cache;
+ int pos [3];
+
+ g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
+ !strcmp (method->name, "Invoke"));
+
+ cache = method->klass->image->delegate_invoke_cache;
+ if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+ return res;
+
+ sig = method->signature;
+
+ sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
+ static_sig = g_memdup (sig, sigsize);
+ static_sig->hasthis = 0;
+
+ mb = mono_mb_new (method->klass, method->name);
+
+ /* allocate local 0 (object) prev */
+ mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+ /* allocate local 1 (object) target */
+ mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+ /* allocate local 2 (pointer) mptr */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ /* allocate local 3 to store the return value */
+ if (sig->ret->type != MONO_TYPE_VOID)
+ mono_mb_add_local (mb, sig->ret);
+
+ g_assert (sig->hasthis);
+
+ /* prev = addr of delegate */
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_stloc (mb, 0);
+
+ /* loop */
+ pos [0] = mb->pos;
+ /* target = delegate->target */
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, target));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_stloc (mb, 1);
+
+ /* mptr = delegate->method_ptr */
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_stloc (mb, 2);
+
+ /* target == null ? */
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_byte (mb, CEE_BRTRUE);
+ pos [1] = mb->pos;
+ mono_mb_emit_i4 (mb, 0);
+
+ /* emit static method call */
+
+ for (i = 0; i < sig->param_count; i++)
+ mono_mb_emit_ldarg (mb, i + 1);
+
+ mono_mb_emit_ldloc (mb, 2);
+ mono_mb_emit_byte (mb, CEE_CALLI);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
+
+ if (sig->ret->type != MONO_TYPE_VOID)
+ mono_mb_emit_stloc (mb, 3);
+
+ mono_mb_emit_byte (mb, CEE_BR);
+ pos [2] = mb->pos;
+ mono_mb_emit_i4 (mb, 0);
+
+ /* target != null, emit non static method call */
+
+ mono_mb_patch_addr (mb, pos [1], mb->pos - (pos [1] + 4));
+ mono_mb_emit_ldloc (mb, 1);
+
+ for (i = 0; i < sig->param_count; i++)
+ mono_mb_emit_ldarg (mb, i + 1);
+
+ mono_mb_emit_ldloc (mb, 2);
+ mono_mb_emit_byte (mb, CEE_CALLI);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
+
+ if (sig->ret->type != MONO_TYPE_VOID)
+ mono_mb_emit_stloc (mb, 3);
+
+ mono_mb_patch_addr (mb, pos [2], mb->pos - (pos [2] + 4));
+
+ /* prev = delegate->prev */
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_stloc (mb, 0);
+
+ /* if prev != null goto loop */
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_BRTRUE);
+ mono_mb_emit_i4 (mb, pos [0] - (mb->pos + 4));
+
+ if (sig->ret->type != MONO_TYPE_VOID)
+ mono_mb_emit_ldloc (mb, 3);
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, sig, 0);
+ mono_mb_free (mb);
+
+ g_hash_table_insert (cache, method, res);
+
+ return res;
+}
+
+/*
+ * generates IL code for the runtime invoke function
+ * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc)
+ *
+ * we also catch exceptions if exc != null
+ */
+MonoMethod *
+mono_marshal_get_runtime_invoke (MonoMethod *method)
+{
+ MonoMethodSignature *sig, *csig;
+ MonoExceptionClause *clause;
+ MonoMethodHeader *header;
+ MonoMethodBuilder *mb;
+ MonoMethod *res;
+ GHashTable *cache;
+ static MonoString *string_dummy = NULL;
+ int i, pos, sigsize;
+
+ g_assert (method);
+
+ cache = method->klass->image->runtime_invoke_cache;
+ if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+ return res;
+
+ /* to make it work with our special string constructors */
+ if (!string_dummy)
+ string_dummy = mono_string_new_wrapper ("dummy");
+
+ sig = method->signature;
+
+ sigsize = sizeof (MonoMethodSignature) + 3 * sizeof (MonoType *);
+ csig = g_malloc0 (sigsize);
+
+ csig->param_count = 3;
+ csig->ret = &mono_defaults.object_class->byval_arg;
+ csig->params [0] = &mono_defaults.object_class->byval_arg;
+ csig->params [1] = &mono_defaults.int_class->byval_arg;
+ csig->params [2] = &mono_defaults.int_class->byval_arg;
+
+ mb = mono_mb_new (method->klass, method->name);
+
+ /* allocate local 0 (object) tmp */
+ mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+ /* allocate local 1 (object) exc */
+ mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+
+ /* cond set *exc to null */
+ mono_mb_emit_byte (mb, CEE_LDARG_2);
+ mono_mb_emit_byte (mb, CEE_BRFALSE_S);
+ mono_mb_emit_byte (mb, 3);
+ mono_mb_emit_byte (mb, CEE_LDARG_2);
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+
+ if (sig->hasthis) {
+ if (method->string_ctor) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, string_dummy));
+ } else {
+ mono_mb_emit_ldarg (mb, 0);
+ }
+ }
+
+ for (i = 0; i < sig->param_count; i++) {
+ MonoType *t = sig->params [i];
+ int type;
+
+ mono_mb_emit_ldarg (mb, 1);
+ if (i) {
+ mono_mb_emit_icon (mb, sizeof (gpointer) * i);
+ mono_mb_emit_byte (mb, CEE_ADD);
+ }
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+
+ if (t->byref)
+ continue;
+
+ type = sig->params [i]->type;
+handle_enum:
+ switch (type) {
+ case MONO_TYPE_I1:
+ mono_mb_emit_byte (mb, CEE_LDIND_I1);
+ break;
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U1:
+ mono_mb_emit_byte (mb, CEE_LDIND_U1);
+ break;
+ case MONO_TYPE_I2:
+ mono_mb_emit_byte (mb, CEE_LDIND_I2);
+ break;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ mono_mb_emit_byte (mb, CEE_LDIND_U2);
+ break;
+#if SIZEOF_VOID_P == 4
+ case MONO_TYPE_I:
+#endif
+ case MONO_TYPE_I4:
+ mono_mb_emit_byte (mb, CEE_LDIND_I4);
+ break;
+#if SIZEOF_VOID_P == 4
+ case MONO_TYPE_U:
+#endif
+ case MONO_TYPE_U4:
+ mono_mb_emit_byte (mb, CEE_LDIND_U4);
+ break;
+ case MONO_TYPE_R4:
+ mono_mb_emit_byte (mb, CEE_LDIND_R4);
+ break;
+ case MONO_TYPE_R8:
+ mono_mb_emit_byte (mb, CEE_LDIND_R8);
+ break;
+#if SIZEOF_VOID_P == 8
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+#endif
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ mono_mb_emit_byte (mb, CEE_LDIND_I8);
+ break;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_OBJECT:
+ /* do nothing */
+ break;
+ case MONO_TYPE_VALUETYPE:
+ if (t->data.klass->enumtype) {
+ type = t->data.klass->enum_basetype->type;
+ goto handle_enum;
+ }
+ g_assert_not_reached ();
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ if (method->string_ctor) {
+ MonoMethodSignature *strsig;
+
+ sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
+ strsig = g_memdup (sig, sigsize);
+ strsig->ret = &mono_defaults.string_class->byval_arg;
+
+ mono_mb_emit_managed_call (mb, method, strsig);
+ } else
+ mono_mb_emit_managed_call (mb, method, NULL);
+
+ switch (sig->ret->type) {
+ case MONO_TYPE_VOID:
+ if (!method->string_ctor)
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ break;
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_VALUETYPE:
+ /* box value types */
+ mono_mb_emit_byte (mb, CEE_BOX);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->ret)));
+ break;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_OBJECT:
+ /* nothing to do */
+ break;
+ case MONO_TYPE_PTR:
+ default:
+ g_assert_not_reached ();
+ }
+
+ mono_mb_emit_stloc (mb, 0);
+
+ mono_mb_emit_byte (mb, CEE_LEAVE);
+ pos = mb->pos;
+ mono_mb_emit_i4 (mb, 0);
+
+ /* fixme: use a filter clause and only catch exceptions
+ * when exc != null. With RETHROW we get wrong stack
+ * traces. */
+ clause = g_new0 (MonoExceptionClause, 1);
+ clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
+ clause->try_offset = 0;
+ clause->try_len = mb->pos;
+ clause->handler_offset = mb->pos;
+
+ /* handler code */
+
+ /* store exception */
+ mono_mb_emit_stloc (mb, 1);
+
+ mono_mb_emit_byte (mb, CEE_LDARG_2);
+ mono_mb_emit_byte (mb, CEE_BRTRUE_S);
+ mono_mb_emit_byte (mb, 2);
+ mono_mb_emit_byte (mb, CEE_PREFIX1);
+ mono_mb_emit_byte (mb, CEE_RETHROW);
+
+ mono_mb_emit_byte (mb, CEE_LDARG_2);
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+
+ mono_mb_emit_byte (mb, CEE_LEAVE);
+ mono_mb_emit_i4 (mb, 0);
+
+ clause->handler_len = mb->pos - clause->handler_offset;
+
+ /* return result */
+ mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, csig, 0);
+ mono_mb_free (mb);
+
+ header = ((MonoMethodNormal *)res)->header;
+ header->num_clauses = 1;
+ header->clauses = clause;
+
+ g_hash_table_insert (cache, method, res);
+
+ return res;
+}
+
+/*
+ * generates IL code to call managed methods from unmanaged code
+ */
+MonoMethod *
+mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
+{
+ MonoMethodSignature *sig, *csig;
+ MonoMethodBuilder *mb;
+ MonoMethod *res;
+ GHashTable *cache;
+ int i, sigsize;
+
+ g_assert (method != NULL);
+
+ cache = method->klass->image->managed_wrapper_cache;
+ if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+ return res;
+
+ sig = method->signature;
+
+ mb = mono_mb_new (method->klass, method->name);
+
+ /* we copy the signature, so that we can modify it */
+ sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
+ csig = g_memdup (sig, sigsize);
+
+ /* fixme: howto handle this ? */
+ if (sig->hasthis) {
+
+ if (this) {
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, this));
+
+
+ } else {
+ /* fixme: */
+ g_assert_not_reached ();
+ }
+ }
+
+ for (i = 0; i < sig->param_count; i++) {
+ MonoType *t = sig->params [i];
+
+ switch (t->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ mono_mb_emit_ldarg (mb, i);
+ break;
+ case MONO_TYPE_STRING:
+ csig->params [i] = &mono_defaults.int_class->byval_arg;
+ mono_mb_emit_ldarg (mb, i);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+ mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+ break;
+
+ default:
+ g_warning ("type 0x%02x unknown", t->type);
+ g_assert_not_reached ();
+ }
+ }
+
+ mono_mb_emit_managed_call (mb, method, NULL);
+
+ /* fixme: add return type conversions */
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, csig, 0);
+ mono_mb_free (mb);
+
+ g_hash_table_insert (cache, method, res);
+
+ return res;
+}
+
+/*
+ * generates IL code for the pinvoke wrapper (the generated method
+ * call the unamnage code in method->addr)
+ */
+MonoMethod *
+mono_marshal_get_native_wrapper (MonoMethod *method)
+{
+ MonoMethodSignature *sig, *csig;
+ MonoMethodBuilder *mb;
+ MonoMethod *res;
+ GHashTable *cache;
+ MonoClass *klass;
+ gboolean pinvoke = FALSE;
+ int i, argnum, *tmp_locals, sigsize;
+
+ g_assert (method != NULL);
+
+ cache = method->klass->image->native_wrapper_cache;
+ if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+ return res;
+
+ sig = method->signature;
+
+ if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
+ (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
+ pinvoke = TRUE;
+
+ mb = mono_mb_new (method->klass, method->name);
+
+ mb->method->save_lmf = 1;
+
+ if (pinvoke && !method->addr)
+ mono_lookup_pinvoke_call (method);
+
+ if (!method->addr) {
+ mono_mb_emit_exception (mb);
+ res = mono_mb_create_method (mb, sig, 0);
+ mono_mb_free (mb);
+ g_hash_table_insert (cache, method, res);
+ return res;
+ }
+
+ /* we copy the signature, so that we can modify it */
+ sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
+ csig = g_memdup (sig, sigsize);
+
+ if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
+
+ if (method->string_ctor)
+ csig->ret = &mono_defaults.string_class->byval_arg;
+
+ if (sig->hasthis)
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+
+ for (i = 0; i < sig->param_count; i++)
+ mono_mb_emit_ldarg (mb, i + sig->hasthis);
+
+ g_assert (method->addr);
+ mono_mb_emit_native_call (mb, csig, method->addr);
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, csig, 0);
+ mono_mb_free (mb);
+ g_hash_table_insert (cache, method, res);
+ return res;
+ }
+
+ g_assert (pinvoke);
+
+ /* we allocate local for use with emit_struct_conv() */
+ /* allocate local 0 (pointer) src_ptr */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ /* allocate local 1 (pointer) dst_ptr */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ /* allocate local 2 (pointer) as tmp/scratch storage */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ /* allocate local 3 to store the return value */
+ mono_mb_add_local (mb, sig->ret);
+ }
+
+ /* we first do all conversions */
+ tmp_locals = alloca (sizeof (int) * sig->param_count);
+ for (i = 0; i < sig->param_count; i ++) {
+ MonoType *t = sig->params [i];
+
+ argnum = i + sig->hasthis;
+
+ /* allocate one tmp/scratch storage for each parameter */
+ tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ switch (t->type) {
+ case MONO_TYPE_VALUETYPE:
+ klass = sig->params [i]->data.klass;
+ if (klass->enumtype)
+ break;
+
+ /* store the address of the source into local variable 0 */
+ mono_mb_emit_byte (mb, CEE_LDARGA);
+ mono_mb_emit_i2 (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+ /* allocate space for the native struct and
+ * store the address into local variable 1 (dest) */
+ mono_mb_emit_icon (mb, mono_class_native_size (klass));
+ mono_mb_emit_byte (mb, CEE_LOCALLOC);
+ mono_mb_emit_stloc (mb, tmp_locals [i]);
+ mono_mb_emit_ldloc (mb, tmp_locals [i]);
+ mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+ /* emit valuetype convnversion code code */
+ emit_struct_conv (mb, sig->params [i]->data.klass, FALSE);
+
+ break;
+ case MONO_TYPE_STRING:
+ /* fixme: load the address instead */
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+ mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+ mono_mb_emit_stloc (mb, tmp_locals [i]);
+ break;
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ if (t->data.klass->delegate) {
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+ mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_DEL_FTN);
+ mono_mb_emit_stloc (mb, tmp_locals [i]);
+ } else {
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+ /* fixme: convert to what ? */
+ mono_mb_emit_stloc (mb, tmp_locals [i]);
+ }
+ break;
+ }
+ }
+
+ /* push all arguments */
+
+ if (sig->hasthis)
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+
+ for (i = 0; i < sig->param_count; i++) {
+ MonoType *t = sig->params [i];
+
+ argnum = i + sig->hasthis;
+
+ if (t->byref) {
+ mono_mb_emit_ldarg (mb, argnum);
+ continue;
+ }
+
+ switch (t->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ mono_mb_emit_ldarg (mb, argnum);
+ break;
+ case MONO_TYPE_VALUETYPE:
+ klass = sig->params [i]->data.klass;
+ if (klass->enumtype) {
+ mono_mb_emit_ldarg (mb, argnum);
+ break;
+ }
+ mono_mb_emit_ldloc (mb, tmp_locals [i]);
+ //mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ //mono_mb_emit_byte (mb, CEE_MONO_LDOBJ);
+ //mono_mb_emit_i4 (mb, mono_klass_native_size (klass));
+
+ break;
+ case MONO_TYPE_STRING:
+ /* fixme: load the address instead */
+ mono_mb_emit_ldloc (mb, tmp_locals [i]);
+ break;
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ mono_mb_emit_ldloc (mb, tmp_locals [i]);
+ break;
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_TYPEDBYREF:
+ case MONO_TYPE_FNPTR:
+ default:
+ g_warning ("type 0x%02x unknown", t->type);
+ g_assert_not_reached ();
+ }
+ }
+
+ /* call the native method */
+ mono_mb_emit_native_call (mb, csig, method->addr);
+
+ switch (sig->ret->type) {
+ case MONO_TYPE_VOID:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ /* no conversions necessary */
+ break;
+ case MONO_TYPE_STRING:
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+ mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+ break;
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_TYPEDBYREF:
+ case MONO_TYPE_FNPTR:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ default:
+ g_warning ("return type 0x%02x unknown", sig->ret->type);
+ g_assert_not_reached ();
+ }
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, sig, 0);
+ mono_mb_free (mb);
+
+ g_hash_table_insert (cache, method, res);
+
+ return res;
+}
+
+/*
+ * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
+ */
+MonoMethod *
+mono_marshal_get_struct_to_ptr (MonoClass *klass)
+{
+ MonoMethodBuilder *mb;
+ static MonoMethod *stoptr = NULL;
+ MonoMethod *res;
+
+ g_assert (klass != NULL);
+
+ if (klass->str_to_ptr)
+ return klass->str_to_ptr;
+
+ if (!stoptr)
+ stoptr = mono_find_method_by_name (mono_defaults.marshal_class, "StructureToPtr", 3);
+ g_assert (stoptr);
+
+ mb = mono_mb_new (stoptr->klass, stoptr->name);
+
+ /* allocate local 0 (pointer) src_ptr */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ /* allocate local 1 (pointer) dst_ptr */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ /* allocate local 2 (pointer) as tmp/scratch storage */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ /* initialize src_ptr to point to the start of object data */
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+ mono_mb_emit_icon (mb, sizeof (MonoObject));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+ /* initialize dst_ptr */
+ mono_mb_emit_byte (mb, CEE_LDARG_1);
+ mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+ emit_struct_conv (mb, klass, FALSE);
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, stoptr->signature, 0);
+ mono_mb_free (mb);
+
+ klass->str_to_ptr = res;
+ return res;
+}
+
+/*
+ * generates IL code for PtrToStructure (IntPtr src, object structure)
+ */
+MonoMethod *
+mono_marshal_get_ptr_to_struct (MonoClass *klass)
+{
+ MonoMethodBuilder *mb;
+ static MonoMethod *ptostr = NULL;
+ MonoMethod *res;
+
+ g_assert (klass != NULL);
+
+ if (klass->ptr_to_str)
+ return klass->ptr_to_str;
+
+ if (!ptostr)
+ ptostr = mono_find_method_by_name (mono_defaults.marshal_class, "PtrToStructure", 2);
+ g_assert (ptostr);
+
+ mb = mono_mb_new (ptostr->klass, ptostr->name);
+
+ /* allocate local 0 (pointer) src_ptr */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ /* allocate local 1 (pointer) dst_ptr */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ /* allocate local 2 (pointer) as tmp/scratch storage */
+ mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ /* initialize src_ptr to point to the start of object data */
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+ mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+ /* initialize dst_ptr */
+ mono_mb_emit_byte (mb, CEE_LDARG_1);
+ mono_mb_emit_icon (mb, sizeof (MonoObject));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+ emit_struct_conv (mb, klass, TRUE);
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ res = mono_mb_create_method (mb, ptostr->signature, 0);
+ mono_mb_free (mb);
+
+ klass->ptr_to_str = res;
+ return res;
+}
/* FIXME: on win32 we should probably use GlobalAlloc(). */
void*
return result;
}
+void
+ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
+ gpointer dest, gint32 length)
+{
+ int element_size;
+ void *source_addr;
+
+ MONO_CHECK_ARG_NULL (src);
+ MONO_CHECK_ARG_NULL (dest);
+
+ g_assert (src->obj.vtable->klass->rank == 1);
+ g_assert (start_index >= 0 && start_index < mono_array_length (src));
+ g_assert (start_index + length <= mono_array_length (src));
+
+ element_size = mono_array_element_size (src->obj.vtable->klass);
+
+ source_addr = mono_array_addr_with_size (src, element_size, start_index);
+
+ memcpy (dest, source_addr, length * element_size);
+}
+
+void
+ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
+ MonoArray *dest, gint32 length)
+{
+ int element_size;
+ void *dest_addr;
+
+ MONO_CHECK_ARG_NULL (src);
+ MONO_CHECK_ARG_NULL (dest);
+
+ g_assert (dest->obj.vtable->klass->rank == 1);
+ g_assert (start_index >= 0 && start_index < mono_array_length (dest));
+ g_assert (start_index + length <= mono_array_length (dest));
+
+ element_size = mono_array_element_size (dest->obj.vtable->klass);
+
+ dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
+
+ memcpy (dest_addr, src, length * element_size);
+}
+
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
+{
+ char *p = ptr;
+ return *(gpointer*)(p + offset);
+}
+
+unsigned char
+ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
+{
+ char *p = ptr;
+ return *(unsigned char*)(p + offset);
+}
+
+gint16
+ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
+{
+ char *p = ptr;
+ return *(gint16*)(p + offset);
+}
+
gint32
-mono_marshal_type_size (MonoMarshalNative type, int count, gint32 *align)
-{
- switch (type) {
- case MONO_NATIVE_BOOLEAN:
- *align = 4;
- return 4;
- case MONO_NATIVE_I1:
- case MONO_NATIVE_U1:
- *align = 1;
- return 1;
- case MONO_NATIVE_I2:
- case MONO_NATIVE_U2:
- *align = 2;
- return 2;
- case MONO_NATIVE_I4:
- case MONO_NATIVE_U4:
- *align = 4;
- return 4;
- case MONO_NATIVE_I8:
- case MONO_NATIVE_U8:
- *align = 8;
- return 8;
- case MONO_NATIVE_R4:
- *align = 4;
- return 4;
- case MONO_NATIVE_R8:
- *align = 8;
- return 8;
- case MONO_NATIVE_CURRENCY:
- case MONO_NATIVE_BSTR:
- case MONO_NATIVE_LPSTR:
- case MONO_NATIVE_LPWSTR:
- case MONO_NATIVE_LPTSTR:
- case MONO_NATIVE_BYVALTSTR:
- case MONO_NATIVE_IUNKNOWN:
- case MONO_NATIVE_IDISPATCH:
- case MONO_NATIVE_STRUCT:
- case MONO_NATIVE_INTERFACE:
- case MONO_NATIVE_SAFEARRAY:
- case MONO_NATIVE_BYVALARRAY:
- case MONO_NATIVE_INT:
- case MONO_NATIVE_UINT:
- case MONO_NATIVE_VBBYREFSTR:
- case MONO_NATIVE_ANSIBSTR:
- case MONO_NATIVE_TBSTR:
- case MONO_NATIVE_VARIANTBOOL:
- case MONO_NATIVE_FUNC:
- case MONO_NATIVE_ASANY:
- case MONO_NATIVE_ARRAY:
- case MONO_NATIVE_LPSTRUCT:
- case MONO_NATIVE_CUSTOM:
- case MONO_NATIVE_ERROR:
- default:
- break;
- }
- g_assert_not_reached ();
- return 0;
+ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
+{
+ char *p = ptr;
+ return *(gint32*)(p + offset);
}
-guint32
-mono_type_to_unmanaged (MonoType *type) {
- int t = type->type;
- if (type->byref)
- return MONO_NATIVE_UINT;
+gint64
+ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
+{
+ char *p = ptr;
+ return *(gint64*)(p + offset);
+}
-handle_enum:
- switch (t) {
- case MONO_TYPE_BOOLEAN: return MONO_NATIVE_BOOLEAN;
- case MONO_TYPE_CHAR: return MONO_NATIVE_U2;
- case MONO_TYPE_I1: return MONO_NATIVE_I1;
- case MONO_TYPE_U1: return MONO_NATIVE_U1;
- case MONO_TYPE_I2: return MONO_NATIVE_I2;
- case MONO_TYPE_U2: return MONO_NATIVE_U2;
- case MONO_TYPE_I4: return MONO_NATIVE_I4;
- case MONO_TYPE_U4: return MONO_NATIVE_U4;
- case MONO_TYPE_I8: return MONO_NATIVE_I8;
- case MONO_TYPE_U8: return MONO_NATIVE_U8;
- case MONO_TYPE_R4: return MONO_NATIVE_R4;
- case MONO_TYPE_R8: return MONO_NATIVE_R8;
- /* the default may change according to the platform... */
- case MONO_TYPE_STRING: return MONO_NATIVE_LPSTR;
- case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
- case MONO_TYPE_VALUETYPE: /*FIXME*/
- if (type->data.klass->enumtype) {
- t = type->data.klass->enum_basetype->type;
- goto handle_enum;
- }
- return MONO_NATIVE_STRUCT;
- case MONO_TYPE_ARRAY: return MONO_NATIVE_ARRAY;
- case MONO_TYPE_I: return MONO_NATIVE_INT;
- case MONO_TYPE_U: return MONO_NATIVE_UINT;
- case MONO_TYPE_FNPTR: return MONO_NATIVE_FUNC;
- case MONO_TYPE_OBJECT: return MONO_NATIVE_ASANY; /* ?? */
- case MONO_TYPE_SZARRAY: return MONO_NATIVE_ARRAY;
- case MONO_TYPE_CLASS:
- /* FIXME : we need to handle ArrayList and StringBuilder here, probably */
- case MONO_TYPE_TYPEDBYREF:
- default:
- g_error ("type 0x%02x not handled in marshal", t);
- }
- return MONO_NATIVE_MAX;
+void
+ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
+{
+ char *p = ptr;
+ *(unsigned char*)(p + offset) = val;
}
void
-mono_marshal_load_type_info (MonoClass* klass)
+ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
{
- int i, j, count;
- MonoMarshalType *info;
+ char *p = ptr;
+ *(gpointer*)(p + offset) = val;
+}
- if (klass->marshal_info)
- return;
+void
+ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
+{
+ char *p = ptr;
+ *(gint16*)(p + offset) = val;
+}
- for (i = 0; i < klass->field.count; ++i) {
- if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
- continue;
- /* handle fields in embedded valuetypes. */
- count++;
- }
+void
+ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
+{
+ char *p = ptr;
+ *(gint32*)(p + offset) = val;
+}
- klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
- info->num_fields = count;
-
- for (j = i = 0; i < klass->field.count; ++i) {
- if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
- continue;
- /* handle fields in embedded valuetypes. */
- j++;
- }
+void
+ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
+{
+ char *p = ptr;
+ *(gint64*)(p + offset) = val;
+}
+
+MonoString*
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAuto (gpointer ptr)
+{
+ MonoDomain *domain = mono_domain_get ();
+
+ return mono_string_new (domain, (char *)ptr);
+}
+
+guint32
+ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
+{
+ return (GetLastError ());
+}
+
+guint32
+ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
+{
+ MonoClass *klass;
+
+ MONO_CHECK_ARG_NULL (rtype);
+ klass = mono_class_from_mono_type (rtype->type);
+
+ return mono_class_native_size (klass);
+}
+
+void
+ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
+{
+ MonoMethod *method;
+ gpointer pa [3];
+
+ MONO_CHECK_ARG_NULL (obj);
+ MONO_CHECK_ARG_NULL (dst);
+
+ method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
+
+ pa [0] = obj;
+ pa [1] = &dst;
+ pa [2] = &delete_old;
+
+ mono_runtime_invoke (method, NULL, pa, NULL);
}
+void
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
+{
+ MonoMethod *method;
+ gpointer pa [2];
+
+ MONO_CHECK_ARG_NULL (src);
+ MONO_CHECK_ARG_NULL (dst);
+
+ method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
+
+ pa [0] = &src;
+ pa [1] = dst;
+
+ mono_runtime_invoke (method, NULL, pa, NULL);
+}